]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.1 2.3.1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:05 +0000 (15:25 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:05 +0000 (15:25 -0500)
128 files changed:
CREDITS
Documentation/Configure.help
Documentation/devices.tex
Documentation/devices.txt
README
arch/i386/config.in
arch/i386/defconfig
arch/mips/lib/ide-no.c
arch/mips/lib/ide-std.c
arch/ppc/kernel/apus_setup.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/mbx_setup.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/residual.c
arch/ppc/kernel/setup.c
arch/sparc64/solaris/fs.c
drivers/block/Config.in
drivers/block/MAKEDEV-IDE45 [new file with mode: 0644]
drivers/block/MAKEDEV-IDE67 [new file with mode: 0644]
drivers/block/Makefile
drivers/block/aec6210.c [new file with mode: 0644]
drivers/block/ali14xx.c
drivers/block/alim15x3.c [new file with mode: 0644]
drivers/block/buddha.c [new file with mode: 0644]
drivers/block/cmd640.c
drivers/block/cmd646.c
drivers/block/cy82c693.c [new file with mode: 0644]
drivers/block/dtc2278.c
drivers/block/falconide.c [new file with mode: 0644]
drivers/block/gayle.c [new file with mode: 0644]
drivers/block/genhd.c
drivers/block/hpt343.c [new file with mode: 0644]
drivers/block/ht6560b.c
drivers/block/ide-cd.c
drivers/block/ide-disk.c
drivers/block/ide-dma.c
drivers/block/ide-floppy.c
drivers/block/ide-pci.c
drivers/block/ide-pmac.c
drivers/block/ide-probe.c
drivers/block/ide-proc.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/ide.h [deleted file]
drivers/block/ide_modes.h
drivers/block/macide.c [new file with mode: 0644]
drivers/block/ns87415.c
drivers/block/opti621.c
drivers/block/pdc202xx.c [new file with mode: 0644]
drivers/block/pdc4030.c
drivers/block/piix.c [new file with mode: 0644]
drivers/block/qd6580.c
drivers/block/rz1000.c
drivers/block/sl82c105.c
drivers/block/trm290.c
drivers/block/umc8672.c
drivers/block/via82c586.c
drivers/char/serial.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_tty.c
drivers/pci/oldproc.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/cpia.c [new file with mode: 0644]
drivers/usb/cpia.h [new file with mode: 0644]
drivers/usb/mouse.c
drivers/usb/uhci.c
drivers/usb/uhci.h
drivers/usb/usb.c
drivers/usb/usb.h
fs/adfs/dir.c
fs/adfs/namei.c
fs/autofs/dir.c
fs/autofs/root.c
fs/buffer.c
fs/dquot.c
fs/ext2/namei.c
fs/hfs/dir_cap.c
fs/hfs/dir_dbl.c
fs/hfs/dir_nat.c
fs/lockd/svc.c
fs/minix/namei.c
fs/ncpfs/dir.c
fs/smbfs/inode.c
fs/super.c
fs/sysv/inode.c
fs/sysv/namei.c
include/asm-alpha/hdreg.h [new file with mode: 0644]
include/asm-alpha/ide.h
include/asm-alpha/io.h
include/asm-arm/arch-arc/ide.h
include/asm-arm/arch-ebsa285/ide.h
include/asm-arm/arch-rpc/ide.h
include/asm-arm/hdreg.h [new file with mode: 0644]
include/asm-arm/ide.h
include/asm-arm/io.h
include/asm-i386/hdreg.h [new file with mode: 0644]
include/asm-i386/ide.h
include/asm-i386/io.h
include/asm-i386/semaphore.h
include/asm-m68k/hdreg.h [new file with mode: 0644]
include/asm-m68k/ide.h
include/asm-m68k/io.h
include/asm-mips/hdreg.h [new file with mode: 0644]
include/asm-mips/ide.h
include/asm-mips/io.h
include/asm-ppc/hdreg.h [new file with mode: 0644]
include/asm-ppc/ide.h
include/asm-ppc/io.h
include/asm-sparc/io.h
include/asm-sparc64/hdreg.h [new file with mode: 0644]
include/asm-sparc64/ide.h
include/asm-sparc64/io.h
include/linux/hdreg.h
include/linux/hdsmart.h [new file with mode: 0644]
include/linux/ide.h [new file with mode: 0644]
include/linux/isdn.h
include/linux/major.h
include/linux/pci.h
include/linux/quota.h
include/linux/skbuff.h
include/linux/videodev.h
include/net/tcp.h
init/main.c

diff --git a/CREDITS b/CREDITS
index 52021ec29bccfa794d7a934570430ed919f2645c..7b1b5f82669d582ed5cdb17f648f9f5bf397fd0f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -91,6 +91,11 @@ S: 20 Ames Street
 S: Cambridge, Massachusetts 02139
 S: USA
 
+N: Michel Aubry
+E: giovanni <giovanni@sudfr.com>
+D: Aladdin 1533/1543(C) chipset IDE
+D: VIA MVP-3/TX Pro III chipset IDE
+
 N: Jens Axboe
 E: axboe@image.dk
 D: Linux CD-ROM maintainer
@@ -765,6 +770,17 @@ N: Andrew Haylett
 E: ajh@primag.co.uk
 D: Selection mechanism
 
+N: Andre Hedrick
+E: hedrick@astro.dyer.vanderbilt.edu
+D: Uniform Multi-Platform E-IDE driver
+D: Aladdin 1533/1543(C) chipset IDE
+D: HighPoint HPT343/5 chipset IDE
+D: PIIX chipset IDE
+D: Promise Ultra/33 chipset IDE
+D: Promise Ultra/66 chipset IDE
+S: Nashville, TN
+S: USA
+
 N: Jochen Hein
 E: jochen.hein@delphi.central.de
 P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B  CB 0A DA DA 40 77 05 6C
@@ -928,6 +944,10 @@ S: Na Orechovce 7
 S: 160 00 Praha 6
 S: Czech Republic
 
+N: Andreas S. Krebs
+E: akrebs@altavista.net
+D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
+
 N: Niels Kristian Bech Jensen
 E: nkbj@image.dk
 W: http://www.image.dk/~nkbj
@@ -938,6 +958,13 @@ S: Dr. Holsts Vej 34, lejl. 164
 S: DK-8230 Ã…byhøj
 S: Denmark
 
+N: Andrzej Krzysztofowicz
+E: ankry@green.mif.pg.gda.pl
+D: Aladdin 1533/1543(C) chipset IDE
+D: PIIX chipset IDE
+S: Faculty of Applied Phys. & Math.
+S: Technical University of Gdansk
+
 N: Michael K. Johnson
 E: johnsonm@redhat.com
 W: http://www.redhat.com/~johnsonm
@@ -1729,6 +1756,10 @@ E: hps@tanstaafl.de
 D: added PCI support to the serial driver
 S: Buckenhof, Germany
 
+N: Michael Schmitz
+E:
+D: Macintosh IDE Driver
+
 N: Martin Schulze
 E: joey@linux.de
 W: http://home.pages.de/~joey/
@@ -2015,6 +2046,9 @@ D: m68k/Amiga and PPC/CHRP Longtrail coordinator
 D: Frame buffer device and XF68_FBDev maintainer
 D: m68k IDE maintainer
 D: Amiga Zorro maintainer
+D: Amiga Buddha and Catweasel chipset IDE
+D: Atari Falcon chipset IDE
+D: Amiga Gayle chipset IDE
 S: C. Huysmansstraat 12
 S: B-3128 Baal
 S: Belgium
index 3e09463a601ef063bc5bccb304ff5444e52df6ca..c0c9e5bd92c7b06c54e861feadc67e1e0d494648 100644 (file)
@@ -289,9 +289,9 @@ CONFIG_BLK_DEV_NBD
 Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
 CONFIG_BLK_DEV_IDE
   If you say Y here, you will use the full-featured IDE driver to
-  control up to four IDE interfaces, each being able to serve a
-  "master" and a "slave" device, for a total of up to eight IDE
-  disk/cdrom/tape/floppy drives. People with SCSI-only systems
+  control up to eight IDE interfaces, each being able to serve a
+  "master" and a "slave" device, for a total of up to sixteen (16)
+  IDE disk/cdrom/tape/floppy drives.  People with SCSI-only systems
   can say N here.
 
   Useful information about large (>540 MB) IDE disks, multiple
@@ -370,6 +370,15 @@ CONFIG_BLK_DEV_IDEDISK
   root filesystem (the one containing the directory /) is located on
   the IDE disk. If unsure, say Y.
 
+Use multi-mode by default
+CONFIG_IDEDISK_MULTI_MODE
+  If you get this error, try to enable this option.
+
+  hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
+  hda: set_multmode: error=0x04 { DriveStatusError }
+
+  If in doubt, say N.
+
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
   If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is
@@ -396,6 +405,17 @@ CONFIG_BLK_DEV_IDECD
   say M here and read Documentation/modules.txt. The module will be
   called ide-cd.o.
 
+Include CD-Changer Reporting
+CONFIG_IDECD_SLOTS
+  If you have an IDE/ATAPI multi-slot cd-changer and you want
+  to report which slots have disk-present, say Y.  If you say Y
+  and there is not a multi-slot cdrom present, this code is skipped.
+
+  This could be the bases of multi-disk access based on multi-mounts.
+  This is still pie-in-the-sky.
+
+  If unsure, say N.
+
 Include IDE/ATAPI TAPE support
 CONFIG_BLK_DEV_IDETAPE
   If you have an IDE tape drive using the ATAPI protocol, say Y.
@@ -638,14 +658,28 @@ CONFIG_BLK_DEV_NS87415
 
   Please read the comments at the top of drivers/block/ns87415.c.
 
+CY82C693 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CY82C693
+
+  This driver adds detection and support for the CY82C693 chipset
+  used on Digital's PC-Alpha 164SX boards.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/cy82c693.c
+
 VIA82C586 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_VIA82C586
-  This adds initial timing settings for VIA (U)DMA onboard ide
-  controllers that are ATA3 compliant. May work with ATA4 systems, but
-  not tested to date.
+  This allows you to to configure your chipset for a better use while
+  running (U)DMA: it will allow you to enable efficiently the second
+  channel dma usage, as it is may not be set by BIOS. It allows you to
+  run a kernel command line at boot time in order to set fifo config.
+  If no command line is provided, it will try to set fifo configuration
+  at its best. It will allow you to get a proc/ide/via display
+  (while running a "cat") provided you enabled "proc" support and
+  set DISPLAY_APOLLO_TIMINGS in via82c586.c
 
-  If you say Y here, you also need to say Y to "Use DMA by default
-  when available", above.
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
 
   If unsure, say N.
 
@@ -653,6 +687,81 @@ CMD646 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_CMD646
   Say Y here if you have an IDE controller like this.
 
+ALI M15x3 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+  onboard chipsets.  It also tests for Simplex mode and enables
+  normal dual channel support.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/alim15x3.c
+
+  If unsure, say N.
+
+PROMISE PDC20246 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PDC20246
+  This driver adds up to 4 more eide devices sharing a single interrupt.
+  This add-on card is a bootable PCI UDMA controller.
+  Since multiple cards can be installed and there are BIOS ROM problems
+  that happen if the BIOS revisions of all installed cards (three-max)
+  do not match.  Should you be unable to make new BIOS chips with a burner,
+  the driver attempts to dynamic tuning of the chipset at boot-time
+  for max-speed.  Ultra33 BIOS 1.25 or new required for more than one card.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/pdc202xx.c
+
+  If unsure, say N.
+
+PROMISE PDC20262 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PDC20262
+  This driver adds up to 4 more eide devices sharing a single interrupt.
+  This add-on card is a bootable PCI UDMA ATA-66 controller.
+  The driver attempts to dynamic tuning of the chipset at boot-time
+  for max-speed.  Note tested limits are UDMA-2.
+  Ultra66 BIOS 1.11 or newer required.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/pdc202xx.c
+
+  If unsure, say N.
+
+AEC6210 chipset support
+CONFIG_BLK_DEV_AEC6210
+  This driver adds up to 4 more eide devices sharing a single interrupt.
+  This add-on card is a bootable PCI UDMA controller.  In order to get this
+  card to initialize correctly in some cases, you should include this driver.
+
+  This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless.
+
+  Please read the comments at the top of drivers/block/aec6210.c
+
+Intel PIIXn chipsets support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PIIX
+  This driver adds PIO mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly tune
+  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
+  via the standard end-user tool 'hdparm'.
+
+  Please read the comments at the top of drivers/block/piix.c
+
+  If unsure, say N.
+
+HPT343 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT343
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT343 chipset in its current form is a non-bootable
+  PCI UDMA controller. This driver requires dynamic tuning of the
+  chipset during the ide-probe at boot. It is reported to support DVD
+  II drives, by the manufacturer.
+
+  This requires CONFIG_IDEDMA_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/hpt343.c
+
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
@@ -676,6 +785,68 @@ CONFIG_BLK_DEV_ALI14XX
   I/O speeds to be set as well. See the files Documentation/ide.txt
   and drivers/block/ali14xx.c for more info.
 
+Amiga builtin Gayle IDE interface support
+CONFIG_BLK_DEV_GAYLE
+  This is the IDE driver for the builtin IDE interface on some Amiga
+  models.  It supports both the `A1200 style' (used in A600 and A1200)
+  and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE interface.
+  Say Y if you have such an Amiga model and want to use IDE devices
+  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
+  IDE interface.
+
+Falcon IDE interface support
+CONFIG_BLK_DEV_FALCON_IDE
+  This is the IDE driver for the builtin IDE interface on the Atari Falcon.
+  Say Y if you have a Falcon and want to use IDE devices (hard disks,
+  CD-ROM drives, etc.) that are connected to the builtin IDE interface.
+
+Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL)
+CONFIG_BLK_DEV_BUDDHA
+  This is the IDE driver for the IDE interfaces on the Buddha and
+  Catweasel expansion boards.  It supports up to two interfaces on the
+  Buddha and three on the Catweasel.
+  Say Y if you have a Buddha or Catweasel expansion board and want to
+  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
+  to one of its IDE interfaces.
+
+Amiga IDE Doubler support (EXPERIMENTAL)
+CONFIG_BLK_DEV_IDEDOUBLER
+  This driver provides support for the so called `IDE doublers' (made by
+  various manufacturers, e.g. Eyetech) that can be connected to the
+  builtin IDE interface of some Amiga models. Using such an IDE doubler,
+  you can connect up to four instead of two IDE devices on the Amiga's
+  builtin IDE interface.
+  Note that the normal Amiga Gayle IDE driver may not work correctly if
+  you have an IDE doubler and don't enable this driver!
+  Say Y if you have an IDE doubler.  The driver is enabled at kernel
+  runtime using the "ide=doubler" kernel boot parameter.
+
+ Support for PowerMac IDE devices (must also enable IDE)
+ CONFIG_BLK_DEV_IDE_PMAC
+   No help for CONFIG_BLK_DEV_IDE_PMAC
+
+ PowerMac IDE DMA support
+ CONFIG_BLK_DEV_IDEDMA_PMAC
+   No help for CONFIG_BLK_DEV_IDEDMA_PMAC
+
+ Use DMA by default
+ CONFIG_PMAC_IDEDMA_AUTO
+   No help for CONFIG_PMAC_IDEDMA_AUTO
+
+Macintosh Quadra/Powerbook IDE interface support
+CONFIG_BLK_DEV_MAC_IDE
+  This is the IDE driver for the builtin IDE interface on the some m68k
+  Macintosh models. It supports both the `Quadra style' (used in Quadra/
+  Centris 630 and Performa 588 models) and `Powerbook style' (used in the
+  Powerbook 150 and 190 models) IDE interface.
+  Say Y if you have such an Macintosh model and want to use IDE devices
+  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
+  IDE interface.
+
+ RapIDE interface support
+ CONFIG_BLK_DEV_IDE_RAPIDE
+   No help for CONFIG_BLK_DEV_IDE_RAPIDE
+
 XT hard disk support
 CONFIG_BLK_DEV_XD
   Very old 8 bit hard disk controllers used in the IBM XT computer
index 84c0e487507c680a8d3329f73df10e8d660a09b5..5bd758c0d6b10508c761d48cbd9417df9f7e30a7 100644 (file)
@@ -254,7 +254,9 @@ Your cooperation is appreciated.
 \major{86}{}{char }{SCSI media changer}
 \major{87}{}{char }{Sony Control-A1 stereo control bus}
 \major{88}{}{char }{COMX synchronous serial card}
+\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
 \major{89}{}{char }{I$^2$C bus interface}
+\major{  }{}{block}{Seventh IDE hard disk/CD-ROM interface}
 \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
 \major{91}{}{char }{CAN-Bus controller}
 \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
@@ -1745,6 +1747,16 @@ on {\url http://home.pages.de/~videotext/\/}.
        \minordots
 \end{devicelist}
 
+\begin{devicelist}
+\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
+        \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)}
+        \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)}
+\end{devicelist}
+
+\noindent
+Partitions are handled the same way as for the first interface (see
+major number 3).
+
 \begin{devicelist}
 \major{89}{}{char }{I$^2$C bus interface}
        \minor{0}{/dev/i2c0}{First I$^2$C adapter}
@@ -1752,6 +1764,16 @@ on {\url http://home.pages.de/~videotext/\/}.
        \minordots
 \end{devicelist}
 
+\begin{devicelist}
+\major{  }{}{block}{Seventh IDE hard disk/CD-ROM interface}
+        \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)}
+        \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)}
+\end{devicelist}
+
+\noindent
+Partitions are handled the same way as for the first interface (see
+major number 3).
+
 \begin{devicelist}
 \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
         \minor{0}{/dev/mtd0}{First MTD (rw)}
index 2d27f3644b950301db735d7e96a3cd05ef1442fc..92b2d621d6e72f30d8f2ce6790c6108880d2b58b 100644 (file)
@@ -1215,11 +1215,25 @@ Your cooperation is appreciated.
                  1 = /dev/comx1        COMX channel 1
                    ...
 
+    block      Sixth IDE hard disk/CD-ROM interface
+                 0 = /dev/hdm          Master: whole disk (or CD-ROM)
+                64 = /dev/hdn          Slave: whole disk (or CD-ROM)
+
+               Partitions are handled the same way as for the first
+               interface (see major number 3).
+
  89 char       I2C bus interface
                  0 = /dev/i2c0         First I2C adapter
                  1 = /dev/i2c1         Second I2C adapter
                    ...
 
+    block      Seventh IDE hard disk/CD-ROM interface
+                 0 = /dev/hdo          Master: whole disk (or CD-ROM)
+                64 = /dev/hdp          Slave: whole disk (or CD-ROM)
+
+               Partitions are handled the same way as for the first
+               interface (see major number 3).
+
  90 char       Memory Technology Device (RAM, ROM, Flash)
                  0 = /dev/mtd0         First MTD (rw)
                  1 = /dev/mtdr0        First MTD (ro)
diff --git a/README b/README
index b1bac81558f52408d07247ef4a82dec59188aad6..6c8b96d00cbc1536b1196ffae27e28021d5c306d 100644 (file)
--- a/README
+++ b/README
@@ -1,9 +1,23 @@
-       Linux kernel release 2.2.xx
+       Linux kernel release 2.3.xx
 
-These are the release notes for Linux version 2.2.  Read them carefully,
+These are the release notes for Linux version 2.3.  Read them carefully,
 as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong. 
 
+Linux version 2.3 is a DEVELOPMENT kernel, and not intended for general
+public use.  Different releases may have various and sometimes severe
+bugs.  It is *strongly* recommended that you back up the previous kernel
+before installing any new 2.3.xx release.
+
+If you need to use a proven and stable Linux kernel, please use 1.2.13,
+2.0.36 or 2.2.xx.  All features which will be in the 2.3.xx releases will
+be contained in 2.4.xx when the code base has stabilized again.
+
+If you decide to use 2.3, it is recommended that you join the kernel mailing
+list.  To do this, e-mail majordomo@vger.rutgers.edu, and put in the body
+of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest"
+for a daily digest of the mailing list (it is a high-traffic list.)
+
 However, please make sure you don't ask questions which are already answered
 in various files in the Documentation directory.  See DOCUMENTATION below.
 
@@ -48,12 +62,12 @@ INSTALLING the kernel:
  - If you install the full sources, do a
 
                cd /usr/src
-               gzip -cd linux-2.2.XX.tar.gz | tar xfv -
+               gzip -cd linux-2.3.XX.tar.gz | tar xfv -
 
    to get it all put in place. Replace "XX" with the version number of the
    latest kernel.
 
- - You can also upgrade between 2.2.xx releases by patching.  Patches are
+ - You can also upgrade between 2.3.xx releases by patching.  Patches are
    distributed in the traditional gzip and the new bzip2 format.  To
    install by patching, get all the newer patch files and do
 
@@ -91,7 +105,7 @@ INSTALLING the kernel:
 
 SOFTWARE REQUIREMENTS
 
-   Compiling and running the 2.2.x kernels requires up-to-date
+   Compiling and running the 2.3.x kernels requires up-to-date
    versions of various software packages.  Consult
    ./Documentation/Changes for the minimum version numbers required
    and how to get updates for these packages.  Beware that using
index 65a3aee0a71c57c78ef3817536de7183145e5357..00c3b841bea95a1dcc0b80c1221c5d7bc39466d2 100644 (file)
@@ -168,7 +168,7 @@ endmenu
 
 source drivers/char/Config.in
 
-source drivers/usb/Config.in
+source drivers/usb/Config.in
 
 source fs/Config.in
 
index 5bd7fe5bd0bdb69d13b2d450ad898572a7173f57..bbf32f2bcd18018f88c853c3458e6c97383a78a8 100644 (file)
@@ -73,7 +73,9 @@ CONFIG_BLK_DEV_IDE=y
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
+# CONFIG_IDECD_SLOTS is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -83,6 +85,7 @@ CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_AEC6210 is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
@@ -96,6 +99,7 @@ CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_XD is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -291,6 +295,17 @@ CONFIG_82C710_MOUSE=y
 #
 # CONFIG_FTAPE is not set
 
+#
+# USB drivers - not for the faint of heart
+#
+CONFIG_USB=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_MOUSE=y
+CONFIG_USB_KBD=y
+# CONFIG_USB_AUDIO is not set
+
 #
 # Filesystems
 #
index 5a11e03839c56a67aa32cca72802ab421ee2a0a9..d2b4fe04a2f2b032ceb8b3ab0429e4a6e5eb65c5 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/hdreg.h>
 #include <linux/kernel.h>
+#include <asm/hdreg.h>
 #include <asm/ptrace.h>
 #include <asm/ide.h>
 
@@ -24,8 +25,10 @@ static ide_ioreg_t no_ide_default_io_base(int index)
        return 0;
 }
 
-static void no_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base,
-                                     int *irq)
+static void no_ide_init_hwif_ports (   hw_regs_t *hw,
+                                       ide_ioreg_t data_port,
+                                       ide_ioreg_t ctrl_port,
+                                       int *irq)
 {
 }
 
index e6bf4dc5f7f03e5cf370be0ea7ee577be6f89123..5b61daf46ec7d69f0678454054f239a8a9a952af 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/hdreg.h>
 #include <asm/ptrace.h>
+#include <asm/hdreg.h>
 #include <asm/ide.h>
 
 static int std_ide_default_irq(ide_ioreg_t base)
@@ -41,15 +42,23 @@ static ide_ioreg_t std_ide_default_io_base(int index)
        }
 }
 
-static void std_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base,
-                                     int *irq)
+static void std_ide_init_hwif_ports (  hw_regs_t *hw,
+                                       ide_ioreg_t data_port,
+                                       ide_ioreg_t ctrl_port,
+                                       int *irq)
 {
-       ide_ioreg_t port = base;
-       int i = 8;
+       ide_ioreg_t reg = data_port;
+       int i;
 
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+       }
        if (irq != NULL)
                *irq = 0;
 }
index 55e57fc5b72c7ef6b8d5d514ecc240d489951d5a..2540e09111fcffff1d9e76f4ab5b52749cb559ca 100644 (file)
@@ -561,9 +561,9 @@ apus_ide_fix_driveid(struct hd_driveid *id)
 }
 
 __initfunc(void
-apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq))
 {
-        m68k_ide_init_hwif_ports(p, base, irq);
+        m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
 }
 #endif
 
index 2c652f0498c18437f91d3c1c0d32883183a921cc..99e97e69eae44d6db96368cd25d8957de90acb16 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
@@ -561,16 +562,23 @@ chrp_ide_fix_driveid(struct hd_driveid *id)
         ppc_generic_ide_fix_driveid(id);
 }
 
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-        ide_ioreg_t port = base;
-        int i = 8;
-
-        while (i--)
-                *p++ = port++;
-        *p++ = port;
-        if (irq != NULL)
-                *irq = chrp_ide_irq;
+       ide_ioreg_t reg = data_port;
+       int i;
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = 0;
+       }
+       if (irq != NULL)
+               hw->irq = chrp_ide_irq;
 }
 
 EXPORT_SYMBOL(chrp_ide_irq);
index 0f1eb3eb5f9cca6a64db981afb5a2f5679fd4a80..f086ef743e845e91931a20fa156d696036c78b43 100644 (file)
@@ -380,23 +380,35 @@ mbx_ide_fix_driveid(struct hd_driveid *id)
         ppc_generic_ide_fix_driveid(id);
 }
 
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-       ide_ioreg_t port = base;
-       int i = 8;
-
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
-       if (irq != NULL)
-               *irq = 0;
+       ide_ioreg_t reg = data_port;
+       int i;
+
+       *irq = 0;
+
+       if (data_port != 0)     /* Only map the first ATA flash drive */
+               return;
+
 #ifdef ATA_FLASH
-       base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
-       for (i = 0; i < 8; ++i)
-               *p++ = base++;
-       *p = ++base;            /* Does not matter */
+
+       reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200);
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+
+       /* Does not matter */
+
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = reg;
+       }
        if (irq)
-               *irq = 13;
+               hw->irq = 13;
 #endif
 }
 #endif
index 9f8638021576dfc46c5fffbf2aedba9753f82581..bfd34fea62d70112fe518411e597b8f33d3a4421 100644 (file)
@@ -365,7 +365,7 @@ note_scsi_host(struct device_node *node, void *host))
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
 extern int pmac_ide_count;
 extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 };
 
 __initfunc(kdev_t find_ide_boot(void))
 {
@@ -544,7 +544,16 @@ pmac_ide_fix_driveid(struct hd_driveid *id)
 }
 
 /* This is declared in drivers/block/ide-pmac.c */
-void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void pmac_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+void
+ide_init_default_hwifs(void)
+{
+}
 #endif
 
 __initfunc(void
index 834bdf1025951368829aece653ea7178ac1d1d07..36a68ffd67623fc1b0dbb1e2fc9f27999c71a629 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/atomic.h>
 #include <asm/bitops.h>
index de18f465adac7afb4c0b630436e641a884098333..30207bf3d82ceae191654fa2645501106bf0c970 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
@@ -691,14 +692,20 @@ prep_ide_fix_driveid(struct hd_driveid *id)
 }
 
 __initfunc(void
-prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq))
 {
-       ide_ioreg_t port = base;
-       int i = 8;
+       ide_ioreg_t reg = data_port;
+       int i;
 
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] =  hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+       }
        if (irq != NULL)
                *irq = 0;
 }
index 83333f660c2527fce9e1a15123dd3ef85b6b6935..dc740aaf6583240dbf1c858e444ef6b0d5641f2b 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 
 
index 2d38f3adc98d97713db521644b6451465522bac8..8e656d77ce0cff0c00c91fa9188e7ec5b3bd4838 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/pmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
+#include <linux/ide.h>
 #include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
@@ -160,10 +161,10 @@ void machine_halt(void)
 }
   
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
        if (ppc_ide_md.ide_init_hwif != NULL) {
-               ppc_ide_md.ide_init_hwif(p, base, irq);
+               ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq);
        }
 }
 #endif
index f0921ab9f3b98e5df482945d3fee918393442903..c926f3a942e80e859d1e9bef20561e34b6ba45e6 100644 (file)
@@ -410,7 +410,11 @@ static int report_statvfs(struct inode *inode, u32 buf)
        mm_segment_t old_fs = get_fs();
        int error;
        struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
-                       
+
+       if (!inode->i_sb)
+               return -ENODEV;
+       if (!inode->i_sb->s_op->statfs)
+               return -ENOSYS;
        set_fs (KERNEL_DS);
        error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
        set_fs (old_fs);
@@ -448,6 +452,10 @@ static int report_statvfs64(struct inode *inode, u32 buf)
        int error;
        struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
                        
+       if (!inode->i_sb)
+               return -ENODEV;
+       if (!inode->i_sb->s_op->statfs)
+               return -ENOSYS;
        set_fs (KERNEL_DS);
        error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
        set_fs (old_fs);
@@ -489,9 +497,7 @@ asmlinkage int solaris_statvfs(u32 path, u32 buf)
        if (!IS_ERR(dentry)) {
                struct inode * inode = dentry->d_inode;
 
-               error = -ENOSYS;
-               if (inode->i_sb->s_op->statfs)
-                       error = report_statvfs(inode, buf);
+               error = report_statvfs(inode, buf);
                dput(dentry);
        }
        unlock_kernel();
@@ -515,10 +521,6 @@ asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
                error = -ENOENT;
        else if (!(inode = dentry->d_inode))
                error = -ENOENT;
-       else if (!inode->i_sb)
-               error = -ENODEV;
-       else if (!inode->i_sb->s_op->statfs)
-               error = -ENOSYS;
        else
                error = report_statvfs(inode, buf);
        fput(file);
@@ -538,9 +540,7 @@ asmlinkage int solaris_statvfs64(u32 path, u32 buf)
        if (!IS_ERR(dentry)) {
                struct inode * inode = dentry->d_inode;
 
-               error = -ENOSYS;
-               if (inode->i_sb->s_op->statfs)
-                       error = report_statvfs64(inode, buf);
+               error = report_statvfs64(inode, buf);
                dput(dentry);
        }
        unlock_kernel();
@@ -564,10 +564,6 @@ asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
                error = -ENOENT;
        else if (!(inode = dentry->d_inode))
                error = -ENOENT;
-       else if (!inode->i_sb)
-               error = -ENODEV;
-       else if (!inode->i_sb->s_op->statfs)
-               error = -ENOSYS;
        else
                error = report_statvfs64(inode, buf);
        fput(file);
index 390aa708ce30cd94db2d55464d14474e3002c200..47fc9eac1b79674c077688e5c95567fc427bb2af 100644 (file)
@@ -19,7 +19,13 @@ if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
 else
   bool '   Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
   dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+  if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
+    bool '     Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
+  fi
   dep_tristate '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+  if [ "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+    bool '     Include CD-Changer Reporting' CONFIG_IDECD_SLOTS
+  fi
   dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
   dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
   dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
@@ -34,16 +40,29 @@ else
       if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
         bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
         bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+        bool '     AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
         if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
           bool '     Use DMA by default when available' CONFIG_IDEDMA_AUTO
         fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+          bool '     Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX
           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
             bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
             bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
+            bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
+            bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+            bool '     PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246
+            bool '     PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262
+            if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \
+                 "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then
+              define_bool CONFIG_BLK_DEV_PDC202XX y
+            else
+              define_bool CONFIG_BLK_DEV_PDC202XX n
+            fi
+            bool '     HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343
           fi
         fi
       fi
@@ -72,10 +91,25 @@ else
       bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then
-        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-        fi
+          bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+        fi
       fi
     fi
+    if [ "$CONFIG_AMIGA" = "y" ]; then
+      bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
+      fi
+    fi
+    if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
+    fi
+    if [ "$CONFIG_ATARI" = "y" ]; then
+      bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
+    fi
+    if [ "$CONFIG_MAC" = "y" ]; then
+      bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+    fi
   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
@@ -129,6 +163,19 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
 fi
 
+
+if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \
+     "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
+     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT343" = "y" -o \
+     "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+  define_bool CONFIG_BLK_DEV_IDE_MODES y
+else
+  define_bool CONFIG_BLK_DEV_IDE_MODES n
+fi
+
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
 else
diff --git a/drivers/block/MAKEDEV-IDE45 b/drivers/block/MAKEDEV-IDE45
new file mode 100644 (file)
index 0000000..c55a9b3
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+#      Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
+#
+#      The song goes, "I did it the hard way..........."
+#
+
+if [ ! -f /dev/hdi ]; then \
+       echo "Making IDE4 Primary Devices hdi's"; \
+       mknod /dev/hdi b 56 0; \
+       mknod /dev/hdi1 b 56 1; \
+       mknod /dev/hdi2 b 56 2; \
+       mknod /dev/hdi3 b 56 3; \
+       mknod /dev/hdi4 b 56 4; \
+       mknod /dev/hdi5 b 56 5; \
+       mknod /dev/hdi6 b 56 6; \
+       mknod /dev/hdi7 b 56 7; \
+       mknod /dev/hdi8 b 56 8; \
+       mknod /dev/hdi9 b 56 9; \
+       mknod /dev/hdi10 b 56 10; \
+       mknod /dev/hdi11 b 56 11; \
+       mknod /dev/hdi12 b 56 12; \
+       mknod /dev/hdi13 b 56 13; \
+       mknod /dev/hdi14 b 56 14; \
+       mknod /dev/hdi15 b 56 15; \
+       mknod /dev/hdi16 b 56 16; \
+       chown root.disk /dev/hdi*; \
+       chmod 660 /dev/hdi*; \
+fi
+
+if [ ! -f /dev/hdj ]; then \
+       echo "Making IDE4 Secondary Devices hdj's"; \
+       mknod /dev/hdj b 56 64; \
+       mknod /dev/hdj1 b 56 65; \
+       mknod /dev/hdj2 b 56 66; \
+       mknod /dev/hdj3 b 56 67; \
+       mknod /dev/hdj4 b 56 68; \
+       mknod /dev/hdj5 b 56 69; \
+       mknod /dev/hdj6 b 56 70; \
+       mknod /dev/hdj7 b 56 71; \
+       mknod /dev/hdj8 b 56 72; \
+       mknod /dev/hdj9 b 56 73; \
+       mknod /dev/hdj10 b 56 74; \
+       mknod /dev/hdj11 b 56 75; \
+       mknod /dev/hdj12 b 56 76; \
+       mknod /dev/hdj13 b 56 77; \
+       mknod /dev/hdj14 b 56 78; \
+       mknod /dev/hdj15 b 56 79; \
+       mknod /dev/hdj16 b 56 80; \
+       chown root.disk /dev/hdj*; \
+       chmod 660 /dev/hdj*; \
+fi
+
+if [ ! -f /dev/hdk ]; then \
+       echo "Making IDE5 Primary Devices hdk's"; \
+       mknod /dev/hdk b 57 0; \
+       mknod /dev/hdk1 b 57 1; \
+       mknod /dev/hdk2 b 57 2; \
+       mknod /dev/hdk3 b 57 3; \
+       mknod /dev/hdk4 b 57 4; \
+       mknod /dev/hdk5 b 57 5; \
+       mknod /dev/hdk6 b 57 6; \
+       mknod /dev/hdk7 b 57 7; \
+       mknod /dev/hdk8 b 57 8; \
+       mknod /dev/hdk9 b 57 9; \
+       mknod /dev/hdk10 b 57 10; \
+       mknod /dev/hdk11 b 57 11; \
+       mknod /dev/hdk12 b 57 12; \
+       mknod /dev/hdk13 b 57 13; \
+       mknod /dev/hdk14 b 57 14; \
+       mknod /dev/hdk15 b 57 15; \
+       mknod /dev/hdk16 b 57 16; \
+       chown root.disk /dev/hdk*; \
+       chmod 660 /dev/hdk*; \
+fi
+
+if [ ! -f /dev/hdl ]; then \
+       echo "Making IDE5 Secondary Devices hdl's"; \
+       mknod /dev/hdl b 57 64; \
+       mknod /dev/hdl1 b 57 65; \
+       mknod /dev/hdl2 b 57 66; \
+       mknod /dev/hdl3 b 57 67; \
+       mknod /dev/hdl4 b 57 68; \
+       mknod /dev/hdl5 b 57 69; \
+       mknod /dev/hdl6 b 57 70; \
+       mknod /dev/hdl7 b 57 71; \
+       mknod /dev/hdl8 b 57 72; \
+       mknod /dev/hdl9 b 57 73; \
+       mknod /dev/hdl10 b 57 74; \
+       mknod /dev/hdl11 b 57 75; \
+       mknod /dev/hdl12 b 57 76; \
+       mknod /dev/hdl13 b 57 77; \
+       mknod /dev/hdl14 b 57 78; \
+       mknod /dev/hdl15 b 57 79; \
+       mknod /dev/hdl16 b 57 80; \
+       chown root.disk /dev/hdl*; \
+       chmod 660 /dev/hdl*; \
+fi
+
diff --git a/drivers/block/MAKEDEV-IDE67 b/drivers/block/MAKEDEV-IDE67
new file mode 100644 (file)
index 0000000..27728be
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+#      Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
+#
+#      The song goes, "I did it the hard way..........."
+#
+
+if [ ! -f /dev/hdm ]; then \
+       echo "Making IDE6 Primary Devices hdm's"; \
+       mknod /dev/hdm b 88 0; \
+       mknod /dev/hdm1 b 88 1; \
+       mknod /dev/hdm2 b 88 2; \
+       mknod /dev/hdm3 b 88 3; \
+       mknod /dev/hdm4 b 88 4; \
+       mknod /dev/hdm5 b 88 5; \
+       mknod /dev/hdm6 b 88 6; \
+       mknod /dev/hdm7 b 88 7; \
+       mknod /dev/hdm8 b 88 8; \
+       mknod /dev/hdm9 b 88 9; \
+       mknod /dev/hdm10 b 88 10; \
+       mknod /dev/hdm11 b 88 11; \
+       mknod /dev/hdm12 b 88 12; \
+       mknod /dev/hdm13 b 88 13; \
+       mknod /dev/hdm14 b 88 14; \
+       mknod /dev/hdm15 b 88 15; \
+       mknod /dev/hdm16 b 88 16; \
+       chown root.disk /dev/hdm*; \
+       chmod 660 /dev/hdm*; \
+fi
+
+if [ ! -f /dev/hdn ]; then \
+       echo "Making IDE6 Secondary Devices hdn's"; \
+       mknod /dev/hdn b 88 64; \
+       mknod /dev/hdn1 b 88 65; \
+       mknod /dev/hdn2 b 88 66; \
+       mknod /dev/hdn3 b 88 67; \
+       mknod /dev/hdn4 b 88 68; \
+       mknod /dev/hdn5 b 88 69; \
+       mknod /dev/hdn6 b 88 70; \
+       mknod /dev/hdn7 b 88 71; \
+       mknod /dev/hdn8 b 88 72; \
+       mknod /dev/hdn9 b 88 73; \
+       mknod /dev/hdn10 b 88 74; \
+       mknod /dev/hdn11 b 88 75; \
+       mknod /dev/hdn12 b 88 76; \
+       mknod /dev/hdn13 b 88 77; \
+       mknod /dev/hdn14 b 88 78; \
+       mknod /dev/hdn15 b 88 79; \
+       mknod /dev/hdn16 b 88 80; \
+       chown root.disk /dev/hdn*; \
+       chmod 660 /dev/hdn*; \
+fi
+
+if [ ! -f /dev/hdo ]; then \
+       echo "Making IDE7 Primary Devices hdo's"; \
+       mknod /dev/hdo b 89 0; \
+       mknod /dev/hdo1 b 89 1; \
+       mknod /dev/hdo2 b 89 2; \
+       mknod /dev/hdo3 b 89 3; \
+       mknod /dev/hdo4 b 89 4; \
+       mknod /dev/hdo5 b 89 5; \
+       mknod /dev/hdo6 b 89 6; \
+       mknod /dev/hdo7 b 89 7; \
+       mknod /dev/hdo8 b 89 8; \
+       mknod /dev/hdo9 b 89 9; \
+       mknod /dev/hdo10 b 89 10; \
+       mknod /dev/hdo11 b 89 11; \
+       mknod /dev/hdo12 b 89 12; \
+       mknod /dev/hdo13 b 89 13; \
+       mknod /dev/hdo14 b 89 14; \
+       mknod /dev/hdo15 b 89 15; \
+       mknod /dev/hdo16 b 89 16; \
+       chown root.disk /dev/hdo*; \
+       chmod 660 /dev/hdo*; \
+fi
+
+if [ ! -f /dev/hdp ]; then \
+       echo "Making IDE7 Secondary Devices hdp's"; \
+       mknod /dev/hdp b 89 64; \
+       mknod /dev/hdp1 b 89 65; \
+       mknod /dev/hdp2 b 89 66; \
+       mknod /dev/hdp3 b 89 67; \
+       mknod /dev/hdp4 b 89 68; \
+       mknod /dev/hdp5 b 89 69; \
+       mknod /dev/hdp6 b 89 70; \
+       mknod /dev/hdp7 b 89 71; \
+       mknod /dev/hdp8 b 89 72; \
+       mknod /dev/hdp9 b 89 73; \
+       mknod /dev/hdp10 b 89 74; \
+       mknod /dev/hdp11 b 89 75; \
+       mknod /dev/hdp12 b 89 76; \
+       mknod /dev/hdp13 b 89 77; \
+       mknod /dev/hdp14 b 89 78; \
+       mknod /dev/hdp15 b 89 79; \
+       mknod /dev/hdp16 b 89 80; \
+       chown root.disk /dev/hdp*; \
+       chmod 660 /dev/hdp*; \
+fi
+
index 79f3a9547fd197810eb722fa27663d848c0cd9b0..fd9b99c354932d19eb414999b33c625f70825c2e 100644 (file)
@@ -158,6 +158,22 @@ ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
 IDE_OBJS += via82c586.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_GAYLE),y)
+IDE_OBJS += gayle.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y)
+IDE_OBJS += falconide.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y)
+IDE_OBJS += macide.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_BUDDHA),y)
+IDE_OBJS += buddha.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_CMD646),y)
 IDE_OBJS += cmd646.o
 endif
@@ -166,6 +182,30 @@ ifeq ($(CONFIG_BLK_DEV_SL82C105),y)
 IDE_OBJS += sl82c105.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
+IDE_OBJS += alim15x3.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
+IDE_OBJS += cy82c693.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_PIIX),y)
+IDE_OBJS += piix.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_PDC202XX),y)
+IDE_OBJS += pdc202xx.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_AEC6210),y)
+IDE_OBJS += aec6210.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_HPT343),y)
+IDE_OBJS += hpt343.o
+endif
+
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
 
 ifeq ($(CONFIG_PROC_FS),y)
diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c
new file mode 100644 (file)
index 0000000..c00cac8
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * linux/drivers/block/aec6210.c       Version 0.01    Nov 17, 1998
+ *
+ * Copyright (C) 1998  Andre Hedrick (hedrick@astro.dyer.vanderbilt.edu)
+ *
+ *  pio 0 ::       40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02
+ *  pio 1 ::       40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
+ *  pio 2 ::       40: 08 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
+ *  pio 3 ::       40: 03 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *  pio 4 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *  dma 0 ::       40: 0a 07 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *  dma 1 ::       40: 02 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *  dma 2 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *                 50: ff ff ff ff 00 06 04 00 00 00 00 00 00 00 00 00
+ *
+ * udma 0 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *                 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00
+ *
+ * udma 1 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *                 50: ff ff ff ff 01 06 04 00 00 00 00 00 00 00 00 00
+ *
+ * udma 2 ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *                 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00
+ *
+ * auto   ::       40: 01 04 00 00 00 00 00 00 02 05 a6 05 00 02 00 02
+ *                 50: ff ff ff ff 02 06 04 00 00 00 00 00 00 00 00 00
+ *
+ * auto   ::       40: 01 04 01 04 01 04 01 04 02 05 a6 cf 00 02 00 02
+ *                 50: ff ff ff ff aa 06 04 00 00 00 00 00 00 00 00 00
+ *
+ *                 NO-Devices
+ *                 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02
+ *                 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00
+
+ */
+
+#include <linux/config.h>      /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+__initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name))
+{
+       if (dev->rom_address) {
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+                       dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+               printk("%s: ROM enabled at 0x%08lx\n",
+                       name, dev->rom_address);
+       }
+       return dev->irq;
+}
index 5d5ca66dc79dbcd3cdf179141e0d8eb4653d7592..46a275305122c0f239b4a24d68ced5954905de4a 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /* port addresses for auto-detection */
diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c
new file mode 100644 (file)
index 0000000..013b472
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * linux/drivers/block/alim15x3.c      Version 0.04    Feb. 8, 1999
+ *
+ *  Copyright (C) 1998-99 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer
+ *
+ *  (U)DMA capable version of ali 1533/1543(C)
+ *
+ *  Default disable (U)DMA on all devices execpt hard disks.
+ *  This measure of overkill is needed to stablize the chipset code.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy);
+extern int (*ali_display_info)(char *, char **, off_t, int, int);  /* ide-proc.c */
+struct pci_dev *bmide_dev;
+
+char *fifo[4] = {
+       "FIFO Off",
+       "FIFO On ",
+       "DMA mode",
+       "PIO mode" };
+
+char *udmaT[8] = {
+       "1.5T",
+       "  2T",
+       "2.5T",
+       "  3T",
+       "3.5T",
+       "  4T",
+       "  6T",
+       "  8T"
+};
+
+char *channel_status[8] = {
+       "OK            ",
+       "busy          ",
+       "DRQ           ",
+       "DRQ busy      ",
+       "error         ",
+       "error busy    ",
+       "error DRQ     ",
+       "error DRQ busy"
+};
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+__initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name))
+{
+       byte confreg0 = 0, confreg1 =0, progif = 0;
+       int errors = 0;
+
+       if (pci_read_config_byte(dev, 0x50, &confreg1))
+               goto veryspecialsettingserror;
+       if (!(confreg1 & 0x02))
+               if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02))
+                       goto veryspecialsettingserror;
+
+       if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif))
+               goto veryspecialsettingserror;
+       if (!(progif & 0x40)) {
+               /*
+                * The way to enable them is to set progif
+                * writable at 0x4Dh register, and set bit 6
+                * of progif to 1:
+                */
+               if (pci_read_config_byte(dev, 0x4d, &confreg0))
+                       goto veryspecialsettingserror;
+               if (confreg0 & 0x80)
+                       if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80))
+                               goto veryspecialsettingserror;
+               if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40))
+                       goto veryspecialsettingserror;
+               if (confreg0 & 0x80)
+                       if (pci_write_config_byte(dev, 0x4d, confreg0))
+                               errors++;
+       }
+
+       if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40)))
+               goto veryspecialsettingserror;
+
+       printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n",
+               name, errors ? "with Error(s)" : "Succeeded" );
+       return 0;
+
+veryspecialsettingserror:
+       printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name);
+       return 0;
+}
+
+int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+               case ide_dma_check:
+                       if (drive->media == ide_cdrom) {
+                               ide_hwif_t *hwif        = HWIF(drive);
+                               struct pci_dev *dev     = hwif->pci_dev;
+                               struct hd_driveid *id   = drive->id;
+                               byte cd_dma_fifo        = 0;
+
+                               pci_read_config_byte(dev, 0x53, &cd_dma_fifo);
+
+                               if (((id->field_valid & 4) || (id->field_valid & 2)) &&
+                                   (id->capability & 1) && hwif->autodma) {
+                                       unsigned long dma_set_bit  = hwif->dma_base + 2;
+#if 0
+                                       if (cd_dma_fifo & 0x02)
+                                               pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x02);
+                                       pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01);
+#else
+                                       pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01|0x02);
+#endif
+                                       if (drive->select.b.unit & 0x01) {
+                                               outb(inb(dma_set_bit)|0x40, dma_set_bit);
+                                       } else {
+                                               outb(inb(dma_set_bit)|0x20, dma_set_bit);
+                                       }
+                               } else {
+                                       if (cd_dma_fifo & 0x01)
+                                               pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x01);
+                                       pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x02);
+                               }
+                       } else if (drive->media != ide_disk) {
+                               return ide_dmaproc(ide_dma_off_quietly, drive);
+                       }
+               default:
+                       break;
+       }
+       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
+}
+
+__initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif))
+{
+       struct pci_dev *dev;
+       byte ideic, inmir;
+       byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+                                     1, 11, 0, 12, 0, 14, 0, 15 };
+       hwif->irq = hwif->channel ? 15 : 14;
+       for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */
+               if (dev->vendor==PCI_VENDOR_ID_AL &&
+                  dev->device==PCI_DEVICE_ID_AL_M1533)
+                       break;
+       if (dev) {                      
+               pci_read_config_byte(dev, 0x58, &ideic);
+               ideic = ideic & 0x03;
+               if ((hwif->channel && ideic == 0x03) ||
+                  (!hwif->channel && !ideic)) {
+                       pci_read_config_byte(dev, 0x44, &inmir);
+                       inmir = inmir & 0x0f;
+                       hwif->irq = irq_routing_table[inmir];
+               } else
+                       if (hwif->channel && !(ideic & 0x01)) {
+                               pci_read_config_byte(dev, 0x75, &inmir);
+                               inmir = inmir & 0x0f;
+                               hwif->irq = irq_routing_table[inmir];
+                       }
+       }
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+       bmide_dev = hwif->pci_dev;
+       ali_display_info = &ali_get_info;
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+       if (hwif->dma_base)
+               hwif->dmaproc = &ali15x3_dmaproc;
+       return;
+}
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+       byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
+       unsigned int bibma;
+       byte c0, c1;
+       byte rev, tmp;
+       char *p = buffer;
+       char *q;
+
+       /* fetch rev. */
+       pci_read_config_byte(bmide_dev, 0x08, &rev);
+       if (rev >= 0xc1)        /* M1543C or newer */
+               udmaT[7] = " ???";
+       else
+               fifo[3]  = "   ???  ";
+
+       /* first fetch bibma: */
+       pci_read_config_dword(bmide_dev, 0x20, &bibma);
+       bibma = (bibma & 0xfff0) ;
+       /*
+        * at that point bibma+0x2 et bibma+0xa are byte
+        * registers to investigate:
+        */
+       c0 = inb((unsigned short)bibma + 0x02);
+       c1 = inb((unsigned short)bibma + 0x0a);
+
+       p += sprintf(p,
+               "\n                                Ali M15x3 Chipset.\n");
+       p += sprintf(p,
+               "                                ------------------\n");
+       pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+       p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+       pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+       p += sprintf(p,
+               "CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+               (reg53h & 0x02) ? "Yes" : "No ",
+               (reg53h & 0x01) ? "Yes" : "No " );
+       pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+       p += sprintf(p,
+               "FIFO Status: contains %d Words, runs%s%s\n\n",
+               (reg53h & 0x3f),
+               (reg53h & 0x40) ? " OVERWR" : "",
+               (reg53h & 0x80) ? " OVERRD." : "." );
+
+       p += sprintf(p,
+               "-------------------primary channel-------------------secondary channel---------\n\n");
+
+       pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+       p += sprintf(p,
+               "channel status:       %s                               %s\n",
+               (reg53h & 0x20) ? "On " : "Off",
+               (reg53h & 0x10) ? "On " : "Off" );
+
+       p += sprintf(p,
+               "both channels togth:  %s                               %s\n",
+               (c0&0x80) ? "No " : "Yes",
+               (c1&0x80) ? "No " : "Yes" );
+
+       pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+       p += sprintf(p,
+               "Channel state:        %s                    %s\n",
+               channel_status[reg53h & 0x07],
+               channel_status[(reg53h & 0x70) >> 4] );
+
+       pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+       p += sprintf(p,
+               "Add. Setup Timing:    %dT                                %dT\n",
+               (reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+               (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+       pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+       p += sprintf(p,
+               "Command Act. Count:   %dT                                %dT\n"
+               "Command Rec. Count:   %dT                               %dT\n\n",
+               (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+               (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+               (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+               (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+       p += sprintf(p,
+               "----------------drive0-----------drive1------------drive0-----------drive1------\n\n");
+       p += sprintf(p,
+               "DMA enabled:      %s              %s               %s              %s\n",
+               (c0&0x20) ? "Yes" : "No ",
+               (c0&0x40) ? "Yes" : "No ",
+               (c1&0x20) ? "Yes" : "No ",
+               (c1&0x40) ? "Yes" : "No " );
+
+       pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+       q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
+       if (rev < 0xc1) {
+               if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+                       p += sprintf(p, q, 8, 8, 8, 8);
+               } else {
+                       p += sprintf(p, q,
+                               (reg5xh & 0x03) + 12,
+                               ((reg5xh & 0x30)>>4) + 12,
+                               (reg5yh & 0x03) + 12,
+                               ((reg5yh & 0x30)>>4) + 12 );
+               }
+       } else {
+               p += sprintf(p, q,
+                       (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4,
+                       (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4,
+                       (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4,
+                       (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4 );
+       }
+
+#if 0
+       p += sprintf(p, 
+               "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
+               (reg5xh & 0x03) + 12,
+               ((reg5xh & 0x30)>>4) + 12,
+               (reg5yh & 0x03) + 12,
+               ((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+       p += sprintf(p,
+               "FIFO mode:        %s         %s          %s         %s\n",
+               fifo[((reg5xh & 0x0c) >> 2)],
+               fifo[((reg5xh & 0xc0) >> 6)],
+               fifo[((reg5yh & 0x0c) >> 2)],
+               fifo[((reg5yh & 0xc0) >> 6)] );
+
+       pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+       pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+       pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+       p += sprintf(p,/*
+               "------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
+               "Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
+               "Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
+               (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+               (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+               (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+               (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+               (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+               (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+               (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+               (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+       p += sprintf(p,
+               "-----------------------------------UDMA Timings--------------------------------\n\n");
+
+       pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+       pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+       p += sprintf(p,
+               "UDMA:             %s               %s                %s               %s\n"
+               "UDMA timings:     %s             %s              %s             %s\n\n",
+               (reg5xh & 0x08) ? "OK" : "No",
+               (reg5xh & 0x80) ? "OK" : "No",
+               (reg5yh & 0x08) ? "OK" : "No",
+               (reg5yh & 0x80) ? "OK" : "No",
+               udmaT[(reg5xh & 0x07)],
+               udmaT[(reg5xh & 0x70) >> 4],
+               udmaT[reg5yh & 0x07],
+               udmaT[(reg5yh & 0x70) >> 4] );
+
+       return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
diff --git a/drivers/block/buddha.c b/drivers/block/buddha.c
new file mode 100644 (file)
index 0000000..8086dac
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver
+ *
+ *     Copyright (C) 1997 by Geert Uytterhoeven
+ *
+ *  This driver was written by based on the specifications in README.buddha.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  TODO:
+ *    - test it :-)
+ *    - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  The Buddha has 2 IDE interfaces, the Catweasel has 3
+     */
+
+#define BUDDHA_NUM_HWIFS       2
+#define CATWEASEL_NUM_HWIFS    3
+
+
+    /*
+     *  Bases of the IDE interfaces (relative to the board address)
+     */
+
+#define BUDDHA_BASE1   0x800
+#define BUDDHA_BASE2   0xa00
+#define BUDDHA_BASE3   0xc00
+
+static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = {
+    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define BUDDHA_DATA    0x00
+#define BUDDHA_ERROR   0x06            /* see err-bits */
+#define BUDDHA_NSECTOR 0x0a            /* nr of sectors to read/write */
+#define BUDDHA_SECTOR  0x0e            /* starting sector */
+#define BUDDHA_LCYL    0x12            /* starting cylinder */
+#define BUDDHA_HCYL    0x16            /* high byte of starting cyl */
+#define BUDDHA_SELECT  0x1a            /* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS  0x1e            /* see status-bits */
+#define BUDDHA_CONTROL 0x11a
+
+static int buddha_offsets[IDE_NR_PORTS] = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL
+};
+
+
+    /*
+     *  Other registers
+     */
+
+#define BUDDHA_IRQ1    0xf00           /* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2    0xf40           /* interrupt */
+#define BUDDHA_IRQ3    0xf80
+
+static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = {
+    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+#define BUDDHA_IRQ_MR  0xfc0           /* master interrupt enable */
+
+
+    /*
+     *  Board information
+     */
+
+static u_long buddha_board = 0;
+static int buddha_num_hwifs = -1;
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+       return 0;
+    return 1;
+}
+
+
+    /*
+     *  Any Buddha or Catweasel boards present?
+     */
+
+static int find_buddha(void)
+{
+    u_int key;
+    const struct ConfigDev *cd;
+
+    buddha_num_hwifs = 0;
+    if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, 0, 0)))
+       buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+    else if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, 0,
+                              0)))
+       buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+    if (key) {
+       cd = zorro_get_board(key);
+       buddha_board = (u_long)cd->cd_BoardAddr;
+       if (buddha_board) {
+           buddha_board = ZTWO_VADDR(buddha_board);
+           /* write to BUDDHA_IRQ_MR to enable the board IRQ */
+           *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0;
+           zorro_config_board(key, 0);
+       }
+    }
+    return buddha_num_hwifs;
+}
+
+
+    /*
+     *  Probe for a Buddha or Catweasel IDE interface
+     *  We support only _one_ of them, no multiple boards!
+     */
+
+void buddha_init(void)
+{
+    hw_regs_t hw;
+    int i, index;
+
+    if (buddha_num_hwifs < 0 && !find_buddha())
+       return;
+
+    for (i = 0; i < buddha_num_hwifs; i++) {
+       ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
+                       buddha_offsets, 0,
+                       (ide_ioreg_t)(buddha_board+buddha_irqports[i]),
+                       buddha_ack_intr, IRQ_AMIGA_PORTS);
+       index = ide_register_hw(&hw, NULL);
+       if (index != -1)
+           printk("ide%d: %s IDE interface\n", index,
+                  buddha_num_hwifs == BUDDHA_NUM_HWIFS ? "Buddha" :
+                                                         "Catweasel");
+    }
+}
index 9982493701c12d1b4f13d63173af419b9614de13..ee6d7c9cc96bd74b092ce2e2908580709db4b9fd 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
index 57b5931319ffbd88f1524ab9a51b1e51716a350f..de0844a874ccf97b0387fd84d7f7320b25193210 100644 (file)
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
 
 static int cmd646_config_drive_for_dma(ide_drive_t *drive)
 {
@@ -43,14 +45,14 @@ static int cmd646_config_drive_for_dma(ide_drive_t *drive)
 }
 
 /* This is fun.  -DaveM */
-#define IDE_SETXFER            0x03
-#define IDE_SETFEATURE         0xef
-#define IDE_DMA2_ENABLE                0x22
-#define IDE_DMA1_ENABLE                0x21
-#define IDE_DMA0_ENABLE                0x20
-#define IDE_UDMA2_ENABLE       0x42
-#define IDE_UDMA1_ENABLE       0x41
-#define IDE_UDMA0_ENABLE       0x40
+#define IDE_SETXFER            SETFEATURES_XFER
+#define IDE_SETFEATURE         WIN_SETFEATURES
+#define IDE_DMA2_ENABLE                XFER_MW_DMA_2
+#define IDE_DMA1_ENABLE                XFER_MW_DMA_1
+#define IDE_DMA0_ENABLE                XFER_MW_DMA_0
+#define IDE_UDMA2_ENABLE       XFER_UDMA_2
+#define IDE_UDMA1_ENABLE       XFER_UDMA_1
+#define IDE_UDMA0_ENABLE       XFER_UDMA_0
 
 static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
 {
@@ -212,10 +214,36 @@ static int cmd646_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
        return ide_dmaproc(func, drive);
 }
 
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+static int cmd646_1_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       unsigned long dma_base = hwif->dma_base;
+       byte dma_stat;
+
+       if (func == ide_dma_end) {
+               drive->waiting_for_dma = 0;
+               dma_stat = inb(dma_base+2);             /* get DMA status */
+               outb(inb(dma_base)&~1, dma_base);       /* stop DMA */
+               outb(dma_stat|6, dma_base+2);   /* clear the INTR & ERROR bits */
+               return (dma_stat & 7) != 4;     /* verify good DMA status */
+       }
+
+       /* Other cases are done by generic IDE-DMA code. */
+       return cmd646_dmaproc(func, drive);
+}
+
 __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
 {
        struct pci_dev *dev = hwif->pci_dev;
        unsigned char mrdmode;
+       unsigned int class_rev;
+
+       pci_read_config_dword(hwif->pci_dev, PCI_CLASS_REVISION, &class_rev);
+       class_rev &= 0xff;
 
        hwif->chipset = ide_cmd646;
 
@@ -247,5 +275,9 @@ __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
        (void) pci_write_config_byte(dev, 0x58, 0x3f);
        (void) pci_write_config_byte(dev, 0x5b, 0x3f);
 
-       hwif->dmaproc = &cmd646_dmaproc;
+       if (class_rev == 0x01) {
+               hwif->dmaproc = &cmd646_1_dmaproc;
+       } else {
+               hwif->dmaproc = &cmd646_dmaproc;
+       }
 }
diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c
new file mode 100644 (file)
index 0000000..59c38be
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * linux/drivers/block/cy82c693.c      Version 0.33    Jan. 23, 1999
+ *
+ *  Copyright (C) 1998, 1999 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998 Andre Hedrick, Integrater
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writting the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support. 
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ *   a large and fast disk - the results look great, so I'd say the
+ *   driver is working fine :-)
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
+ *   for optimizations and bug fixing, so fell free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ *   (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ *   problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ *
+ * History:
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ *                       removed DMA clock speed setting by default
+ *                       added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ *                       added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+/* the current version */
+#define CY82_VERSION   "CY82C693U driver v0.33 99-01-23 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ *     The following are used to debug the driver.
+ */
+#define        CY82C693_DEBUG_LOGS     0
+#define        CY82C693_DEBUG_INFO     0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ * note: the value for busmaster timeout is tricky and i got it by trial and error !
+ *       using a to low value will cause DMA timeouts and drop IDE performance
+ *       using a to high value will cause audio playback to scatter
+ *       if you know a better value or how to calc it, please let me know 
+ */
+#define BUSMASTER_TIMEOUT      0x50    /* twice the value written in cy82c693ub datasheet */
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG                0x04
+#define CY82_IDE_ADDRSETUP     0x48
+#define CY82_IDE_MASTER_IOR    0x4C    
+#define CY82_IDE_MASTER_IOW    0x4D    
+#define CY82_IDE_SLAVE_IOR     0x4E    
+#define CY82_IDE_SLAVE_IOW     0x4F
+#define CY82_IDE_MASTER_8BIT   0x50    
+#define CY82_IDE_SLAVE_8BIT    0x51    
+
+#define CY82_INDEX_PORT                0x22
+#define CY82_DATA_PORT         0x23
+
+#define CY82_INDEX_CTRLREG1    0x01
+#define CY82_INDEX_CHANNEL0    0x30
+#define CY82_INDEX_CHANNEL1    0x31
+#define CY82_INDEX_TIMEOUT     0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO       4
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED 25
+#define CY82C963_MAX_BUS_SPEED 33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+        byte   address_time;           /* Address setup (clocks) */
+       byte    time_16r;               /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+       byte    time_16w;               /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+       byte    time_8;                 /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk (int time, int bus_speed)
+{
+       int clocks;
+
+       clocks = (time*bus_speed+999)/1000 -1;
+
+       if (clocks < 0)
+               clocks = 0;
+
+       if (clocks > 0x0F)
+               clocks = 0x0F;
+
+       return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ *       for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */ 
+static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
+{
+       int clk1, clk2;
+       int bus_speed;
+
+       bus_speed = ide_system_bus_speed();     /* get speed of PCI bus */
+       /* we don't check against CY82C693's min and max speed,
+        * so you can play with the idebus=xx parameter
+        */
+
+       if (pio > CY82C693_MAX_PIO)
+               pio = CY82C693_MAX_PIO;
+
+       /* let's calc the address setup time clocks */
+       p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+       /* let's calc the active and recovery time clocks */
+       clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+       /* calc recovery timing */
+       clk2 =  ide_pio_timings[pio].cycle_time -
+               ide_pio_timings[pio].active_time -
+               ide_pio_timings[pio].setup_time;
+
+       clk2 = calc_clk(clk2, bus_speed);
+
+       clk1 = (clk1<<4)|clk2;  /* combine active and recovery clocks */
+
+       /* note: we use the same values for 16bit IOR and IOW
+         *     those are all the same, since I don't have other
+        *      timings than those from ide_modes.h
+        */
+
+       p_pclk->time_16r = (byte)clk1;
+       p_pclk->time_16w = (byte)clk1;
+
+       /* what are good values for 8bit ?? */
+       p_pclk->time_8 = (byte)clk1;
+}
+
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+        byte index;
+       byte data;
+
+        if (mode>2)    /* make sure we set a valid mode */
+               mode = 2;
+                          
+       if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+               mode = drive->id->tDMA;
+       
+        index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+               /* for debug let's show the previous values */
+
+       OUT_BYTE(index, CY82_INDEX_PORT);
+       data = IN_BYTE(CY82_DATA_PORT);
+
+       printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+       data = (byte)mode|(byte)(single<<2);
+
+       OUT_BYTE(index, CY82_INDEX_PORT);
+       OUT_BYTE(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+       printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+       /* 
+        * note: below we set the value for Bus Master IDE TimeOut Register
+        * I'm not absolutly sure what this does, but it solved my problem
+        * with IDE DMA and sound, so I now can play sound and work with
+        * my IDE driver at the same time :-)
+        *
+        * If you know the correct (best) value for this register please
+        * let me know - ASK
+        */
+
+       data = BUSMASTER_TIMEOUT;
+       OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+       OUT_BYTE(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO        
+       printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/* 
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+       /*
+        * if the function is dma on, set dma mode for drive everything
+        * else is done by the defaul func
+        */
+       if (func == ide_dma_on) {
+               struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+               printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+               if (id != NULL) {               
+                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
+                       if (id->field_valid & 2) {       /* regular DMA */
+                              int mmode, smode;
+
+                              mmode = id->dma_mword & (id->dma_mword >> 8);
+                              smode = id->dma_1word & (id->dma_1word >> 8);
+                                             
+                              if (mmode != 0)
+                                    cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
+                              else if (smode != 0)
+                                    cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
+                       }
+               }
+       }
+        return ide_dmaproc(func, drive);
+}
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = hwif->pci_dev;
+       pio_clocks_t pclk;
+       unsigned int addrCtrl;
+
+       /* select primary or secondary channel */
+       if (hwif->index > 0)  /* drive is on the secondary channel */
+               dev = dev->next;
+
+#if CY82C693_DEBUG_LOGS
+       /* for debug let's show the register values */
+       
+               if (drive->select.b.unit == 0) {
+               /*
+                * get master drive registers                   
+                * address setup control register
+                * is 32 bit !!!
+                */ 
+               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+               addrCtrl &= 0x0F;
+
+               /* now let's get the remaining registers */
+               pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+               pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+               pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+       } else {
+               /*
+                * set slave drive registers
+                * address setup control register
+                * is 32 bit !!!
+                */ 
+               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+               addrCtrl &= 0xF0;
+               addrCtrl >>= 4;
+
+               /* now let's get the remaining registers */
+               pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+               pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+               pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+       }
+
+       printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+        /* first let's calc the pio modes */
+       pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+       printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+        compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
+
+       /* now let's write  the clocks registers */
+       if (drive->select.b.unit == 0) {
+               /*
+                * set master drive
+                * address setup control register
+                * is 32 bit !!!
+                */ 
+               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+               
+               addrCtrl &= (~0xF);
+               addrCtrl |= (unsigned int)pclk.address_time;
+               pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+               /* now let's set the remaining registers */
+               pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+               pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+               pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+               
+               addrCtrl &= 0xF;
+       } else {
+               /*
+                * set slave drive
+                * address setup control register
+                * is 32 bit !!!
+                */ 
+               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+               addrCtrl &= (~0xF0);
+               addrCtrl |= ((unsigned int)pclk.address_time<<4);
+               pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+               /* now let's set the remaining registers */
+               pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+               pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+               pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+               addrCtrl >>= 4;
+               addrCtrl &= 0xF;
+       }       
+
+#if CY82C693_DEBUG_INFO
+       printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+static void init_cy82c693_chip (struct pci_dev *dev)
+{
+       static int initDone = 0;
+#ifdef CY82C693_SETDMA_CLOCK
+        byte data;
+#endif /* CY82C693_SETDMA_CLOCK */ 
+
+       if (initDone != 0)      /* only perform setup once */
+               return;
+       initDone = 1;
+
+       /* write info about this verion of the driver */
+       printk (KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+       /* okay let's set the DMA clock speed */
+        
+        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        data = IN_BYTE(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+       printk (KERN_INFO "CY82U693: Peripheral Configuration Register: 0x%X\n", data);
+#endif /* CY82C693_DEBUG_INFO */
+
+        /*
+        * for some reason sometimes the DMA controller
+        * speed is set to ATCLK/2 ???? - we fix this here
+        * 
+        * note: i don't know what causes this strange behaviour,
+        *       but even changing the dma speed doesn't solve it :-(
+        *       the ide performance is still only half the normal speed 
+        * 
+        *       if anybody knows what goes wrong with my machine, please
+        *       let me know - ASK
+         */
+
+       data |= 0x03;
+
+        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        OUT_BYTE(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+       printk (KERN_INFO "CY82U693: New Peripheral Configuration Register: 0x%X\n", data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */ 
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+__initfunc(void ide_init_cy82c693(ide_hwif_t *hwif))
+{
+       hwif->chipset = ide_cy82c693;
+       hwif->dmaproc = &cy82c693_dmaproc;
+       hwif->tuneproc = &cy82c693_tune_drive;
+
+       init_cy82c693_chip(hwif->pci_dev);
+}
+
index b656a0bd27c32d0a66f8af16a2a16e9b26c3daee..d805dec759d55cc536dcbce2d9dfdfee52d67b20 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
diff --git a/drivers/block/falconide.c b/drivers/block/falconide.c
new file mode 100644 (file)
index 0000000..321569e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  linux/drivers/block/falconide.c -- Atari Falcon IDE Driver
+ *
+ *     Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+
+    /*
+     *  Base of the IDE interface
+     */
+
+#define ATA_HD_BASE    0xfff00000
+
+    /*
+     *  Offsets from the above base
+     */
+
+#define ATA_HD_DATA    0x00
+#define ATA_HD_ERROR   0x05            /* see err-bits */
+#define ATA_HD_NSECTOR 0x09            /* nr of sectors to read/write */
+#define ATA_HD_SECTOR  0x0d            /* starting sector */
+#define ATA_HD_LCYL    0x11            /* starting cylinder */
+#define ATA_HD_HCYL    0x15            /* high byte of starting cyl */
+#define ATA_HD_SELECT  0x19            /* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS  0x1d            /* see status-bits */
+#define ATA_HD_CONTROL 0x39
+
+static int falconide_offsets[IDE_NR_PORTS] = {
+    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+    /*
+     *  Probe for a Falcon IDE interface
+     */
+
+void falconide_init(void)
+{
+    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+       hw_regs_t hw;
+       int index;
+
+       ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
+                       0, 0, NULL, IRQ_MFP_IDE);
+       index = ide_register_hw(&hw, NULL);
+
+       if (index != -1)
+           printk("ide%d: Falcon IDE interface\n", index);
+    }
+}
diff --git a/drivers/block/gayle.c b/drivers/block/gayle.c
new file mode 100644 (file)
index 0000000..920f2ee
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver
+ *
+ *     Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define GAYLE_BASE_4000        0xdd2020        /* A4000/A4000T */
+#define GAYLE_BASE_1200        0xda0000        /* A1200/A600 */
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define GAYLE_DATA     0x00
+#define GAYLE_ERROR    0x06            /* see err-bits */
+#define GAYLE_NSECTOR  0x0a            /* nr of sectors to read/write */
+#define GAYLE_SECTOR   0x0e            /* starting sector */
+#define GAYLE_LCYL     0x12            /* starting cylinder */
+#define GAYLE_HCYL     0x16            /* high byte of starting cyl */
+#define GAYLE_SELECT   0x1a            /* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS   0x1e            /* see status-bits */
+#define GAYLE_CONTROL  0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] = {
+    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+    /*
+     *  These are at different offsets from the base
+     */
+
+#define GAYLE_IRQ_4000 0xdd3020        /* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200 0xda9000        /* interrupt */
+
+
+    /*
+     *  Offset of the secondary port for IDE doublers
+     *  Note that GAYLE_CONTROL is NOT available then!
+     */
+
+#define GAYLE_NEXT_PORT        0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS                1
+#define GAYLE_NUM_PROBE_HWIFS  GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG  1
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS                2
+#define GAYLE_NUM_PROBE_HWIFS  (ide_doubler ? GAYLE_NUM_HWIFS : \
+                                              GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG  (!ide_doubler)
+int ide_doubler = 0;   /* support IDE doublers? */
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+       return 0;
+    return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+       return 0;
+    (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    outb(0x7c | (ch & 0x03), hwif->io_ports[IDE_IRQ_OFFSET]);
+    return 1;
+}
+
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
+
+void gayle_init(void)
+{
+    int a4000, i;
+
+    if (!MACH_IS_AMIGA)
+       return;
+
+    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
+       return;
+
+    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+       ide_ioreg_t base, ctrlport, irqport;
+       ide_ack_intr_t *ack_intr;
+       hw_regs_t hw;
+       int index;
+
+       if (a4000) {
+           base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000);
+           irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+           ack_intr = gayle_ack_intr_a4000;
+       } else {
+           base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200);
+           irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+           ack_intr = gayle_ack_intr_a1200;
+       }
+
+       if (GAYLE_HAS_CONTROL_REG)
+           ctrlport = base + GAYLE_CONTROL;
+       else
+           ctrlport = 0;
+
+       base += i*GAYLE_NEXT_PORT;
+
+       ide_setup_ports(&hw, base, gayle_offsets,
+                       ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
+
+       index = ide_register_hw(&hw, NULL);
+       if (index != -1) {
+           switch (i) {
+               case 0:
+                   printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+                          a4000 ? 4000 : 1200);
+                   break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+               case 1:
+                   printk("ide%d: IDE doubler\n", index);
+                   break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+           }
+       }
+#if 1 /* TESTING */
+       if (i == 1) {
+           volatile u_short *addr = (u_short *)base;
+           u_short data;
+           printk("+++ Probing for IDE doubler... ");
+           *addr = 0xffff;
+           data = *addr;
+           printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
+       }
+#endif /* TESTING */
+    }
+}
index 3169a9bfda72585274e53ee8351d6b99f1473bd8..761a3eb0c88543078eb5e483de769da82adac7f4 100644 (file)
@@ -83,6 +83,10 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
         * This requires special handling here.
         */
        switch (hd->major) {
+               case IDE7_MAJOR:
+                       unit += 2;
+               case IDE6_MAJOR:
+                       unit += 2;
                case IDE5_MAJOR:
                        unit += 2;
                case IDE4_MAJOR:
diff --git a/drivers/block/hpt343.c b/drivers/block/hpt343.c
new file mode 100644 (file)
index 0000000..820e905
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * linux/drivers/block/hpt343.c                Version 0.23    May 12, 1999
+ *
+ * Copyright (C) 1998-99       Andre Hedrick
+ *                                     (hedrick@astro.dyer.vanderbilt.edu)
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * drive_number
+ *     = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *     = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/config.h>      /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)      ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define HPT343_DEBUG_DRIVE_INFO                0
+#define HPT343_DISABLE_ALL_DMAING      0
+#define HPT343_DMA_DISK_ONLY           0
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+static void hpt343_clear_chipset (ide_drive_t *drive)
+{
+       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       unsigned int reg1       = 0, tmp1 = 0;
+       unsigned int reg2       = 0, tmp2 = 0;
+
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+       tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+       tmp2 = ((0x00 << drive_number) | reg2);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+}
+
+static int hpt343_tune_chipset (ide_drive_t *drive, byte speed)
+{
+       int                     err;
+       byte                    hi_speed, lo_speed;
+       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       unsigned int reg1       = 0, tmp1 = 0;
+       unsigned int reg2       = 0, tmp2 = 0;
+
+       SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+       if (hi_speed & 7) {
+               hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+       } else {
+               lo_speed <<= 5;
+               lo_speed >>= 5;
+       }
+
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+       tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+       tmp2 = ((hi_speed << drive_number) | reg2);
+       err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+               " (0x%02x 0x%02x) 0x%04x\n",
+               drive->name, ide_xfer_verbose(speed),
+               drive_number, reg1, tmp1, reg2, tmp2,
+               hi_speed, lo_speed, err);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+       return(err);
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       struct hd_driveid *id   = drive->id;
+       byte speed              = 0x00;
+
+#if HPT343_DISABLE_ALL_DMAING
+       return ((int) ide_dma_off);
+#elif HPT343_DMA_DISK_ONLY
+       if (drive->media != ide_disk)
+               return ((int) ide_dma_off_quietly);
+#endif /* HPT343_DISABLE_ALL_DMAING */
+
+       if (id->dma_ultra & 0x0004) {
+               if (!((id->dma_ultra >> 8) & 4)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0404;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_2;
+       } else if (id->dma_ultra & 0x0002) {
+               if (!((id->dma_ultra >> 8) & 2)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0202;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_1;
+       } else if (id->dma_ultra & 0x0001) {
+               if (!((id->dma_ultra >> 8) & 1)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0101;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               if (!((id->dma_mword >> 8) & 4)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0404;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               if (!((id->dma_mword >> 8) & 2)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0202;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_mword & 0x0001) {
+               if (!((id->dma_mword >> 8) & 1)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0101;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_0;
+       } else if (id->dma_1word & 0x0004) {
+               if (!((id->dma_1word >> 8) & 4)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0404;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_2;
+       } else if (id->dma_1word & 0x0002) {
+               if (!((id->dma_1word >> 8) & 2)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0202;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_1;
+       } else if (id->dma_1word & 0x0001) {
+               if (!((id->dma_1word >> 8) & 1)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0101;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_0;
+        } else {
+               return ((int) ide_dma_off_quietly);
+       }
+
+       (void) hpt343_tune_chipset(drive, speed);
+
+       return ((int)   ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+       unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+       unsigned short xfer_pio = drive->id->eide_pio_modes;
+
+       byte                    timing, speed, pio;
+
+       pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+       if (xfer_pio> 4)
+               xfer_pio = 0;
+
+       if (drive->id->eide_pio_iordy > 0) {
+               for (xfer_pio = 5;
+                       xfer_pio>0 &&
+                       drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+                       xfer_pio--);
+       } else {
+               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+                          (drive->id->eide_pio_modes & 2) ? 0x04 :
+                          (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+       }
+
+       timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+       switch(timing) {
+               case 4: speed = XFER_PIO_4;break;
+               case 3: speed = XFER_PIO_3;break;
+               case 2: speed = XFER_PIO_2;break;
+               case 1: speed = XFER_PIO_1;break;
+               default:
+                       speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+                       break;
+       }
+
+       (void) hpt343_tune_chipset(drive, speed);
+}
+
+#if 0
+static void hpt343_tune_drive (ide_drive_t *drive, byte pio)
+{
+}
+#endif
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
+
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       dma_func = ide_dma_off;
+                       goto fast_ata_pio;
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x0007) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+                       }
+               } else if (id->field_valid & 2) {
+try_dma_modes:
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+                               dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+               } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+                       if (id->eide_dma_time > 150) {
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+                       dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+                       goto fast_ata_pio;
+               }
+       } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+no_dma_set:
+
+               config_chipset_for_pio(drive);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * hpt343_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ *
+ * This is specific to the HPT343 UDMA bios-less chipset
+ * and HPT345 UDMA bios chipset (stamped HPT363)
+ * by HighPoint|Triones Technologies, Inc.
+ */
+
+int hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+               case ide_dma_check:
+                       hpt343_clear_chipset(drive);
+                       return config_drive_xfer_rate(drive);
+#if 0
+               case ide_dma_off:
+               case ide_dma_off_quietly:
+               case ide_dma_on:
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
+               case ide_dma_read:
+               case ide_dma_write:
+               case ide_dma_begin:
+               case ide_dma_end:
+               case ide_dma_test_irq:
+#endif
+               default:
+                       break;
+       }
+       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define        HPT343_PCI_INIT_REG             0x80
+
+__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name))
+{
+       int i;
+       unsigned short cmd;
+       unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+#if 0
+       unsigned char misc10 = inb(hpt343IoBase + 0x0010);
+       unsigned char misc11 = inb(hpt343IoBase + 0x0011);
+#endif
+
+       pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x00);
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+
+       dev->base_address[0] = (hpt343IoBase + 0x20);
+       dev->base_address[1] = (hpt343IoBase + 0x34);
+       dev->base_address[2] = (hpt343IoBase + 0x28);
+       dev->base_address[3] = (hpt343IoBase + 0x3c);
+
+       for(i=0; i<4; i++)
+               dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+
+       /*
+        * Since 20-23 can be assigned and are R/W, we correct them.
+        */
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]);
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+#if 0
+       outb(misc10|0x78, (hpt343IoBase + 0x0010));
+       outb(misc11, (hpt343IoBase + 0x0011));
+#endif
+
+#ifdef DEBUG
+       printk("%s: 0x%02x 0x%02x\n",
+               (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name,
+               inb(hpt343IoBase + 0x0010),
+               inb(hpt343IoBase + 0x0011));
+#endif
+
+       pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x80);
+       if (cmd & PCI_COMMAND_MEMORY) {
+               if (dev->rom_address) {
+                       pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+                       printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
+               }
+       } else {
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+       }
+       return dev->irq;
+}
+
+__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif))
+{
+       if (hwif->dma_base) {
+               unsigned short pcicmd = 0;
+
+               pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+               hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+               hwif->dmaproc = &hpt343_dmaproc;
+       }
+}
index a3e1229bca653ef0f4d863a697a89cec2bb58f48..d9fb885c278cd6c1ad91aa36eb8faeaf0a996f7b 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
index 7e07eda65966295148b7daa33aeed8beeef3c72e..c1d050c46f48d50b5e0567ce07fa7e6039f0db37 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
+
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include "ide.h"
 #include "ide-cd.h"
 
 /****************************************************************************
@@ -670,7 +671,8 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
 
        OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
        OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-       OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+       if (IDE_CONTROL_REG)
+               OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
  
        if (info->dma)
                (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
@@ -2940,7 +2942,19 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
         else   
                printk (" drive");
 
-       printk (", %dkB Cache\n", ntohs(buf.cap.buffer_size));
+       printk (", %dkB Cache", ntohs(buf.cap.buffer_size));
+
+       if (drive->using_dma) {
+               if ((drive->id->field_valid & 4) &&
+                   (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) {
+                       printk(", UDMA");       /* UDMA BIOS-enabled! */
+               } else if (drive->id->field_valid & 4) {
+                       printk(", (U)DMA");     /* Can be BIOS-enabled! */
+               } else {
+                       printk(", DMA");
+               }
+       }
+       printk("\n");
 
        return nslots;
 }
@@ -2956,6 +2970,53 @@ static void ide_cdrom_add_settings(ide_drive_t *drive)
        ide_add_setting(drive,  "dsc_overlap",          SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
 }
 
+#ifdef CONFIG_IDECD_SLOTS
+static void ide_cdrom_slot_check (ide_drive_t *drive, int nslots)
+{
+       tracktype tracks;
+       struct cdrom_info *info = drive->driver_data;
+       struct cdrom_device_info *devinfo = &info->devinfo;
+       int slot_count = 0, drive_stat = 0, tmp;
+
+       for (slot_count=0;slot_count<nslots;slot_count++) {
+               (void) ide_cdrom_select_disc(devinfo, slot_count);
+               printk("     CD Slot %d ", slot_count+1);
+
+               drive_stat = ide_cdrom_drive_status(devinfo, slot_count);
+               if (drive_stat<0) {
+                       continue;
+               } else switch(drive_stat) {
+                       case CDS_DISC_OK:
+                               /* use routine in Uniform CD-ROM driver */
+                               cdrom_count_tracks(devinfo, &tracks);
+                               tmp = tracks.audio + tracks.data +
+                                       tracks.cdi + tracks.xa;
+                               printk(": Disc has %d track%s: ", tmp,
+                                       (tmp == 1)? "" : "s");
+                               printk("%d=data %d=audio %d=Cd-I %d=XA\n",
+                                       tracks.data, tracks.audio,
+                                       tracks.cdi, tracks.xa);
+                               break;
+                       case CDS_NO_DISC:
+                               printk("Empty slot.\n");
+                               break;
+                       case CDS_TRAY_OPEN:
+                               printk("CD-ROM tray open.\n");
+                               break;
+                       case CDS_DRIVE_NOT_READY:
+                               printk("CD-ROM drive not ready.\n");
+                               break;
+                       case CDS_NO_INFO:
+                               printk("No Information available.\n");
+                               break;
+                       default:
+                               printk("This Should not happen!\n");
+                               break;
+               }
+       }
+}
+#endif /* CONFIG_IDECD_SLOTS */
+
 static
 int ide_cdrom_setup (ide_drive_t *drive)
 {
@@ -3083,6 +3144,11 @@ int ide_cdrom_setup (ide_drive_t *drive)
                return 1;
        }
        ide_cdrom_add_settings(drive);
+#ifdef CONFIG_IDECD_SLOTS
+       if (CDROM_CONFIG_FLAGS (drive)->is_changer) {
+               ide_cdrom_slot_check(drive, nslots);
+       }
+#endif /* CONFIG_IDECD_SLOTS */
        return 0;
 }
 
index 14ad6269ec2f76336a0db3c06489f2b24ebddf24..955be4c6b18226088b6cd1c5217f5bfe00b90eca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-disk.c     Version 1.08  Dec   10, 1998
+ *  linux/drivers/block/ide-disk.c     Version 1.09  April 23, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
  *                     process of adding new ATA4 compliance.
  *                     fixed problems in allowing fdisk to see
  *                     the entire disk.
+ * Version 1.09                added increment of rq->sector in ide_multwrite
+ *                     added UDMA 3/4 reporting
  */
 
-#define IDEDISK_VERSION        "1.08"
+#define IDEDISK_VERSION        "1.09"
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
+#define _IDE_DISK_C            /* Tell linux/hdsmart.h it's really us */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include "ide.h"
-
 static void idedisk_bswap_data (void *buffer, int wcount)
 {
        u16 *p = buffer;
@@ -101,6 +104,15 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
                id->cyls = lba_sects / (16 * 63); /* correct cyls */
                return 1;       /* lba_capacity is our only option */
        }
+       /*
+        * ... and at least one TLA VBC has POS instead of brain and can't
+        * tell 16 from 15.
+        */
+       if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) &&
+           (id->heads == 15) && (id->sectors == 63)) {
+               id->cyls = lba_sects / (15 * 63); /* correct cyls */
+               return 1;       /* lba_capacity is our only option */
+       }
        /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
        if ((lba_sects - chs_sects) < _10_percent) {
                return 1;       /* lba_capacity is good */
@@ -220,6 +232,9 @@ void ide_multwrite (ide_drive_t *drive, unsigned int mcount)
                printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n",
                        drive->name, rq->sector, (unsigned long) rq->buffer,
                        nsect, rq->nr_sectors - nsect);
+#endif
+#ifdef CONFIG_BLK_DEV_PDC4030
+               rq->sector += nsect;
 #endif
                if ((rq->nr_sectors -= nsect) <= 0)
                        break;
@@ -279,7 +294,11 @@ static void set_multmode_intr (ide_drive_t *drive)
 {
        byte stat = GET_STAT();
 
+#if 0
+       if (OK_STAT(stat,READY_STAT,BAD_STAT) || drive->mult_req == 0) {
+#else
        if (OK_STAT(stat,READY_STAT,BAD_STAT)) {
+#endif
                drive->mult_count = drive->mult_req;
        } else {
                drive->mult_req = drive->mult_count = 0;
@@ -322,14 +341,21 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl
        int use_pdc4030_io = 0;
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
-       OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+       if (IDE_CONTROL_REG)
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
        OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
 #ifdef CONFIG_BLK_DEV_PDC4030
+#ifdef CONFIG_BLK_DEV_PDC4030_TESTING
+       if (IS_PDC4030_DRIVE) {
+               use_pdc4030_io = 1;
+       }
+#else
        if (IS_PDC4030_DRIVE) {
                if (hwif->channel != 0 || rq->cmd == READ) {
                        use_pdc4030_io = 1;
                }
        }
+#endif /* CONFIG_BLK_DEV_PDC4030_TESTING */
        if (drive->select.b.lba || use_pdc4030_io) {
 #else /* !CONFIG_BLK_DEV_PDC4030 */
        if (drive->select.b.lba) {
@@ -760,9 +786,12 @@ static void idedisk_setup (ide_drive_t *drive)
                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
        if (drive->using_dma) {
-               if ((id->field_valid & 4) &&
-                   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-                       printk(", UDMA");       /* UDMA BIOS-enabled! */
+               if  ((id->field_valid & 4) && (id->word93 & 0x2000) &&
+                    (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
+                       printk(", UDMA(66)");   /* UDMA BIOS-enabled! */
+               } else if ((id->field_valid & 4) &&
+                          (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+                       printk(", UDMA(33)");   /* UDMA BIOS-enabled! */
                } else if (id->field_valid & 4) {
                        printk(", (U)DMA");     /* Can be BIOS-enabled! */
                } else {
@@ -786,17 +815,17 @@ static void idedisk_setup (ide_drive_t *drive)
 
        drive->mult_count = 0;
        if (id->max_multsect) {
-#if 1  /* original, pre IDE-NFG, per request of AC */
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+               id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+               id->multsect_valid = id->multsect ? 1 : 0;
+               drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+               drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else  /* original, pre IDE-NFG, per request of AC */
                drive->mult_req = INITIAL_MULT_COUNT;
                if (drive->mult_req > id->max_multsect)
                        drive->mult_req = id->max_multsect;
                if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
                        drive->special.b.set_multmode = 1;
-#else
-               id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
-               id->multsect_valid = id->multsect ? 1 : 0;
-               drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
-               drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
 #endif
        }
        drive->no_io_32bit = id->dword_io ? 1 : 0;
index 17f46f464f85ef818f965fd78cce0658756d0257..9f26ea6bc5b9f26d8aa1a495bf6243f2172694e8 100644 (file)
@@ -1,5 +1,12 @@
 /*
- *  linux/drivers/block/ide-dma.c      Version 4.08  December 31, 1997
+ *  linux/drivers/block/ide-dma.c      Version 4.09  April 23, 1999
+ *
+ *  Copyright (c) 1999  Andre Hedrick
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ *  Special Thanks to Mark for his Six years of work.
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -24,7 +31,7 @@
  *
  * Use "hdparm -i" to view modes supported by a given drive.
  *
- * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
+ * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
  * DMA support, but must be (re-)compiled against this kernel version or later.
  *
  * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "ide.h"
+#define IDE_DMA_NEW_LISTINGS           0
+
+#if IDE_DMA_NEW_LISTINGS
+struct drive_list_entry {
+       char * id_model;
+       char * id_firmware;
+};
+
+struct drive_list_entry drive_whitelist [] = {
+
+       { "Micropolis 2112A"    ,       "ALL"           },
+       { "CONNER CTMA 4000"    ,       "ALL"           },
+       { "CONNER CTT8000-A"    ,       "ALL"           },
+       { "ST34342A"            ,       "ALL"           },
+       { 0                     ,       0               }
+};
+
+struct drive_list_entry drive_blacklist [] = {
+
+       { "WDC AC11000H"        ,       "ALL"           },
+       { "WDC AC22100H"        ,       "ALL"           },
+       { "WDC AC32500H"        ,       "ALL"           },
+       { "WDC AC33100H"        ,       "ALL"           },
+       { "WDC AC31600H"        ,       "ALL"           },
+       { "WDC AC32100H"        ,       "24.09P07"      },
+       { "WDC AC23200L"        ,       "21.10N21"      },
+       { 0                     ,       0               }
+
+};
+
+int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+       for ( ; drive_table->id_model ; drive_table++)
+               if ((!strcmp(drive_table->id_model, id->model)) &&
+                   ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+                    (!strcmp(drive_table->id_firmware, "ALL"))))
+                       return 1;
+       return 0;
+}
+#else /* !IDE_DMA_NEW_LISTINGS */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -109,11 +156,14 @@ const char *good_dma_drives[] = {"Micropolis 2112A",
  */
 const char *bad_dma_drives[] = {"WDC AC11000H",
                                "WDC AC22100H",
+                               "WDC AC32100H",
                                "WDC AC32500H",
                                "WDC AC33100H",
                                "WDC AC31600H",
                                NULL};
 
+#endif /* IDE_DMA_NEW_LISTINGS */
+
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
  * to handle the biggest I/O request we are likely to see.  Since requests
@@ -164,11 +214,12 @@ void ide_dma_intr (ide_drive_t *drive)
  * Returns 0 if all went okay, returns 1 otherwise.
  * May also be invoked from trm290.c
  */
-int ide_build_dmatable (ide_drive_t *drive)
+int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
 {
        struct request *rq = HWGROUP(drive)->rq;
        struct buffer_head *bh = rq->bh;
        unsigned int size, addr, *table = (unsigned int *)HWIF(drive)->dmatable;
+       unsigned char *virt_addr;
 #ifdef CONFIG_BLK_DEV_TRM290
        unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
 #else
@@ -185,11 +236,13 @@ int ide_build_dmatable (ide_drive_t *drive)
                 * than two possibly non-adjacent physical 4kB pages.
                 */
                if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
-                       addr = virt_to_bus (rq->buffer);
+                       virt_addr = rq->buffer;
+                       addr = virt_to_bus (virt_addr);
                        size = rq->nr_sectors << 9;
                } else {
                        /* group sequential buffers into one large buffer */
-                       addr = virt_to_bus (bh->b_data);
+                       virt_addr = bh->b_data;
+                       addr = virt_to_bus (virt_addr);
                        size = bh->b_size;
                        while ((bh = bh->b_reqnext) != NULL) {
                                if ((addr + size) != virt_to_bus (bh->b_data))
@@ -206,6 +259,20 @@ int ide_build_dmatable (ide_drive_t *drive)
                        printk("%s: misaligned DMA buffer\n", drive->name);
                        return 0;
                }
+
+               /*
+                * Some CPUs without cache snooping need to invalidate/write
+                * back their caches before DMA transfers to guarantee correct
+                * data.        -- rmk
+                */
+               if (size) {
+                       if (func == ide_dma_read) {
+                               dma_cache_inv((unsigned int)virt_addr, size);
+                       } else {
+                               dma_cache_wback((unsigned int)virt_addr, size);
+                       }
+               }
+
                while (size) {
                        if (++count >= PRD_ENTRIES) {
                                printk("%s: DMA table too small\n", drive->name);
@@ -224,10 +291,17 @@ int ide_build_dmatable (ide_drive_t *drive)
                        }
                }
        } while (bh != NULL);
-       if (!count)
+       if (!count) {
                printk("%s: empty DMA table?\n", drive->name);
-       else if (!is_trm290_chipset)
-               *--table |= cpu_to_le32(0x80000000);    /* set End-Of-Table (EOT) bit */
+       } else {
+               if (!is_trm290_chipset)
+                       *--table |= cpu_to_le32(0x80000000);    /* set End-Of-Table (EOT) bit */
+               /*
+                * Some CPUs need to flush the DMA table to physical RAM
+                * before DMA can start.        -- rmk
+                */
+               dma_cache_wback((unsigned long)HWIF(drive)->dmatable, count * sizeof(unsigned int) * 2);
+       }
        return count;
 }
 
@@ -238,9 +312,22 @@ int ide_build_dmatable (ide_drive_t *drive)
  */
 int check_drive_lists (ide_drive_t *drive, int good_bad)
 {
-       const char **list;
        struct hd_driveid *id = drive->id;
 
+#if IDE_DMA_NEW_LISTINGS
+
+       if (good_bad) {
+               return in_drive_list(id, drive_whitelist);
+       } else {
+               int blacklist = in_drive_list(id, drive_blacklist);
+               if (blacklist)
+                       printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+               return(blacklist);
+       }
+#else /* !IDE_DMA_NEW_LISTINGS */
+
+       const char **list;
+
        if (good_bad) {
                /* Consult the list of known "good" drives */
                list = good_dma_drives;
@@ -259,6 +346,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
                        }
                }
        }
+#endif /* IDE_DMA_NEW_LISTINGS */
        return 0;
 }
 
@@ -269,18 +357,24 @@ static int config_drive_for_dma (ide_drive_t *drive)
 
        if (id && (id->capability & 1) && hwif->autodma) {
                /* Consult the list of known "bad" drives */
-               if (check_drive_lists(drive, BAD_DMA_DRIVE))
+               if (ide_dmaproc(ide_dma_bad_drive, drive))
                        return hwif->dmaproc(ide_dma_off, drive);
+#if 0
+               /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */
+               if ((id->field_valid & 4) && (id->word93 & 0x2000))
+                       if ((id->dma_ultra & (id->dma_ultra >> 11) & 3))
+                               return hwif->dmaproc(ide_dma_on, drive);
+#endif
                /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
                if (id->field_valid & 4)        /* UltraDMA */
-                       if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
+                       if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
                                return hwif->dmaproc(ide_dma_on, drive);
                /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
                if (id->field_valid & 2)        /* regular DMA */
                        if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
                                return hwif->dmaproc(ide_dma_on, drive);
                /* Consult the list of known "good" drives */
-               if (check_drive_lists(drive, GOOD_DMA_DRIVE))
+               if (ide_dmaproc(ide_dma_good_drive, drive))
                        return hwif->dmaproc(ide_dma_on, drive);
        }
        return hwif->dmaproc(ide_dma_off_quietly, drive);
@@ -321,7 +415,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                case ide_dma_read:
                        reading = 1 << 3;
                case ide_dma_write:
-                       if (!(count = ide_build_dmatable(drive)))
+                       if (!(count = ide_build_dmatable(drive, func)))
                                return 1;       /* try PIO instead of DMA */
                        outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */
                        outb(reading, dma_base);                        /* specify r/w */
@@ -348,6 +442,9 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
                        dma_stat = inb(dma_base+2);
                        return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
+               case ide_dma_bad_drive:
+               case ide_dma_good_drive:
+                       return check_drive_lists(drive, (func == ide_dma_good_drive));
                default:
                        printk("ide_dmaproc: unsupported func: %d\n", func);
                        return 1;
@@ -434,9 +531,29 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c
                        request_region(dma_base+16, extra, name);
                dma_base += hwif->channel ? 8 : 0;
                hwif->dma_extra = extra;
-               if (inb(dma_base+2) & 0x80) {
-                       printk("%s: simplex device:  DMA disabled\n", name);
-                       dma_base = 0;
+
+               switch(dev->device) {
+                       case PCI_DEVICE_ID_CMD_643:
+                               /*
+                                * Lets attempt to use the same Ali tricks
+                                * to fix CMD643.....
+                                */
+                       case PCI_DEVICE_ID_AL_M5219:
+                       case PCI_DEVICE_ID_AL_M5229:
+                               outb(inb(dma_base+2) & 0x60, dma_base+2);
+                               /*
+                                * Ali 15x3 chipsets know as ALI IV and V report
+                                * this as simplex, skip this test for them.
+                                */
+                               if (inb(dma_base+2) & 0x80) {
+                                       printk("%s: simplex device: DMA forced\n", name);
+                               }
+                               break;
+                       default:
+                               if (inb(dma_base+2) & 0x80) {
+                                       printk("%s: simplex device:  DMA disabled\n", name);
+                                       dma_base = 0;
+                               }
                }
        }
        return dma_base;
index 30c862f11ed312b5ba8a7ec7ef991ae4ed3048b3..78aa7fe2996780a9f9fb4564c32d1ece66387c87 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 
-/*
- *     Main Linux ide driver include file
- */
-#include "ide.h"
-
 /*
  *     The following are used to debug the driver.
  */
@@ -1011,7 +1007,8 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
                dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-       OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+       if (IDE_CONTROL_REG)
+               OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
        OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);                        /* Use PIO/DMA */
        OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
        OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
index df9c715e1d1729eba81ce8a521b18f4cb91bc120..cc6a3462bc6b18aba7af2ca9557b08fc10c79e5a 100644 (file)
@@ -1,5 +1,7 @@
 /*
- *  linux/drivers/block/ide-pci.c      Version 1.02  December 29, 1997
+ *  linux/drivers/block/ide-pci.c      Version 1.03  May 1, 1999
+ *
+ *  Copyright (c) 1998-1999  Andre Hedrick
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "ide.h"
-
 #define DEVID_PIIXa    ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
 #define DEVID_PIIXb    ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
 #define DEVID_PIIX3    ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
 #define DEVID_PIIX4    ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
 #define DEVID_VP_IDE   ((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
 #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+#define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
 #define DEVID_RZ1000   ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001   ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_SAMURAI  ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
 #define DEVID_CMD640   ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
+#define DEVID_CMD643   ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
 #define DEVID_CMD646   ((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
 #define DEVID_SIS5513  ((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
 #define DEVID_OPTI621  ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
 #define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
-#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    0xd568})  /* from datasheets */
+#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
 #define DEVID_TRM290   ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
 #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_UM8886A  ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
 #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
 #define DEVID_HPT343   ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#define DEVID_ALI15X3  ((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
+#define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
+#define DEVID_HINT     ((ide_pci_devid_t){0x3388,                0x8013})
+#define DEVID_CX5530   ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
 
 #define IDE_IGNORE     ((void *)-1)
 
@@ -98,11 +106,68 @@ extern void ide_init_rz1000(ide_hwif_t *);
 
 #ifdef CONFIG_BLK_DEV_VIA82C586
 extern void ide_init_via82c586(ide_hwif_t *);
+extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase);
 #define        INIT_VIA82C586  &ide_init_via82c586
+#define        DMA_VIA82C586   &ide_dmacapable_via82c586
 #else
 #define        INIT_VIA82C586  NULL
+#define        DMA_VIA82C586   NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_ALI15X3
+extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+extern void ide_init_ali15x3(ide_hwif_t *);
+#define PCI_ALI15X3    &pci_init_ali15x3
+#define        INIT_ALI15X3    &ide_init_ali15x3
+#else
+#define PCI_ALI15X3    NULL
+#define        INIT_ALI15X3    NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_CY82C693
+extern void ide_init_cy82c693(ide_hwif_t *);
+#define        INIT_CY82C693   &ide_init_cy82c693
+#else
+#define        INIT_CY82C693   NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern void ide_init_pdc202xx(ide_hwif_t *);
+#define PCI_PDC202XX   &pci_init_pdc202xx
+#define        INIT_PDC202XX   &ide_init_pdc202xx
+#else
+#define PCI_PDC202XX   NULL
+#define        INIT_PDC202XX   NULL
 #endif
 
+#ifdef CONFIG_BLK_DEV_PIIX
+extern void ide_init_piix(ide_hwif_t *);
+#define        INIT_PIIX       &ide_init_piix
+#else
+#define        INIT_PIIX       NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_AEC6210
+extern unsigned int pci_init_aec6210(struct pci_dev *, const char *);
+#define PCI_AEC6210    &pci_init_aec6210
+#else
+#define PCI_AEC6210    NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_HPT343
+extern unsigned int pci_init_hpt343(struct pci_dev *, const char *);
+extern void ide_init_hpt343(ide_hwif_t *);
+#define PCI_HPT343     &pci_init_hpt343
+#define        INIT_HPT343     &ide_init_hpt343
+#else
+#define PCI_HPT343     NULL
+#define        INIT_HPT343     NULL
+#endif
+
+#define INIT_SAMURAI   NULL
+#define INIT_CX5530    NULL
+
 typedef struct ide_pci_enablebit_s {
        byte    reg;    /* byte pci reg holding the enable-bit */
        byte    mask;   /* mask to isolate the enable-bit */
@@ -112,36 +177,45 @@ typedef struct ide_pci_enablebit_s {
 typedef struct ide_pci_device_s {
        ide_pci_devid_t         devid;
        const char              *name;
+       unsigned int            (*init_chipset)(struct pci_dev *dev, const char *name);
        void                    (*init_hwif)(ide_hwif_t *hwif);
+       void                    (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
        ide_pci_enablebit_t     enablebits[2];
        byte                    bootable;
        unsigned int            extra;
 } ide_pci_device_t;
 
 static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-       {DEVID_PIIXa,   "PIIX",         NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
-       {DEVID_PIIXb,   "PIIX",         NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
-       {DEVID_PIIX3,   "PIIX3",        NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
-       {DEVID_PIIX4,   "PIIX4",        NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
-       {DEVID_VP_IDE,  "VP_IDE",       INIT_VIA82C586, {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
-       {DEVID_PDC20246,"PDC20246",     NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      16 },
-       {DEVID_RZ1000,  "RZ1000",       INIT_RZ1000,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_RZ1001,  "RZ1001",       INIT_RZ1000,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_CMD640,  "CMD640",       IDE_IGNORE,     {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_NS87410, "NS87410",      NULL,           {{0x43,0x08,0x08}, {0x47,0x08,0x08}},   ON_BOARD,       0 },
-       {DEVID_SIS5513, "SIS5513",      NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   ON_BOARD,       0 },
-       {DEVID_CMD646,  "CMD646",       INIT_CMD646,    {{0x00,0x00,0x00}, {0x51,0x80,0x80}},   ON_BOARD,       0 },
-       {DEVID_HT6565,  "HT6565",       NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_OPTI621, "OPTI621",      INIT_OPTI621,   {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
-       {DEVID_OPTI621X,"OPTI621X",     INIT_OPTI621,   {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
-       {DEVID_TRM290,  "TRM290",       INIT_TRM290,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_NS87415, "NS87415",      INIT_NS87415,   {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_AEC6210, "AEC6210",      NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
-       {DEVID_W82C105, "W82C105",      INIT_W82C105,   {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
-       {DEVID_UM8886A, "UM8886A",      NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_UM8886BF,"UM8886BF",     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_HPT343,  "HPT343",       NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
-       {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 }};
+       {DEVID_PIIXa,   "PIIX",         NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_PIIXb,   "PIIX",         NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_PIIX3,   "PIIX3",        NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_PIIX4,   "PIIX4",        NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_VP_IDE,  "VP_IDE",       NULL,           INIT_VIA82C586, DMA_VIA82C586,  {{0x40,0x02,0x02}, {0x40,0x01,0x01}},   ON_BOARD,       0 },
+       {DEVID_PDC20246,"PDC20246",     PCI_PDC202XX,   INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      16 },
+       {DEVID_PDC20262,"PDC20262",     PCI_PDC202XX,   INIT_PDC202XX,  NULL,           {{0x50,0x02,0x02}, {0x50,0x04,0x04}},   OFF_BOARD,      48 },
+       {DEVID_RZ1000,  "RZ1000",       NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_RZ1001,  "RZ1001",       NULL,           INIT_RZ1000,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_SAMURAI, "SAMURAI",      NULL,           INIT_SAMURAI,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_CMD640,  "CMD640",       NULL,           IDE_IGNORE,     NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_NS87410, "NS87410",      NULL,           NULL,           NULL,           {{0x43,0x08,0x08}, {0x47,0x08,0x08}},   ON_BOARD,       0 },
+       {DEVID_SIS5513, "SIS5513",      NULL,           NULL,           NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   ON_BOARD,       0 },
+       {DEVID_CMD643,  "CMD643",       NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_CMD646,  "CMD646",       NULL,           INIT_CMD646,    NULL,           {{0x00,0x00,0x00}, {0x51,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_HT6565,  "HT6565",       NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_OPTI621, "OPTI621",      NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
+       {DEVID_OPTI621X,"OPTI621X",     NULL,           INIT_OPTI621,   NULL,           {{0x45,0x80,0x00}, {0x40,0x08,0x00}},   ON_BOARD,       0 },
+       {DEVID_TRM290,  "TRM290",       NULL,           INIT_TRM290,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_NS87415, "NS87415",      NULL,           INIT_NS87415,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_AEC6210, "AEC6210",      PCI_AEC6210,    NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   OFF_BOARD,      0 },
+       {DEVID_W82C105, "W82C105",      NULL,           INIT_W82C105,   NULL,           {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
+       {DEVID_UM8886A, "UM8886A",      NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_UM8886BF,"UM8886BF",     NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_HPT343,  "HPT343",       PCI_HPT343,     INIT_HPT343,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
+       {DEVID_ALI15X3, "ALI15X3",      PCI_ALI15X3,    INIT_ALI15X3,   NULL,           {{0x09,0x20,0x20}, {0x09,0x10,0x10}},   ON_BOARD,       0 },
+       {DEVID_CY82C693,"CY82C693",     NULL,           INIT_CY82C693,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_HINT,    "HINT_IDE",     NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {DEVID_CX5530,  "CX5530",       NULL,           INIT_CX5530,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
+       {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 }};
 
 /*
  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
@@ -151,27 +225,28 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
 __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name))
 {
        switch(dev->device) {
-               case PCI_DEVICE_ID_ARTOP_ATP850UF:
-               case PCI_DEVICE_ID_PROMISE_20246:
-                       if (dev->rom_address) {
-                               pci_write_config_byte(dev, PCI_ROM_ADDRESS,
-                                       dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
-                               printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
-                       }
-                       
-                       if ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID) {
-                               unsigned char irq1 = 0, irq2 = 0;
-
-                               pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq1);
-                               pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);    /* 0xbc */
-                               if (irq1 != irq2) {
-                                       printk("%s: IRQ1 %d IRQ2 %d\n",
-                                               name, irq1, irq2);
-                                       pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq1);    /* 0xbc */
-                               }
-                       }
-                       return dev->irq;
                case PCI_DEVICE_ID_TTI_HPT343:
+                       {
+                               int i;
+                               unsigned short pcicmd = 0;
+                               unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+
+                               pci_write_config_byte(dev, 0x80, 0x00);
+                               dev->base_address[0] = (hpt343IoBase + 0x20);
+                               dev->base_address[1] = (hpt343IoBase + 0x34);
+                               dev->base_address[2] = (hpt343IoBase + 0x28);
+                               dev->base_address[3] = (hpt343IoBase + 0x3c);
+                               for(i=0; i<4; i++)
+                                       dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+
+                               pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+                               pci_write_config_byte(dev, 0x80, 0x80);
+                               if (!(pcicmd & PCI_COMMAND_MEMORY))
+                                       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+                       }
+               case PCI_DEVICE_ID_PROMISE_20246:
+               case PCI_DEVICE_ID_PROMISE_20262:
+               case PCI_DEVICE_ID_ARTOP_ATP850UF:
                        return dev->irq;
                default:
                        break;
@@ -269,7 +344,7 @@ __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *n
         */
        for (reg = 0; reg < 4; reg++)
                if (!dev->base_address[reg]) {
-                       printk("%s: Missing I/O address #%d, please report to <mj@ucw.cz>\n", name, reg);
+                       printk("%s: Missing I/O address #%d\n", name, reg);
                        return 1;
                }
        return 0;
@@ -325,7 +400,13 @@ check_if_enabled:
        pciirq = dev->irq;
        if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
                printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
-               pciirq = ide_special_settings(dev, d->name);
+               /*
+                * This allows offboard ide-pci cards the enable a BIOS,
+                * verify interrupt settings of split-mirror pci-config
+                * space, place chipset into init-mode, and/or preserve
+                * an interrupt if the card is not native ide support.
+                */
+               pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
        } else if (tried_config) {
                printk("%s: will probe irqs later\n", d->name);
                pciirq = 0;
@@ -340,6 +421,19 @@ check_if_enabled:
                printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
 #endif
        }
+       if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) {
+               /*
+                * Since there are two cards that report almost identically,
+                * the only discernable difference is the values
+                * reported in pcicmd.
+                * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+                * Non-bootable card or HPT343 :: pcicmd == 0x05
+                */
+               if (pcicmd & PCI_COMMAND_MEMORY) {
+                       printk("%s: is IDE Express HPT363.\n", d->name);
+                       d->bootable = OFF_BOARD;
+               }
+       }
        /*
         * Set up the IDE ports
         */
@@ -363,8 +457,8 @@ check_if_enabled:
                if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
                        continue;       /* no room in ide_hwifs[] */
                if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-                       ide_init_hwif_ports(hwif->io_ports, base, NULL);
-                       hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
+                       ide_init_hwif_ports(&hwif->hw, base, (ctl + 2), NULL);
+                       memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
                        hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
                }
                hwif->chipset = ide_pci;
@@ -382,8 +476,10 @@ check_if_enabled:
                        }
                }
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-                   IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF))
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF)) {
                        hwif->irq = hwif->channel ? 15 : 14;
+                       goto bypass_umc_dma;
+               }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513))
@@ -391,8 +487,12 @@ check_if_enabled:
                if (autodma)
                        hwif->autodma = 1;
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
                    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
+#ifdef CONFIG_BLK_DEV_HPT343
                    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) ||
+#endif
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
                    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
                        unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
                        if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
@@ -406,12 +506,18 @@ check_if_enabled:
                                        dma_base = 0;
                                }
                        }
-                       if (dma_base)
-                               ide_setup_dma(hwif, dma_base, 8);
-                       else
+                       if (dma_base) {
+                               if (d->dma_init) {
+                                       d->dma_init(hwif, dma_base);
+                               } else {
+                                       ide_setup_dma(hwif, dma_base, 8);
+                               }
+                       } else {
                                printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
+                       }
                }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+bypass_umc_dma:
                if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
                        d->init_hwif(hwif);
                mate = hwif;
@@ -441,6 +547,8 @@ __initfunc(void ide_scan_pcibus (void))
                        printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
                else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
                        continue;       /* OPTI Viper-M uses same devid for functions 0 and 1 */
+               else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+                       continue;       /* CY82C693 is more than only a IDE controller */
                else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
                        if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
                                printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
index d8d353d876c1c9a88125724e8fbf745725178452..1156d368935d07265909dd080407e430a66e4f0c 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
+
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
@@ -31,9 +33,9 @@
 #include <asm/adb.h>
 #include <asm/pmu.h>
 #endif
-#include "ide.h"
 #include "ide_modes.h"
 
+int pmac_ide_ports_known;
 ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
 int pmac_ide_irq[MAX_HWIFS];
 int pmac_ide_count;
@@ -58,24 +60,32 @@ struct notifier_block idepmac_sleep_notifier = {
  * N.B. this can't be an initfunc, because the media-bay task can
  * call ide_[un]register at any time.
  */
-void
-pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void pmac_ide_init_hwif_ports (        hw_regs_t *hw,
+                               ide_ioreg_t data_port,
+                               ide_ioreg_t ctrl_port,
+                               int *irq)
 {
+       ide_ioreg_t reg = ide_ioreg_t data_port;
        int i, r;
 
-       *p = 0;
-       if (base == 0)
+       if (data_port == 0)
                return;
        /* we check only for -EINVAL meaning that we have found a matching
           bay but with the wrong device type */ 
 
-       r = check_media_bay_by_base(base, MB_CD);
+       r = check_media_bay_by_base(data_port, MB_CD);
        if (r == -EINVAL)
                return;
                
-       for (i = 0; i < 8; ++i)
-               *p++ = base + i * 0x10;
-       *p = base + 0x160;
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg * 0x10;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x160;
+       }
        if (irq != NULL) {
                *irq = 0;
                for (i = 0; i < MAX_HWIFS; ++i) {
@@ -104,8 +114,7 @@ void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
        }
 }
 
-__initfunc(void
-pmac_ide_probe(void))
+__initfunc(void pmac_ide_probe(void))
 {
        struct device_node *np;
        int i;
@@ -172,7 +181,8 @@ pmac_ide_probe(void))
                        feature_set(np, FEATURE_IDE_enable);
 
                hwif = &ide_hwifs[i];
-               pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq);
+               pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
+               memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
                hwif->chipset = ide_generic;
                hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
                hwif->tuneproc = pmac_ide_tuneproc;
index 1d13043e8a76e5e4b22e044cd9f02f391877c243..bc3954b7dd3f41b63637e72444ba916de379486b 100644 (file)
@@ -18,6 +18,8 @@
  *                      by Andrea Arcangeli
  * Version 1.03                fix for (hwif->chipset == ide_4drives)
  * Version 1.04                fixed buggy treatments of known flash memory cards
+ *                     fix for (hwif->chipset == ide_pdc4030)
+ *                     added ide6/7
  */
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 #include <linux/genhd.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
+
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include "ide.h"
-
 static inline void do_identify (ide_drive_t *drive, byte cmd)
 {
        int bswap = 1;
@@ -147,17 +149,6 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
        return;
 }
 
-/*
- * Delay for *at least* 50ms.  As we don't know how much time is left
- * until the next tick occurs, we wait an extra tick to be safe.
- * This is used only during the probing/polling for drives at boot time.
- */
-static void delay_50ms (void)
-{
-       unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
-       while (0 < (signed long)(timeout - jiffies));
-}
-
 /*
  * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
  * and waits for a response.  It also monitors irqs while this is
@@ -176,20 +167,26 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
        unsigned long irqs = 0;
        byte s, a;
 
-       if (!HWIF(drive)->irq) {                /* already got an IRQ? */
-               probe_irq_off(probe_irq_on());  /* clear dangling irqs */
-               irqs = probe_irq_on();          /* start monitoring irqs */
-               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
-       }
+       if (IDE_CONTROL_REG) {
+               if (!HWIF(drive)->irq) {                /* already got an IRQ? */
+                       probe_irq_off(probe_irq_on());  /* clear dangling irqs */
+                       irqs = probe_irq_on();          /* start monitoring irqs */
+                       OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
+               }
 
-       delay_50ms();                           /* take a deep breath */
-       a = IN_BYTE(IDE_ALTSTATUS_REG);
-       s = IN_BYTE(IDE_STATUS_REG);
-       if ((a ^ s) & ~INDEX_STAT) {
-               printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-               hd_status = IDE_STATUS_REG;     /* ancient Seagate drives, broken interfaces */
-       } else
-               hd_status = IDE_ALTSTATUS_REG;  /* use non-intrusive polling */
+               ide_delay_50ms();                               /* take a deep breath */
+               a = IN_BYTE(IDE_ALTSTATUS_REG);
+               s = IN_BYTE(IDE_STATUS_REG);
+               if ((a ^ s) & ~INDEX_STAT) {
+                       printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+                       hd_status = IDE_STATUS_REG;     /* ancient Seagate drives, broken interfaces */
+               } else {
+                       hd_status = IDE_ALTSTATUS_REG;  /* use non-intrusive polling */
+               }
+       } else {
+               ide_delay_50ms();
+               hd_status = IDE_STATUS_REG;
+       }
 
 #if CONFIG_BLK_DEV_PDC4030
        if (IS_PDC4030_DRIVE) {
@@ -210,10 +207,10 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
                                (void) probe_irq_off(irqs);
                        return 1;       /* drive timed-out */
                }
-               delay_50ms();           /* give drive a breather */
+               ide_delay_50ms();               /* give drive a breather */
        } while (IN_BYTE(hd_status) & BUSY_STAT);
 
-       delay_50ms();           /* wait for IRQ and DRQ_STAT */
+       ide_delay_50ms();               /* wait for IRQ and DRQ_STAT */
        if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
                unsigned long flags;
                __save_flags(flags);    /* local CPU only */
@@ -224,7 +221,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
                __restore_flags(flags); /* local CPU only */
        } else
                rc = 2;                 /* drive refused ID */
-       if (!HWIF(drive)->irq) {
+       if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
                irqs = probe_irq_off(irqs);     /* get our irq number */
                if (irqs > 0) {
                        HWIF(drive)->irq = irqs; /* save it for later */
@@ -280,11 +277,11 @@ static int do_probe (ide_drive_t *drive, byte cmd)
                (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
        SELECT_DRIVE(hwif,drive);
-       delay_50ms();
+       ide_delay_50ms();
        if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
                if (drive->select.b.unit != 0) {
                        SELECT_DRIVE(hwif,&hwif->drives[0]);    /* exit with drive0 selected */
-                       delay_50ms();           /* allow BUSY_STAT to assert & clear */
+                       ide_delay_50ms();               /* allow BUSY_STAT to assert & clear */
                }
                return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
        }
@@ -297,13 +294,13 @@ static int do_probe (ide_drive_t *drive, byte cmd)
                if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
                        unsigned long timeout;
                        printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
-                       delay_50ms();
+                       ide_delay_50ms();
                        OUT_BYTE (drive->select.all, IDE_SELECT_REG);
-                       delay_50ms();
+                       ide_delay_50ms();
                        OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
                        timeout = jiffies;
                        while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
-                               delay_50ms();
+                               ide_delay_50ms();
                        rc = try_to_identify(drive, cmd);
                }
                if (rc == 1)
@@ -314,7 +311,7 @@ static int do_probe (ide_drive_t *drive, byte cmd)
        }
        if (drive->select.b.unit != 0) {
                SELECT_DRIVE(hwif,&hwif->drives[0]);    /* exit with drive0 selected */
-               delay_50ms();
+               ide_delay_50ms();
                (void) GET_STAT();              /* ensure drive irq is clear */
        }
        return rc;
@@ -407,15 +404,40 @@ static void probe_hwif (ide_hwif_t *hwif)
        unsigned int unit;
        unsigned long flags;
 
+       ide_ioreg_t ide_control_reg     = hwif->io_ports[IDE_CONTROL_OFFSET];
+       ide_ioreg_t region_low          = hwif->io_ports[IDE_DATA_OFFSET];
+       ide_ioreg_t region_high         = region_low;
+       ide_ioreg_t region_request      = 8;
+       int i;
+
        if (hwif->noprobe)
                return;
        if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
                probe_cmos_for_drives (hwif);
-       if ((hwif->chipset != ide_4drives || !hwif->mate->present)
+
+       /*
+        * Calculate the region that this interface occupies,
+        * handling interfaces where the registers may not be
+        * ordered sanely.  We deal with the CONTROL register
+        * separately.
+        */
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               if (hwif->io_ports[i]) {
+                       if (hwif->io_ports[i] < region_low)
+                               region_low = hwif->io_ports[i];
+                       if (hwif->io_ports[i] > region_high)
+                               region_high = hwif->io_ports[i];
+               }
+       }
+       region_request = (region_high - region_low);
+       if (region_request == 0x0007)
+               region_request++;
+       if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
-        && (hwif->chipset != ide_pdc4030 || hwif->channel == 0)
+           (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
-        && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)))
+           (ide_check_region(region_low, region_request) ||
+           (ide_control_reg && ide_check_region(ide_control_reg,1))))
        {
                int msgout = 0;
                for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -443,21 +465,22 @@ static void probe_hwif (ide_hwif_t *hwif)
                if (drive->present && !hwif->present) {
                        hwif->present = 1;
                        if (hwif->chipset != ide_4drives || !hwif->mate->present) {
-                               ide_request_region(hwif->io_ports[IDE_DATA_OFFSET],  8, hwif->name);
-                               ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+                               ide_request_region(region_low, region_request, hwif->name);
+                               if (ide_control_reg)
+                                       ide_request_region(ide_control_reg, 1, hwif->name);
                        }
                }
        }
-       if (hwif->reset) {
+       if (ide_control_reg && hwif->reset) {
                unsigned long timeout = jiffies + WAIT_WORSTCASE;
                byte stat;
 
                printk("%s: reset\n", hwif->name);
-               OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+               OUT_BYTE(12, ide_control_reg);
                udelay(10);
-               OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+               OUT_BYTE(8, ide_control_reg);
                do {
-                       delay_50ms();
+                       ide_delay_50ms();
                        stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
                } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
 
@@ -660,7 +683,11 @@ static void init_gendisk (ide_hwif_t *hwif)
        max_readahead[hwif->major] = max_ra;
        for (unit = 0; unit < minors; ++unit) {
                *bs++ = BLOCK_SIZE;
+#ifdef CONFIG_BLK_DEV_PDC4030
+               *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : MAX_SECTORS);
+#else
                *max_sect++ = MAX_SECTORS;
+#endif
                *max_ra++ = MAX_READAHEAD;
        }
 
@@ -693,7 +720,8 @@ static int hwif_init (ide_hwif_t *hwif)
        if (!hwif->present)
                return 0;
        if (!hwif->irq) {
-               if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+               if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
+               {
                        printk("%s: DISABLED, NO IRQ\n", hwif->name);
                        return (hwif->present = 0);
                }
@@ -722,6 +750,12 @@ static int hwif_init (ide_hwif_t *hwif)
 #endif
 #if MAX_HWIFS > 5
        case IDE5_MAJOR: rfn = &do_ide5_request; break;
+#endif
+#if MAX_HWIFS > 6
+       case IDE6_MAJOR: rfn = &do_ide6_request; break;
+#endif
+#if MAX_HWIFS > 7
+       case IDE7_MAJOR: rfn = &do_ide7_request; break;
 #endif
        default:
                printk("%s: request_fn NOT DEFINED\n", hwif->name);
index 26a56e7406904116f38cb9824264e59d077b50c9..f985980b12162a73f242dc15c4b9c7aa13c9afba 100644 (file)
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
 
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
+#ifdef CONFIG_BLK_DEV_VIA82C586
+int (*via_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_VIA82C586 */
+
+#ifdef CONFIG_BLK_DEV_ALI15X3
+int (*ali_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+
 static int ide_getxdigit(char c)
 {
        int digit;
@@ -682,6 +691,18 @@ void proc_ide_create(void)
        ent = create_proc_entry("drivers", 0, root);
        if (!ent) return;
        ent->read_proc  = proc_ide_read_drivers;
+#ifdef CONFIG_BLK_DEV_VIA82C586
+       if (via_display_info) {
+               ent = create_proc_entry("via", 0, root);
+               ent->get_info = via_display_info;
+       }
+#endif /* CONFIG_BLK_DEV_VIA82C586 */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+       if (ali_display_info) {
+               ent = create_proc_entry("ali", 0, root);
+               ent->get_info = ali_display_info;
+       }
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
 }
 
 void proc_ide_destroy(void)
@@ -690,6 +711,14 @@ void proc_ide_destroy(void)
         * Mmmm.. does this free up all resources,
         * or do we need to do a more proper cleanup here ??
         */
+#ifdef CONFIG_BLK_DEV_VIA82C586
+       if (via_display_info)
+               remove_proc_entry("ide/via",0);
+#endif /* CONFIG_BLK_DEV_VIA82C586 */
+#ifdef CONFIG_BLK_DEV_ALI15X3
+       if (ali_display_info)
+               remove_proc_entry("ide/ali",0);
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
        remove_proc_entry("ide/drivers", 0);
        remove_proc_entry("ide", 0);
 }
index e97087097dc195c2cea652238ab5eb32676ae1f8..1382eb3abf54adc0a83868d4a556a93ebb2313c7 100644 (file)
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 
-/*
- *     Main Linux ide driver include file
- */
-#include "ide.h"
-
 /*
  *     For general magnetic tape device compatibility.
  */
 /*
  *     The following are used to debug the driver:
  *
+ *     Setting IDETAPE_INFO_LOG to 1 will log driver vender information.
  *     Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
  *     Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
  *     some places.
  *     is verified to be stable enough. This will make it much more
  *     esthetic.
  */
+#define IDETAPE_INFO_LOG               0
 #define IDETAPE_DEBUG_LOG              0
 #define IDETAPE_DEBUG_BUGS             1
 
+#if IDETAPE_DEBUG_LOG
+#undef IDETAPE_INFO_LOG
+#define IDETAPE_INFO_LOG               IDETAPE_DEBUG_LOG
+#endif
+
 /*
  *     After each failed packet command we issue a request sense command
  *     and retry the packet command IDETAPE_MAX_PC_RETRIES times.
@@ -1968,7 +1972,8 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
                dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-       OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+       if (IDE_CONTROL_REG)
+               OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
        OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);                        /* Use PIO/DMA */
        OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
        OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
@@ -3337,16 +3342,16 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
 {
        struct idetape_id_gcw gcw;
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_INFO_LOG
        unsigned short mask,i;
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_INFO_LOG */
 
        if (!id)
                return 0;
 
        *((unsigned short *) &gcw) = id->config;
 
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_INFO_LOG
        printk (KERN_INFO "Dumping ATAPI Identify Device tape parameters\n");
        printk (KERN_INFO "Protocol Type: ");
        switch (gcw.protocol) {
@@ -3434,7 +3439,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
                
        } else
                printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_INFO_LOG */
 
        /* Check that we can support this device */
 
@@ -3491,7 +3496,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
 
        tape->capabilities = *capabilities;             /* Save us a copy */
        tape->tape_block_size = capabilities->blk512 ? 512:1024;
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_INFO_LOG
        printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
        printk (KERN_INFO "Mode Parameter Header:\n");
        printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
@@ -3519,7 +3524,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
        printk (KERN_INFO "Continuous transfer limits in blocks - %d\n",capabilities->ctl);
        printk (KERN_INFO "Current speed in KBps - %d\n",capabilities->speed);  
        printk (KERN_INFO "Buffer size - %d\n",capabilities->buffer_size*512);
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_INFO_LOG */
 }
 
 static void idetape_add_settings(ide_drive_t *drive)
@@ -3561,7 +3566,18 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
 
        drive->driver_data = tape;
        drive->ready_stat = 0;                  /* An ATAPI device ignores DRDY */
-       drive->dsc_overlap = 1;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+       /*
+        *  These two ide-pci host adapters appear to need this disabled.
+        */
+       if ((hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+           (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+               drive->dsc_overlap = 0;
+       } else
+#endif  /* CONFIG_BLK_DEV_IDEPCI */
+       {
+               drive->dsc_overlap = 1;
+       }
        memset (tape, 0, sizeof (idetape_tape_t));
        tape->drive = drive;
        tape->minor = minor;
index e93a7d454223735c47623cefc40680d30981b9b1..6b59faed30b161317bf53f5bb634758328958b3b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 6.18  August 16, 1998
+ *  linux/drivers/block/ide.c  Version 6.19  January 29, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
  * Version 6.16                fixed various bugs; even more SMP friendly
  * Version 6.17                fix for newest EZ-Drive problem
  * Version 6.18                default unpartitioned-disk translation now "BIOS LBA"
+ * Version 6.19                Re-design for a UNIFORM driver for all platforms,
+ *                     model based on suggestions from Russell King and
+ *                     Geert Uytterhoeven
+ *                     Promise DC4030VL now supported.
+ *                     delay_50ms() changed to ide_delay_50ms() and exported.
  *
  *  Some additional driver compile-time options are in ide.h
  *
  *     - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
 */
 
+#define        REVISION        "Revision: 6.19"
+#define        VERSION         "Id: ide.c 6.19 1999/01/29"
+
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
 #define _IDE_C                 /* Tell ide.h it's really us */
 #include <linux/malloc.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#include "ide.h"
 #include "ide_modes.h"
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif /* CONFIG_KMOD */
 
-static const byte      ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR };
+#ifdef CONFIG_BLK_DEV_VIA82C586
+extern byte fifoconfig;           /* defined in via82c586.c used by ide_setup()*/
+#endif
+
+static const byte      ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR };
 
 static int     idebus_parameter; /* holds the "idebus=" parameter */
 static int     system_bus_speed; /* holds what we think is VESA/PCI bus speed */
 static int     initializing;     /* set while initializing built-in drivers */
 
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 /*
  * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
  * which is shared between several drivers.
  */
 static int     ide_lock = 0;
+#endif /* __mc68000__ || CONFIG_APUS */
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
@@ -187,14 +201,18 @@ static inline void set_recovery_timer (ide_hwif_t *hwif)
 static void init_hwif_data (unsigned int index)
 {
        unsigned int unit;
+       hw_regs_t hw;
        ide_hwif_t *hwif = &ide_hwifs[index];
 
        /* bulk initialize hwif & drive info with zeros */
        memset(hwif, 0, sizeof(ide_hwif_t));
+       memset(&hw, 0, sizeof(hw_regs_t));
 
        /* fill in any non-zero initial values */
        hwif->index     = index;
-       ide_init_hwif_ports(hwif->io_ports, ide_default_io_base(index), &hwif->irq);
+       ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
+       memcpy(&hwif->hw, &hw, sizeof(hw));
+       memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
        hwif->noprobe   = !hwif->io_ports[IDE_DATA_OFFSET];
 #ifdef CONFIG_BLK_DEV_HD
        if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
@@ -211,6 +229,7 @@ static void init_hwif_data (unsigned int index)
                drive->media                    = ide_disk;
                drive->select.all               = (unit<<4)|0xa0;
                drive->hwif                     = hwif;
+               init_waitqueue_head(&drive->wqueue);
                drive->ctl                      = 0x08;
                drive->ready_stat               = READY_STAT;
                drive->bad_wstat                = BAD_W_STAT;
@@ -219,6 +238,7 @@ static void init_hwif_data (unsigned int index)
                drive->name[0]                  = 'h';
                drive->name[1]                  = 'd';
                drive->name[2]                  = 'a' + (index * MAX_DRIVES) + unit;
+               init_waitqueue_head(&drive->wqueue);
        }
 }
 
@@ -246,9 +266,13 @@ static void init_ide_data (void)
                return;         /* already initialized */
        magic_cookie = 0;
 
+       /* Initialise all interface structures */
        for (index = 0; index < MAX_HWIFS; ++index)
                init_hwif_data(index);
 
+       /* Add default hw interfaces */
+       ide_init_default_hwifs();
+
        idebus_parameter = 0;
        system_bus_speed = 0;
 }
@@ -652,6 +676,10 @@ static void do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
                pre_reset(&hwif->drives[unit]);
 
 #if OK_TO_RESET_CONTROLLER
+       if (!IDE_CONTROL_REG) {
+               __restore_flags(flags);
+               return;
+       }
        /*
         * Note that we also set nIEN while resetting the device,
         * to mask unwanted interrupts from the interface during the reset.
@@ -857,7 +885,8 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat)
 void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
        ide_set_handler (drive, handler, WAIT_CMD);
-       OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* clear nIEN */
+       if (IDE_CONTROL_REG)
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* clear nIEN */
        OUT_BYTE(nsect,IDE_NSECTOR_REG);
        OUT_BYTE(cmd,IDE_COMMAND_REG);
 }
@@ -1253,6 +1282,20 @@ void do_ide5_request (void)
 }
 #endif /* MAX_HWIFS > 5 */
 
+#if MAX_HWIFS > 6
+void do_ide6_request (void)
+{
+       unlock_do_hwgroup_request (ide_hwifs[6].hwgroup);
+}
+#endif /* MAX_HWIFS > 6 */
+
+#if MAX_HWIFS > 7
+void do_ide7_request (void)
+{
+       unlock_do_hwgroup_request (ide_hwifs[7].hwgroup);
+}
+#endif /* MAX_HWIFS > 7 */
+
 static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
        unsigned long   flags;
@@ -1370,6 +1413,12 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
        __cli();        /* local CPU only */
        spin_lock_irqsave(&hwgroup->spinlock, flags);
        hwif = hwgroup->hwif;
+
+       if (!ide_ack_intr(hwif)) {
+               spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+               return;
+       }
+
        if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
                /*
                 * Not expecting an interrupt from this drive.
@@ -1391,7 +1440,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
                         * Probably not a shared PCI interrupt,
                         * so we can safely try to do something about it:
                         */
-                       (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
                        unexpected_intr(irq, hwgroup);
                }
                spin_unlock_irqrestore(&hwgroup->spinlock, flags);
@@ -1403,7 +1451,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
                return;
        }
        hwgroup->handler = NULL;
-       (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
        del_timer(&(hwgroup->timer));
        spin_unlock_irqrestore(&hwgroup->spinlock, flags);
        if (drive->unmask)
@@ -1753,7 +1800,8 @@ void ide_unregister (unsigned int index)
         * allocated for weird IDE interface chipsets.
         */
        ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-       ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+       if (hwif->io_ports[IDE_CONTROL_OFFSET])
+               ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 
        /*
         * Remove us from the hwgroup, and free
@@ -1817,21 +1865,58 @@ abort:
        restore_flags(flags);   /* all CPUs */
 }
 
-int ide_register (int arg1, int arg2, int irq)
+/*
+ * Setup hw_regs_t structure described by parameters.  You
+ * may set up the hw structure yourself OR use this routine to
+ * do it for you.
+ */
+void ide_setup_ports ( hw_regs_t *hw,
+                       ide_ioreg_t base, int *offsets,
+                       ide_ioreg_t ctrl, ide_ioreg_t intr,
+                       ide_ack_intr_t *ack_intr, int irq)
+{
+       int i;
+
+       for (i = 0; i < IDE_NR_PORTS; i++) {
+               if (offsets[i] == -1) {
+                       switch(i) {
+                               case IDE_CONTROL_OFFSET:
+                                       hw->io_ports[i] = ctrl;
+                                       break;
+                               case IDE_IRQ_OFFSET:
+                                       hw->io_ports[i] = intr;
+                                       break;
+                               default:
+                                       hw->io_ports[i] = 0;
+                                       break;
+                       }
+               } else {
+                       hw->io_ports[i] = base + offsets[i];
+               }
+       }
+       hw->irq = irq;
+       hw->ack_intr = ack_intr;
+}
+
+/*
+ * Register an IDE interface, specifing exactly the registers etc
+ * Set init=1 iff calling before probes have taken place.
+ */
+int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
 {
        int index, retry = 1;
        ide_hwif_t *hwif;
-       ide_ioreg_t data_port = (ide_ioreg_t) arg1, ctl_port = (ide_ioreg_t) arg2;
 
        do {
                for (index = 0; index < MAX_HWIFS; ++index) {
                        hwif = &ide_hwifs[index];
-                       if (hwif->io_ports[IDE_DATA_OFFSET] == data_port)
+                       if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
                                goto found;
                }
                for (index = 0; index < MAX_HWIFS; ++index) {
                        hwif = &ide_hwifs[index];
-                       if (!hwif->present)
+                       if ((!hwif->present && !initializing) ||
+                           (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
                                goto found;
                }
                for (index = 0; index < MAX_HWIFS; index++)
@@ -1843,14 +1928,33 @@ found:
                ide_unregister(index);
        if (hwif->present)
                return -1;
-       ide_init_hwif_ports(hwif->io_ports, data_port, &hwif->irq);
-       if (ctl_port)
-               hwif->io_ports[IDE_CONTROL_OFFSET] = ctl_port;
-       hwif->irq = irq;
+       memcpy(&hwif->hw, hw, sizeof(*hw));
+       memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+       hwif->irq = hw->irq;
        hwif->noprobe = 0;
-       ide_init_module(IDE_PROBE_MODULE);
-       ide_init_module(IDE_DRIVER_MODULE);
-       return hwif->present ? index : -1;
+
+       if (!initializing) {
+               ide_init_module(IDE_PROBE_MODULE);
+               ide_init_module(IDE_DRIVER_MODULE);
+       }
+
+       if (hwifp)
+               *hwifp = hwif;
+
+       return (initializing || hwif->present) ? index : -1;
+}
+
+/*
+ * Compatability function with existing drivers.  If you want
+ * something different, use the function above.
+ */
+int ide_register (int arg1, int arg2, int irq)
+{
+       hw_regs_t hw;
+
+       ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+       hw.irq = irq;
+       return ide_register_hw(&hw, NULL);
 }
 
 void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
@@ -2075,10 +2179,24 @@ int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int secto
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
+/*
+ * Delay for *at least* 50ms.  As we don't know how much time is left
+ * until the next tick occurs, we wait an extra tick to be safe.
+ * This is used only during the probing/polling for drives at boot time.
+ *
+ * However, its usefullness may be needed in other places, thus we export it now.
+ * The future may change this to a millisecond setable delay.
+ */
+void ide_delay_50ms (void)
+{
+       unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
+       while (0 < (signed long)(timeout - jiffies));
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
-       int err, major, minor;
+       int err = 0, major, minor;
        ide_drive_t *drive;
        struct request rq;
        kdev_t dev;
@@ -2166,7 +2284,68 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                        return -ENOMEM;
                                memcpy(argbuf, args, 4);
                        }
+                       if ((((byte *)arg)[0] == WIN_SETFEATURES) &&
+                           (((byte *)arg)[1] > 66) &&
+                           (((byte *)arg)[2] == 3) &&
+                           ((drive->id->word93 & 0x2000) == 0)) {
+                               printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
+                               goto abort;
+                       }
                        err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+                       if (!err &&
+                           (((byte *)arg)[0] == WIN_SETFEATURES) &&
+                           (((byte *)arg)[1] >= 16) &&
+                           (((byte *)arg)[2] == 3) &&
+                           (drive->id->dma_ultra ||
+                            drive->id->dma_mword ||
+                            drive->id->dma_1word)) {
+
+                               /* 
+                                * Re-read drive->id for possible DMA mode 
+                                * change (copied from ide-probe.c)
+                                */
+                               struct hd_driveid *id;
+                               unsigned long timeout, irqs, flags;
+
+                               probe_irq_off(probe_irq_on());
+                               irqs = probe_irq_on();
+                               if (IDE_CONTROL_REG)
+                                       OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+                               ide_delay_50ms();
+                               OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
+                               timeout = jiffies + WAIT_WORSTCASE;
+                               do {
+                                       if (0 < (signed long)(jiffies - timeout)) {
+                                               if (irqs)
+                                                       (void) probe_irq_off(irqs);
+                                               goto abort;     /* drive timed-out */
+                                       }
+                                       ide_delay_50ms();               /* give drive a breather */
+                               } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
+                               ide_delay_50ms();           /* wait for IRQ and DRQ_STAT */
+                               if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT))
+                                       goto abort;
+                               __save_flags(flags);    /* local CPU only */
+                               __cli();                /* local CPU only; some systems need this */
+                               id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+                               ide_input_data(drive, id, SECTOR_WORDS);
+                               (void) GET_STAT();      /* clear drive IRQ */
+                               ide__sti();             /* local CPU only */
+                               __restore_flags(flags); /* local CPU only */
+                               ide_fix_driveid(id);
+                               if (id && id->cyls) {
+                                       drive->id->dma_ultra = id->dma_ultra;
+                                       drive->id->dma_mword = id->dma_mword;
+                                       drive->id->dma_1word = id->dma_1word;
+                                       /* anything more ? */
+#ifdef DEBUG
+                                       printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n",
+                                               drive->name, id->dma_ultra, id->dma_mword, id->dma_1word);
+#endif
+                               kfree(id);
+                               }
+                       }
+               abort:
                        if (copy_to_user((void *)arg, argbuf, argsize))
                                err = -EFAULT;
                        if (argsize > 4)
@@ -2251,6 +2430,32 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap)
                *p++ = '\0';
 }
 
+/*
+ *
+ */
+char *ide_xfer_verbose (byte xfer_rate) {
+       switch(xfer_rate) {
+               case XFER_UDMA_4:       return("UDMA 4");
+               case XFER_UDMA_3:       return("UDMA 3");
+               case XFER_UDMA_2:       return("UDMA 2");
+               case XFER_UDMA_1:       return("UDMA 1");
+               case XFER_UDMA_0:       return("UDMA 0");
+               case XFER_MW_DMA_2:     return("MW DMA 2");
+               case XFER_MW_DMA_1:     return("MW DMA 1");
+               case XFER_MW_DMA_0:     return("MW DMA 0");
+               case XFER_SW_DMA_2:     return("SW DMA 2");
+               case XFER_SW_DMA_1:     return("SW DMA 1");
+               case XFER_SW_DMA_0:     return("SW DMA 0");
+               case XFER_PIO_4:        return("PIO 4");
+               case XFER_PIO_3:        return("PIO 3");
+               case XFER_PIO_2:        return("PIO 2");
+               case XFER_PIO_1:        return("PIO 1");
+               case XFER_PIO_0:        return("PIO 0");
+               case XFER_PIO_SLOW:     return("PIO SLOW");
+               default:                return("XFER ERROR");
+       }
+}
+
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -2370,7 +2575,22 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
  * "idex=reset"                : reset interface before first use
  * "idex=dma"          : enable DMA by default on both drives if possible
  *
- * The following are valid ONLY on ide0,
+ * "splitfifo=betweenChan"
+ *                     : FIFO Configuration of VIA 82c586(<nothing>,"A"or"B").
+ *                                 --see what follows...
+ * "splitfifo=betweenChan,thresholdprim,thresholdsec"
+ *                     : FIFO Configuration of VIA 82c586(<nothing>,"A" or "B").
+ *                             betweenChan = 1(all FIFO's to primary channel)
+ *                                          , 2(all FIFO's to secondary channel)
+ *                                          , 3 or 4(evenly shared between them).
+ *                             note: without FIFO, a channel is (u)dma disabled!
+ *                             thresholdprim = 4, 3, 2 or 1
+ *                                             (standing for 1, 3/4, 1/2, 1/4).
+ *                                    Sets the threshold of FIFO to begin dma
+ *                                    transfer on the primary channel.
+ *                             thresholdsec = cf upper, but for secondary channel.
+ *
+ * The following are valid ONLY on ide0, (except dc4030)
  * and the defaults for the base,ctl ports must not be altered.
  *
  * "ide0=dtc2278"      : probe/support DTC2278 interface
@@ -2380,6 +2600,7 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
  * "ide0=qd6580"       : probe/support qd6580 interface
  * "ide0=ali14xx"      : probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
  * "ide0=umc8672"      : probe/support umc8672 chipsets
+ * "idex=dc4030"       : probe/support Promise DC4030VL interface
  */
 __initfunc(void ide_setup (char *s))
 {
@@ -2391,6 +2612,17 @@ __initfunc(void ide_setup (char *s))
        const char max_hwif  = '0' + (MAX_HWIFS - 1);
 
        printk("ide_setup: %s", s);
+
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+       if (!strcmp(s, "ide=doubler")) {
+               extern int ide_doubler;
+
+               printk("ide: Enabled support for IDE doublers\n");
+               ide_doubler = 1;
+               return;
+       }
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
        init_ide_data ();
 
        /*
@@ -2454,6 +2686,58 @@ __initfunc(void ide_setup (char *s))
                }
        }
 
+#if defined(CONFIG_BLK_DEV_VIA82C586)
+       /*
+        *  Look for drive option "splitfifo=..."
+        */
+
+       if (s[0] == 's' && s[1] == 'p' && s[2] == 'l' &&
+           s[3] == 'i' && s[4] == 't' && s[5] == 'f' &&
+           s[6] == 'i' && s[7] == 'f' && s[8] == 'o') {
+               byte tmp = 0x3a;                /* default config byte */
+
+               i = match_parm(&s[9], NULL, vals, 3);
+               switch(i) {
+               case 3: 
+                       tmp &= 0xf0;
+                       if ((vals[1] > 0) && (vals[1] < 5)) {
+                               /* sets threshold for primary Channel: */
+                               byte x = 4 - vals[1];
+                               tmp |= (x << 2);
+                       }
+                       else
+                               goto bad_option;
+                       if ((vals[2] > 0) && (vals[2] < 5)) {
+                               /* sets threshold for secondary Channel: */
+                               byte x = 4 - vals[2];
+                               tmp |= x;
+                       }
+                       else
+                               goto bad_option;
+               case 1:
+                       /* set the FIFO config between channels to 0: */
+                       tmp &= 0x9f;
+                       /* set the needed FIFO config between channels: */
+                       if (vals[0] == 1)       /* primary fifo only */
+                               tmp |= 0x10;
+                       else if (vals[0] == 2)  /* secondary fifo only */
+                               tmp |= 0x70;
+                       else if (vals[0] == 4)  /* other shared fifo config */
+                               tmp |= 0x50;
+                       else if (vals[0] == 3)  /* default config */
+                               tmp |= 0x30;
+                       else
+                               goto bad_option;
+                       break;
+               default:
+                       goto bad_option;
+               }
+               /* set the found option in fifoconfig */
+               fifoconfig = tmp;               
+               goto done;
+       }
+#endif  /* defined(CONFIG_BLK_DEV_VIA82C586) */
+
        if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
                goto bad_option;
        /*
@@ -2487,9 +2771,9 @@ __initfunc(void ide_setup (char *s))
                if (i > 0 || i <= -7) {                 /* is parameter a chipset name? */
                        if (hwif->chipset != ide_unknown)
                                goto bad_option;        /* chipset already specified */
-                       if (i <= -7 && hw != 0)
+                       if (i <= -7 && i != -14 && hw != 0)
                                goto bad_hwif;          /* chipset drivers are for "ide0=" only */
-                       if (i <= -7 && ide_hwifs[hw^1].chipset != ide_unknown)
+                       if (i <= -7 && i != -14 && ide_hwifs[hw+1].chipset != ide_unknown)
                                goto bad_option;        /* chipset for 2nd port already specified */
                        printk("\n");
                }
@@ -2593,8 +2877,9 @@ __initfunc(void ide_setup (char *s))
                        case 2: /* base,ctl */
                                vals[2] = 0;    /* default irq = probe for it */
                        case 3: /* base,ctl,irq */
-                               ide_init_hwif_ports(hwif->io_ports, (ide_ioreg_t) vals[0], &hwif->irq);
-                               hwif->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) vals[1];
+                               hwif->hw.irq = vals[2];
+                               ide_init_hwif_ports(&hwif->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &hwif->irq);
+                               memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
                                hwif->irq      = vals[2];
                                hwif->noprobe  = 0;
                                hwif->chipset  = ide_generic;
@@ -2631,9 +2916,122 @@ done:
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
+#define ANDRIES_GEOMETRY       0
+
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
 {
        ide_drive_t *drive;
+
+#if ANDRIES_GEOMETRY
+       /*
+        * This is the documented list of values (some version of)
+        * OnTrack DM uses.
+        */
+
+       static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+
+       /*
+        * This is a pure phantasy list - known to be incorrect.
+        *
+        * In fact it seems that EZD does not do anything to the CHS
+        * values in the partition table, so whether EZD is present
+        * or not should probably not influence the geometry.
+        */
+
+       static const byte ez_head_vals[] = {4, 8, 16, 32, 64, 128, 240, 255, 0};        const byte *heads;
+       unsigned long tracks;
+
+       drive = get_info_ptr(i_rdev);
+       if (!drive)
+               return 0;
+
+       if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
+               /*
+                * Update the current 3D drive values.
+                */
+               drive->id->cur_cyls     = drive->bios_cyl;
+               drive->id->cur_heads    = drive->bios_head;
+               drive->id->cur_sectors  = drive->bios_sect;
+               return 0;       /* we already have a translation */
+       }
+
+       if (xparm == -1) {
+               int ret = 0;
+#if FAKE_FDISK_FOR_EZDRIVE
+               if (drive->remap_0_to_1 == 0) {
+                       drive->remap_0_to_1 = 1;
+                       printk("%s [remap 0->1]", msg);
+                       msg = NULL;
+                       ret = 1;
+               }
+               if (drive->bios_head > 16)
+#endif /* FAKE_FDISK_FOR_EZDRIVE */
+               {
+                       /*
+                        * Update the current 3D drive values.
+                        */
+                       drive->id->cur_cyls     = drive->bios_cyl;
+                       drive->id->cur_heads    = drive->bios_head;
+                       drive->id->cur_sectors  = drive->bios_sect;
+                       return ret;     /* we already have a translation */
+               }
+       }
+
+       if (msg)
+               printk("%s ", msg);
+
+       if (drive->forced_geom) {
+               /*
+                * Update the current 3D drive values.
+                */
+               drive->id->cur_cyls     = drive->bios_cyl;
+               drive->id->cur_heads    = drive->bios_head;
+               drive->id->cur_sectors  = drive->bios_sect;
+               return 0;
+       }
+
+#if 1
+       /* There used to be code here that assigned drive->id->CHS
+          to drive->CHS and that to drive->bios_CHS. However,
+          some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
+          In such cases that code was wrong.  Moreover,
+          there seems to be no reason to do any of these things. */
+#else
+       if (drive->id) {
+               drive->cyl  = drive->id->cyls;
+               drive->head = drive->id->heads;
+               drive->sect = drive->id->sectors;
+       }
+       drive->bios_cyl  = drive->cyl;
+       drive->bios_head = drive->head;
+       drive->bios_sect = drive->sect;
+       drive->special.b.set_geometry = 1;
+
+#endif
+
+       tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
+       drive->bios_sect = 63;
+       if (xparm > 1) {
+               drive->bios_head = xparm;
+               drive->bios_cyl = tracks / drive->bios_head;
+       } else {
+               heads = (xparm == -1) ? ez_head_vals : dm_head_vals;
+               while (drive->bios_cyl >= 1024) {
+                       drive->bios_head = *heads;
+                       drive->bios_cyl = tracks / drive->bios_head;
+                       if (0 == *++heads)
+                               break;
+               }
+               if (xparm == 1) {
+                       drive->sect0 = 63;
+                       drive->bios_cyl = (tracks - 1) / drive->bios_head;
+                       printk("[remap +63] ");
+               }
+       }
+
+#else /* ANDRIES_GEOMETRY */
+
        static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
        const byte *heads = head_vals;
        unsigned long tracks;
@@ -2708,14 +3106,16 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
                        printk("[remap +63] ");
                }
        }
+#endif /* ANDRIES_GEOMETRY */
+
        drive->part[0].nr_sects = current_capacity(drive);
        printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
        /*
         * Update the current 3D drive values.
         */
-       drive->id->cur_cyls    = drive->bios_cyl;
-       drive->id->cur_heads   = drive->bios_head;
-       drive->id->cur_sectors = drive->bios_sect;
+       drive->id->cur_cyls     = drive->bios_cyl;
+       drive->id->cur_heads    = drive->bios_head;
+       drive->id->cur_sectors  = drive->bios_sect;
        return 1;
 }
 
@@ -2758,6 +3158,42 @@ __initfunc(static void probe_for_hwifs (void))
                pmac_ide_probe();
        }
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
+       {
+               extern void icside_init(void);
+               icside_init();
+       }
+#endif /* CONFIG_BLK_DEV_IDE_ICSIDE */
+#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
+       {
+               extern void rapide_init(void);
+               rapide_init();
+       }
+#endif /* CONFIG_BLK_DEV_IDE_RAPIDE */
+#ifdef CONFIG_BLK_DEV_GAYLE
+       {
+               extern void gayle_init(void);
+               gayle_init();
+       }
+#endif /* CONFIG_BLK_DEV_GAYLE */
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+       {
+               extern void falconide_init(void);
+               falconide_init();
+       }
+#endif /* CONFIG_BLK_DEV_FALCON_IDE */
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+       {
+               extern void macide_init(void);
+               macide_init();
+       }
+#endif /* CONFIG_BLK_DEV_MAC_IDE */
+#ifdef CONFIG_BLK_DEV_BUDDHA
+       {
+               extern void buddha_init(void);
+               buddha_init();
+       }
+#endif /* CONFIG_BLK_DEV_BUDDHA */
 }
 
 __initfunc(void ide_init_builtin_drivers (void))
@@ -3032,6 +3468,12 @@ EXPORT_SYMBOL(do_ide4_request);
 #if MAX_HWIFS > 5
 EXPORT_SYMBOL(do_ide5_request);
 #endif /* MAX_HWIFS > 5 */
+#if MAX_HWIFS > 6
+EXPORT_SYMBOL(do_ide6_request);
+#endif /* MAX_HWIFS > 6 */
+#if MAX_HWIFS > 7
+EXPORT_SYMBOL(do_ide7_request);
+#endif /* MAX_HWIFS > 7 */
 
 /*
  * Driver module
@@ -3056,6 +3498,7 @@ EXPORT_SYMBOL(ide_end_request);
 EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
+EXPORT_SYMBOL(ide_delay_50ms);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(ide_add_proc_entries);
@@ -3065,14 +3508,23 @@ EXPORT_SYMBOL(proc_ide_read_geometry);
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
 
+EXPORT_SYMBOL(ide_register_hw);
 EXPORT_SYMBOL(ide_register);
 EXPORT_SYMBOL(ide_unregister);
+EXPORT_SYMBOL(ide_setup_ports);
 
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
 __initfunc(int ide_init (void))
 {
+       static char banner_printed = 0;
+
+       if (!banner_printed) {
+               printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+               banner_printed = 1;
+       }
+
        init_ide_data ();
 
        initializing = 1;
diff --git a/drivers/block/ide.h b/drivers/block/ide.h
deleted file mode 100644 (file)
index 52bb4e2..0000000
+++ /dev/null
@@ -1,769 +0,0 @@
-#ifndef _IDE_H
-#define _IDE_H
-/*
- *  linux/drivers/block/ide.h
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <asm/ide.h>
-
-/*
- * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
- * There can be up to two drives per interface, as per the ATA-2 spec.
- *
- * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
- * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
- * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
- * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
- */
-
-/******************************************************************************
- * IDE driver configuration options (play with these as desired):
- *
- * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
- */
-#undef REALLY_FAST_IO                  /* define if ide ports are perfect */
-#define INITIAL_MULT_COUNT     0       /* off=0; on=2,4,8,16,32, etc.. */
-
-#ifndef SUPPORT_SLOW_DATA_PORTS                /* 1 to support slow data ports */
-#define SUPPORT_SLOW_DATA_PORTS        1       /* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_VLB_SYNC               /* 1 to support weird 32-bit chips */
-#define SUPPORT_VLB_SYNC       1       /* 0 to reduce kernel size */
-#endif
-#ifndef DISK_RECOVERY_TIME             /* off=0; on=access_delay_time */
-#define DISK_RECOVERY_TIME     0       /*  for hardware that needs it */
-#endif
-#ifndef OK_TO_RESET_CONTROLLER         /* 1 needed for good error recovery */
-#define OK_TO_RESET_CONTROLLER 1       /* 0 for use with AH2372A/B interface */
-#endif
-#ifndef FAKE_FDISK_FOR_EZDRIVE         /* 1 to help linux fdisk with EZDRIVE */
-#define FAKE_FDISK_FOR_EZDRIVE         1       /* 0 to reduce kernel size */
-#endif
-#ifndef FANCY_STATUS_DUMPS             /* 1 for human-readable drive errors */
-#define FANCY_STATUS_DUMPS     1       /* 0 to reduce kernel size */
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD640
-#if 0  /* change to 1 when debugging cmd640 problems */
-void cmd640_dump_regs (void);
-#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
-#endif
-#endif  /* CONFIG_BLK_DEV_CMD640 */
-
-/*
- * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
- */
-#define IDE_DRIVE_CMD          99      /* (magic) undef to reduce kernel size*/
-
-/*
- *  "No user-serviceable parts" beyond this point  :)
- *****************************************************************************/
-
-typedef unsigned char  byte;   /* used everywhere */
-
-/*
- * Probably not wise to fiddle with these
- */
-#define ERROR_MAX      8       /* Max read/write errors per sector */
-#define ERROR_RESET    3       /* Reset controller every 4th retry */
-#define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
-
-/*
- * Ensure that various configuration flags have compatible settings
- */
-#ifdef REALLY_SLOW_IO
-#undef REALLY_FAST_IO
-#endif
-
-#define HWIF(drive)            ((ide_hwif_t *)((drive)->hwif))
-#define HWGROUP(drive)         ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
-
-/*
- * Definitions for accessing IDE controller registers
- */
-#define IDE_NR_PORTS           (10)
-
-#define IDE_DATA_OFFSET                (0)
-#define IDE_ERROR_OFFSET       (1)
-#define IDE_NSECTOR_OFFSET     (2)
-#define IDE_SECTOR_OFFSET      (3)
-#define IDE_LCYL_OFFSET                (4)
-#define IDE_HCYL_OFFSET                (5)
-#define IDE_SELECT_OFFSET      (6)
-#define IDE_STATUS_OFFSET      (7)
-#define IDE_CONTROL_OFFSET     (8)
-#define IDE_IRQ_OFFSET         (9)
-
-#define IDE_FEATURE_OFFSET     IDE_ERROR_OFFSET
-#define IDE_COMMAND_OFFSET     IDE_STATUS_OFFSET
-
-#define IDE_DATA_REG           (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG          (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG                (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG         (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG           (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG           (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG         (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG         (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG                (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
-#define IDE_IRQ_REG            (HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
-
-#define IDE_FEATURE_REG                IDE_ERROR_REG
-#define IDE_COMMAND_REG                IDE_STATUS_REG
-#define IDE_ALTSTATUS_REG      IDE_CONTROL_REG
-#define IDE_IREASON_REG                IDE_NSECTOR_REG
-#define IDE_BCOUNTL_REG                IDE_LCYL_REG
-#define IDE_BCOUNTH_REG                IDE_HCYL_REG
-
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)          outb((b),(p))
-#define IN_BYTE(p)             (byte)inb(p)
-#else
-#define OUT_BYTE(b,p)          outb_p((b),(p))
-#define IN_BYTE(p)             (byte)inb_p(p)
-#endif /* REALLY_FAST_IO */
-
-#define GET_ERR()              IN_BYTE(IDE_ERROR_REG)
-#define GET_STAT()             IN_BYTE(IDE_STATUS_REG)
-#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
-#define BAD_R_STAT             (BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT             (BAD_R_STAT  | WRERR_STAT)
-#define BAD_STAT               (BAD_R_STAT  | DRQ_STAT)
-#define DRIVE_READY            (READY_STAT  | SEEK_STAT)
-#define DATA_READY             (DRQ_STAT)
-
-/*
- * Some more useful definitions
- */
-#define IDE_MAJOR_NAME "ide"   /* the same for all i/f; see also genhd.c */
-#define MAJOR_NAME     IDE_MAJOR_NAME
-#define PARTN_BITS     6       /* number of minor dev bits for partitions */
-#define PARTN_MASK     ((1<<PARTN_BITS)-1)     /* a useful bit mask */
-#define MAX_DRIVES     2       /* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS   (512 / 4)       /* number of 32bit words per sector */
-#define IDE_LARGE_SEEK(b1,b2,t)        (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
-#define IDE_MIN(a,b)   ((a)<(b) ? (a):(b))
-#define IDE_MAX(a,b)   ((a)>(b) ? (a):(b))
-
-/*
- * Timeouts for various operations:
- */
-#define WAIT_DRQ       (5*HZ/100)      /* 50msec - spec allows up to 20ms */
-#ifdef CONFIG_APM
-#define WAIT_READY     (5*HZ)          /* 5sec - some laptops are very slow */
-#else
-#define WAIT_READY     (3*HZ/100)      /* 30msec - should be instantaneous */
-#endif /* CONFIG_APM */
-#define WAIT_PIDENTIFY (10*HZ) /* 10sec  - should be less than 3ms (?)
-                                           if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE (30*HZ) /* 30sec  - worst case when spinning up */
-#define WAIT_CMD       (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
-#define WAIT_MIN_SLEEP (2*HZ/100)      /* 20msec - minimum sleep time */
-
-#define SELECT_DRIVE(hwif,drive)                               \
-{                                                              \
-       if (hwif->selectproc)                                   \
-               hwif->selectproc(drive);                        \
-       OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
-}
-
-/*
- * Now for the data we need to maintain per-drive:  ide_drive_t
- */
-
-#define ide_scsi       0x21
-#define ide_disk       0x20
-#define ide_optical    0x7
-#define ide_cdrom      0x5
-#define ide_tape       0x1
-#define ide_floppy     0x0
-
-typedef union {
-       unsigned all                    : 8;    /* all of the bits together */
-       struct {
-               unsigned set_geometry   : 1;    /* respecify drive geometry */
-               unsigned recalibrate    : 1;    /* seek to cyl 0      */
-               unsigned set_multmode   : 1;    /* set multmode count */
-               unsigned set_tune       : 1;    /* tune interface for drive */
-               unsigned reserved       : 4;    /* unused */
-               } b;
-       } special_t;
-
-typedef struct ide_drive_s {
-       struct request          *queue; /* request queue */
-       struct ide_drive_s      *next;  /* circular list of hwgroup drives */
-       unsigned long sleep;            /* sleep until this time */
-       unsigned long service_start;    /* time we started last request */
-       unsigned long service_time;     /* service time of last request */
-       special_t       special;        /* special action flags */
-       byte     keep_settings;         /* restore settings after drive reset */
-       byte     using_dma;             /* disk is using dma for read/write */
-       byte     waiting_for_dma;       /* dma currently in progress */
-       byte     unmask;                /* flag: okay to unmask other irqs */
-       byte     slow;                  /* flag: slow data port */
-       byte     bswap;                 /* flag: byte swap data */
-       byte     dsc_overlap;           /* flag: DSC overlap */
-       byte     nice1;                 /* flag: give potential excess bandwidth */
-       unsigned present        : 1;    /* drive is physically present */
-       unsigned noprobe        : 1;    /* from:  hdx=noprobe */
-       unsigned busy           : 1;    /* currently doing revalidate_disk() */
-       unsigned removable      : 1;    /* 1 if need to do check_media_change */
-       unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
-       unsigned no_unmask      : 1;    /* disallow setting unmask bit */
-       unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
-       unsigned nobios         : 1;    /* flag: do not probe bios for drive */
-       unsigned revalidate     : 1;    /* request revalidation */
-       unsigned atapi_overlap  : 1;    /* flag: ATAPI overlap (not supported) */
-       unsigned nice0          : 1;    /* flag: give obvious excess bandwidth */
-       unsigned nice2          : 1;    /* flag: give a share in our own bandwidth */
-       unsigned doorlocking    : 1;    /* flag: for removable only: door lock/unlock works */
-       unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
-#if FAKE_FDISK_FOR_EZDRIVE
-       unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
-       byte            media;          /* disk, cdrom, tape, floppy, ... */
-       select_t        select;         /* basic drive/head select reg value */
-       byte            ctl;            /* "normal" value for IDE_CONTROL_REG */
-       byte            ready_stat;     /* min status value for drive ready */
-       byte            mult_count;     /* current multiple sector setting */
-       byte            mult_req;       /* requested multiple sector setting */
-       byte            tune_req;       /* requested drive tuning setting */
-       byte            io_32bit;       /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-       byte            bad_wstat;      /* used for ignoring WRERR_STAT */
-       byte            nowerr;         /* used for ignoring WRERR_STAT */
-       byte            sect0;          /* offset of first sector for DM6:DDO */
-       byte            usage;          /* current "open()" count for drive */
-       byte            head;           /* "real" number of heads */
-       byte            sect;           /* "real" sectors per track */
-       byte            bios_head;      /* BIOS/fdisk/LILO number of heads */
-       byte            bios_sect;      /* BIOS/fdisk/LILO sectors per track */
-       unsigned short  bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
-       unsigned short  cyl;            /* "real" number of cyls */
-       unsigned int    drive_data;     /* for use by tuneproc/selectproc as needed */
-       void              *hwif;        /* actually (ide_hwif_t *) */
-       wait_queue_head_t wqueue;       /* used to wait for drive in open() */
-       struct hd_driveid *id;          /* drive model identification info */
-       struct hd_struct  *part;        /* drive partition table */
-       char            name[4];        /* drive name, such as "hda" */
-       void            *driver;        /* (ide_driver_t *) */
-       void            *driver_data;   /* extra driver data */
-       struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
-       void            *settings;      /* /proc/ide/ drive settings */
-       char            driver_req[10]; /* requests specific driver */
-       } ide_drive_t;
-
-/*
- * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case the caller
- * should either try again later, or revert to PIO for the current request.
- */
-typedef enum { ide_dma_read,   ide_dma_write,  ide_dma_begin,  ide_dma_end,
-               ide_dma_check,  ide_dma_on,     ide_dma_off,    ide_dma_off_quietly,
-               ide_dma_test_irq
-       } ide_dma_action_t;
-
-typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
-
-
-/*
- * An ide_tuneproc_t() is used to set the speed of an IDE interface
- * to a particular PIO mode.  The "byte" parameter is used
- * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
- * indicates that the interface driver should "auto-tune" the PIO mode
- * according to the drive capabilities in drive->id;
- *
- * Not all interface types support tuning, and not all of those
- * support all possible PIO settings.  They may silently ignore
- * or round values as they see fit.
- */
-typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
-
-/*
- * This is used to provide support for strange interfaces
- */
-typedef void (ide_selectproc_t) (ide_drive_t *);
-
-/*
- * hwif_chipset_t is used to keep track of the specific hardware
- * chipset used by each IDE interface, if known.
- */
-typedef enum { ide_unknown,    ide_generic,    ide_pci,
-               ide_cmd640,     ide_dtc2278,    ide_ali14xx,
-               ide_qd6580,     ide_umc8672,    ide_ht6560b,
-               ide_pdc4030,    ide_rz1000,     ide_trm290,
-               ide_cmd646,     ide_4drives
-       } hwif_chipset_t;
-
-typedef struct ide_pci_devid_s {
-       unsigned short  vid;
-       unsigned short  did;
-} ide_pci_devid_t;
-
-#define IDE_PCI_DEVID_NULL     ((ide_pci_devid_t){0,0})
-#define IDE_PCI_DEVID_EQ(a,b)  (a.vid == b.vid && a.did == b.did)
-
-typedef struct hwif_s {
-       struct hwif_s   *next;          /* for linked-list in ide_hwgroup_t */
-       void            *hwgroup;       /* actually (ide_hwgroup_t *) */
-       ide_ioreg_t     io_ports[IDE_NR_PORTS]; /* task file registers */
-       ide_drive_t     drives[MAX_DRIVES];     /* drive info */
-       struct gendisk  *gd;            /* gendisk structure */
-       ide_tuneproc_t  *tuneproc;      /* routine to tune PIO mode for drives */
-       ide_selectproc_t *selectproc;   /* tweaks hardware to select drive */
-       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 long   dma_base;       /* base addr for dma ports */
-       unsigned        dma_extra;      /* extra 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 */
-       char            name[6];        /* name of interface, eg. "ide0" */
-       byte            index;          /* 0 for ide0; 1 for ide1; ... */
-       hwif_chipset_t  chipset;        /* sub-module for tuning.. */
-       unsigned        noprobe    : 1; /* don't probe for this interface */
-       unsigned        present    : 1; /* this interface exists */
-       unsigned        serialized : 1; /* serialized operation with mate hwif */
-       unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
-       unsigned        reset      : 1; /* reset after probe */
-       unsigned        autodma    : 1; /* automatically try to enable DMA at boot */
-       byte            channel;        /* for dual-port chips: 0=primary, 1=secondary */
-       struct pci_dev  *pci_dev;       /* for pci chipsets */
-       ide_pci_devid_t pci_devid;      /* for pci chipsets: {VID,DID} */
-#if (DISK_RECOVERY_TIME > 0)
-       unsigned long   last_time;      /* time when previous rq was done */
-#endif
-       } ide_hwif_t;
-
-/*
- *  internal ide interrupt handler type
- */
-typedef void (ide_handler_t)(ide_drive_t *);
-
-typedef struct hwgroup_s {
-       spinlock_t              spinlock; /* protects "busy" and "handler" */
-       ide_handler_t           *handler;/* irq handler, if active */
-       int                     busy;   /* BOOL: protects all fields below */
-       ide_drive_t             *drive; /* current drive */
-       ide_hwif_t              *hwif;  /* ptr to current hwif in linked-list */
-       struct request          *rq;    /* current request */
-       struct timer_list       timer;  /* failsafe timer */
-       struct request          wrq;    /* local copy of current write rq */
-       unsigned long           poll_timeout;   /* timeout value during long polls */
-       } ide_hwgroup_t;
-
-/*
- * configurable drive settings
- */
-
-#define TYPE_INT       0
-#define TYPE_INTA      1
-#define TYPE_BYTE      2
-#define TYPE_SHORT     3
-
-#define SETTING_READ   (1 << 0)
-#define SETTING_WRITE  (1 << 1)
-#define SETTING_RW     (SETTING_READ | SETTING_WRITE)
-
-typedef int (ide_procset_t)(ide_drive_t *, int);
-typedef struct ide_settings_s {
-       char                    *name;
-       int                     rw;
-       int                     read_ioctl;
-       int                     write_ioctl;
-       int                     data_type;
-       int                     min;
-       int                     max;
-       int                     mul_factor;
-       int                     div_factor;
-       void                    *data;
-       ide_procset_t           *set;
-       int                     auto_remove;
-       struct ide_settings_s   *next;
-} ide_settings_t;
-
-void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set);
-void ide_remove_setting(ide_drive_t *drive, char *name);
-ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name);
-int ide_read_setting(ide_drive_t *t, ide_settings_t *setting);
-int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val);
-void ide_add_generic_settings(ide_drive_t *drive);
-
-/*
- * /proc/ide interface
- */
-typedef struct {
-       const char      *name;
-       mode_t          mode;
-       read_proc_t     *read_proc;
-       write_proc_t    *write_proc;
-} ide_proc_entry_t;
-
-#ifdef CONFIG_PROC_FS
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
-read_proc_t proc_ide_read_capacity;
-read_proc_t proc_ide_read_geometry;
-
-/*
- * Standard exit stuff:
- */
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
-{                                      \
-       len -= off;                     \
-       if (len < count) {              \
-               *eof = 1;               \
-               if (len <= 0)           \
-                       return 0;       \
-       } else                          \
-               len = count;            \
-       *start = page + off;            \
-       return len;                     \
-}
-#else
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
-#endif
-
-/*
- * Subdrivers support.
- */
-#define IDE_SUBDRIVER_VERSION  1
-
-typedef int    (ide_cleanup_proc)(ide_drive_t *);
-typedef void   (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
-typedef void   (ide_end_request_proc)(byte, ide_hwgroup_t *);
-typedef int    (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-typedef int    (ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef void   (ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef int    (ide_check_media_change_proc)(ide_drive_t *);
-typedef void   (ide_pre_reset_proc)(ide_drive_t *);
-typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
-typedef void   (ide_special_proc)(ide_drive_t *);
-typedef void   (ide_setting_proc)(ide_drive_t *);
-
-typedef struct ide_driver_s {
-       const char                      *name;
-       const char                      *version;
-       byte                            media;
-       unsigned busy                   : 1;
-       unsigned supports_dma           : 1;
-       unsigned supports_dsc_overlap   : 1;
-       ide_cleanup_proc                *cleanup;
-       ide_do_request_proc             *do_request;
-       ide_end_request_proc            *end_request;
-       ide_ioctl_proc                  *ioctl;
-       ide_open_proc                   *open;
-       ide_release_proc                *release;
-       ide_check_media_change_proc     *media_change;
-       ide_pre_reset_proc              *pre_reset;
-       ide_capacity_proc               *capacity;
-       ide_special_proc                *special;
-       ide_proc_entry_t                *proc;
-       } ide_driver_t;
-
-#define DRIVER(drive)          ((ide_driver_t *)((drive)->driver))
-
-/*
- * IDE modules.
- */
-#define IDE_CHIPSET_MODULE             0       /* not supported yet */
-#define IDE_PROBE_MODULE               1
-#define IDE_DRIVER_MODULE              2
-
-typedef int    (ide_module_init_proc)(void);
-
-typedef struct ide_module_s {
-       int                             type;
-       ide_module_init_proc            *init;
-       void                            *info;
-       struct ide_module_s             *next;
-} ide_module_t;
-
-/*
- * ide_hwifs[] is the master data structure used to keep track
- * of just about everything in ide.c.  Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or
- * pointers to a hwif (ide_hwif_t *), rather than indexing this
- * structure directly (the allocation/layout may change!).
- *
- */
-#ifndef _IDE_C
-extern ide_hwif_t      ide_hwifs[];            /* master data repository */
-extern  ide_module_t   *ide_modules;
-#endif
-
-/*
- * We need blk.h, but we replace its end_request by our own version.
- */
-#define IDE_DRIVER             /* Toggle some magic bits in blk.h */
-#define LOCAL_END_REQUEST      /* Don't generate end_request in blk.h */
-#include <linux/blk.h>
-
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
-
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-
-/*
- * This is used on exit from the driver, to designate the next irq handler
- * and also to start the safety timer.
- */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout);
-
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
-
-/*
- * ide_error() takes action based on the error returned by the controller.
- * The calling function must return afterwards, to restart the request.
- */
-void ide_error (ide_drive_t *drive, const char *msg, byte stat);
-
-/*
- * Issue a simple drive command
- * The drive must be selected beforehand.
- */
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
-
-/*
- * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
- * removing leading/trailing blanks and compressing internal blanks.
- * It is primarily used to tidy up the model name/number fields as
- * returned by the WIN_[P]IDENTIFY commands.
- */
-void ide_fixstring (byte *s, const int bytecount, const int byteswap);
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should return.
- *
- */
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
-
-/*
- * This routine is called from the partition-table code in genhd.c
- * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
- *
- * The second parameter, "xparm", determines exactly how the translation
- * will be handled:
- *              0 = convert to CHS with fewer than 1024 cyls
- *                     using the same method as Ontrack DiskManager.
- *              1 = same as "0", plus offset everything by 63 sectors.
- *             -1 = similar to "0", plus redirect sector 0 to sector 1.
- *             >1 = convert to a CHS geometry with "xparm" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
- */
-int ide_xlate_1024 (kdev_t, int, const char *);
-
-/*
- * Start a reset operation for an IDE interface.
- * The caller should return immediately after invoking this.
- */
-void ide_do_reset (ide_drive_t *);
-
-/*
- * This function is intended to be used prior to invoking ide_do_drive_cmd().
- */
-void ide_init_drive_cmd (struct request *rq);
-
-/*
- * "action" parameter type for ide_do_drive_cmd() below.
- */
-typedef enum
-       {ide_wait,      /* insert rq at end of list, and wait for it */
-        ide_next,      /* insert rq immediately after current request */
-        ide_preempt,   /* insert rq in front of current request */
-        ide_end}       /* insert rq at end of list, but don't wait for it */
- ide_action_t;
-
-/*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
- */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
-
-/*
- * Clean up after success/failure of an explicit drive cmd.
- * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
- */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
-
-/*
- * Issue ATA command and wait for completion.
- */
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
-
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- */
-int ide_system_bus_speed (void);
-
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-void ide_multwrite (ide_drive_t *drive, unsigned int mcount);
-
-/*
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the hwgroup by sleeping for timeout jiffies.
- */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
-
-/*
- * ide_get_queue() returns the queue which corresponds to a given device.
- */
-struct request **ide_get_queue (kdev_t dev);
-
-/*
- * CompactFlash cards and their brethern pretend to be removable hard disks,
- * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
- */
-int drive_is_flashcard (ide_drive_t *drive);
-
-int  ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags);
-void ide_timer_expiry (unsigned long data);
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
-void ide_geninit (struct gendisk *gd);
-void do_ide0_request (void);
-#if MAX_HWIFS > 1
-void do_ide1_request (void);
-#endif
-#if MAX_HWIFS > 2
-void do_ide2_request (void);
-#endif
-#if MAX_HWIFS > 3
-void do_ide3_request (void);
-#endif
-#if MAX_HWIFS > 4
-void do_ide4_request (void);
-#endif
-#if MAX_HWIFS > 5
-void do_ide5_request (void);
-#endif
-void ide_init_subdrivers (void);
-
-#ifndef _IDE_C
-extern struct file_operations ide_fops[];
-#endif
-
-#ifdef _IDE_C
-#ifdef CONFIG_BLK_DEV_IDE
-int ideprobe_init (void);
-#endif /* CONFIG_BLK_DEV_IDE */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-int idedisk_init (void);
-#endif /* CONFIG_BLK_DEV_IDEDISK */
-#ifdef CONFIG_BLK_DEV_IDECD
-int ide_cdrom_init (void);
-#endif /* CONFIG_BLK_DEV_IDECD */
-#ifdef CONFIG_BLK_DEV_IDETAPE
-int idetape_init (void);
-#endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-int idefloppy_init (void);
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-int idescsi_init (void);
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-#endif /* _IDE_C */
-
-int ide_register_module (ide_module_t *module);
-void ide_unregister_module (ide_module_t *module);
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
-int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
-int ide_unregister_subdriver (ide_drive_t *drive);
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-#define ON_BOARD               1
-#define NEVER_BOARD            0
-#ifdef CONFIG_BLK_DEV_OFFBOARD
-#  define OFF_BOARD            ON_BOARD
-#else /* CONFIG_BLK_DEV_OFFBOARD */
-#  define OFF_BOARD            NEVER_BOARD
-#endif /* CONFIG_BLK_DEV_OFFBOARD */
-
-unsigned long ide_find_free_region (unsigned short size) __init;
-void ide_scan_pcibus (void) __init;
-#endif
-#ifdef CONFIG_BLK_DEV_IDEDMA
-#define BAD_DMA_DRIVE          0
-#define GOOD_DMA_DRIVE         1
-int ide_build_dmatable (ide_drive_t *drive);
-void ide_dma_intr  (ide_drive_t *drive);
-int check_drive_lists (ide_drive_t *drive, int good_bad);
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-int ide_release_dma (ide_hwif_t *hwif);
-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_PDC4030
-#include "pdc4030.h"
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
-#else
-#define IS_PDC4030_DRIVE (0)   /* auto-NULLs out pdc4030 code */
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-
-#endif /* _IDE_H */
index 49a4997e38bc61c4188eb99433fd91d8963589bd..d8c8a714432082e5a6435f411f036ae7717c4606 100644 (file)
@@ -15,7 +15,7 @@
  * breaking the fragile cmd640.c support.
  */
 
-#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) || defined(CONFIG_BLK_DEV_IDE_PMAC)
+#ifdef CONFIG_BLK_DEV_IDE_MODES
 
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
@@ -111,6 +111,8 @@ static struct ide_pio_info {
        { "ST3600A",  1 },
        { "ST3290A",  0 },
        { "ST3144A",  0 },
+       { "ST3491A",  1 },      /* reports 3, should be 1 or 2 (depending on */ 
+                               /* drive) according to Seagates FIND-ATA program */
 
        { "QUANTUM ELS127A", 0 },
        { "QUANTUM ELS170A", 0 },
@@ -222,5 +224,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) || defined(CONFIG_BLK_DEV_OPTI621) */
+#endif /* CONFIG_BLK_DEV_IDE_MODES */
 #endif /* _IDE_MODES_H */
diff --git a/drivers/block/macide.c b/drivers/block/macide.c
new file mode 100644 (file)
index 0000000..2771ea7
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  linux/drivers/block/macide.c -- Macintosh IDE Driver
+ *
+ *     Copyright (C) 1998 by Michael Schmitz
+ *
+ *  This driver was written based on information obtained from the MacOS IDE
+ *  driver binary by Mikael Forselius
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+
+    /*
+     *  Base of the IDE interface (see ATAManager ROM code)
+     */
+
+#define MAC_HD_BASE    0x50f1a000
+
+    /*
+     *  Offsets from the above base (scaling 4)
+     */
+
+#define MAC_HD_DATA    0x00
+#define MAC_HD_ERROR   0x04            /* see err-bits */
+#define MAC_HD_NSECTOR 0x08            /* nr of sectors to read/write */
+#define MAC_HD_SECTOR  0x0c            /* starting sector */
+#define MAC_HD_LCYL    0x10            /* starting cylinder */
+#define MAC_HD_HCYL    0x14            /* high byte of starting cyl */
+#define MAC_HD_SELECT  0x18            /* 101dhhhh , d=drive, hhhh=head */
+#define MAC_HD_STATUS  0x1c            /* see status-bits */
+#define MAC_HD_CONTROL 0x38            /* control/altstatus */
+
+static int macide_offsets[IDE_NR_PORTS] = {
+    MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL,
+    MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL
+};
+
+       /*
+        * Other registers
+        */
+
+       /* 
+        * IDE interrupt status register for both (?) hwifs on Quadra
+        * Initial setting: 0xc
+        * Guessing again:
+        * Bit 0+1: some interrupt flags
+        * Bit 2+3: some interrupt enable
+        * Bit 4:   ??
+        * Bit 5:   IDE interrupt flag (any hwif)
+        * Bit 6:   maybe IDE interrupt enable (any hwif) ??
+        * Bit 7:   Any interrupt condition
+        *
+        * Only relevant item: bit 5, to be checked by mac_ack_intr
+        */
+
+#define MAC_HD_ISR     0x101
+
+       /*
+        * IDE interrupt glue - seems to be wired to Nubus, Slot C?
+        * (ROM code disassembly again)
+        * First try: just use Nubus interrupt for Slot C. Have Nubus code call
+        * a wrapper to ide_intr that checks the ISR (see above).
+        * Need to #define IDE_IRQ_NUBUS though.
+        * Alternative method: set a mac_ide_hook function pointer to the wrapper 
+        * here and have via_do_nubus call that hook if set. 
+        *
+        * Quadra needs the hook, Powerbook can use Nubus slot C. 
+        * Checking the ISR on Quadra is done by mac_ack_intr (see Amiga code). mac_ide_intr
+        * mac_ide_intr is obsolete except for providing the hwgroup argument.
+        */
+
+       /* The Mac hwif data, for passing hwgroup to ide_intr */
+static ide_hwif_t *mac_hwif = NULL;
+
+       /* The function pointer used in the Nubus handler */
+void (*mac_ide_intr_hook)(int, void *, struct pt_regs *) = NULL;
+
+       /*
+        * Only purpose: feeds the hwgroup to the main IDE handler. 
+        * Obsolete as soon as Nubus code is fixed WRT pseudo slot C int.
+        * (should be the case on Powerbooks)
+        * Alas, second purpose: feed correct irq to IDE handler (I know,
+        * that's cheating) :-(((
+        * Fix needed for interrupt code: accept Nubus ints in the regular
+        * request_irq code, then register Powerbook IDE as Nubus slot C, 
+        * Quadra as slot F (F for fictious).
+        */
+void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs);
+}
+
+    /*
+     *  Check the interrupt status
+     *
+     *  Note: In 2.0 kernels, there have been timing problems with the 
+     *  Powerbook IDE interface (BUSY was asserted too long after the
+     *  interrupt triggered). Result: repeated errors, recalibrate etc. 
+     *  Adding a wait loop to read_intr, write_intr and set_geom_intr
+     *  fixed the problem (waits in read/write_intr were present for Amiga
+     *  already). 
+     *  Powerbooks were not tested with 2.1 due to lack of FPU emulation
+     *  (thanks Apple for using LC040). If the BUSY problem resurfaces in 
+     *  2.1, my best bet would be to add the wait loop right here, afterr
+     *  checking the interrupt register.
+     */
+
+static int mac_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x20))
+       return 0;
+    return 1;
+}
+
+    /*
+     *  Probe for a Macintosh IDE interface
+     */
+
+void macide_init(void)
+{
+    hw_regs_t hw;
+    int index = -1;
+
+    if (MACH_IS_MAC) {
+       switch(macintosh_config->ide_type) {
+       case 0:
+           break;
+
+       case MAC_IDE_QUADRA:
+           ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets,
+                           0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR),
+                           mac_ack_intr, IRQ_MAC_NUBUS);
+           index = ide_register_hw(&hw, &mac_hwif);
+           mac_ide_intr_hook = mac_ide_intr;
+           break;
+
+       default:
+           ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets,
+                           0, 0, NULL, IRQ_MAC_NUBUS);
+           index = ide_register_hw(&hw, &mac_hwif);
+           break;
+       }
+
+        if (index != -1) {
+           if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+               printk("ide%d: Macintosh Quadra IDE interface\n", index);
+           else
+               printk("ide%d: Macintosh Powerbook IDE interface\n", index);
+       }
+    }
+}
index 3275c017132d8c04b895cd9ae40b3ff77cebe618..439e288a1672511ebe8aac53fd56074359df0e00 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <asm/io.h>
-#include "ide.h"
+#include <linux/ide.h>
 
+#include <asm/io.h>
 
 static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 
index bc2cf8949d4b3b4fac5d04ae9b50cd266ec081f8..0885ed49e539bfdff8f04041c77c270ae178ccc7 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 #define OPTI621_MAX_PIO 3
diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c
new file mode 100644 (file)
index 0000000..cbd8365
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ *  linux/drivers/block/pdc202xx.c     Version 0.26    May 12, 1999
+ *
+ *  Copyright (C) 1998-99      Andre Hedrick
+ *                                     (hedrick@astro.dyer.vanderbilt.edu)
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "PDC202XX_FORCE_BURST_BIT"
+ *
+ *  There is only one BIOS in the three contollers.
+ *
+ *  May  8 20:56:17 Orion kernel:
+ *  Uniform Multi-Platform E-IDE driver Revision: 6.19
+ *  PDC20246: IDE controller on PCI bus 00 dev a0
+ *  PDC20246: not 100% native mode: will probe irqs later
+ *  PDC20246: ROM enabled at 0xfebd0000
+ *  PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
+ *      ide0: BM-DMA at 0xef80-0xef87, BIOS settings: hda:DMA, hdb:DMA
+ *      ide1: BM-DMA at 0xef88-0xef8f, BIOS settings: hdc:pio, hdd:pio
+ *  PDC20246: IDE controller on PCI bus 00 dev 98
+ *  PDC20246: not 100% native mode: will probe irqs later
+ *  PDC20246: ROM enabled at 0xfebc0000
+ *  PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
+ *      ide2: BM-DMA at 0xef40-0xef47, BIOS settings: hde:DMA, hdf:DMA
+ *      ide3: BM-DMA at 0xef48-0xef4f, BIOS settings: hdg:DMA, hdh:DMA
+ *  PDC20246: IDE controller on PCI bus 00 dev 90
+ *  PDC20246: not 100% native mode: will probe irqs later
+ *  PDC20246: ROM enabled at 0xfebb0000
+ *  PDC20246: (U)DMA Burst Bit DISABLED Primary PCI Mode Secondary PCI Mode.
+ *  PDC20246: FORCING BURST BIT 0x00 -> 0x01 ACTIVE
+ *      ide4: BM-DMA at 0xef00-0xef07, BIOS settings: hdi:DMA, hdj:pio
+ *      ide5: BM-DMA at 0xef08-0xef0f, BIOS settings: hdk:pio, hdl:pio
+ *  PIIX3: IDE controller on PCI bus 00 dev 39
+ *  PIIX3: device not capable of full native PCI mode
+ *
+ *  ide0 at 0xeff0-0xeff7,0xefe6 on irq 19
+ *  ide1 at 0xefa8-0xefaf,0xebe6 on irq 19
+ *  ide2 at 0xefa0-0xefa7,0xef7e on irq 18
+ *  ide3 at 0xef68-0xef6f,0xef66 on irq 18
+ *  ide4 at 0xef38-0xef3f,0xef62 on irq 17
+ *  hda: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=13328/15/63, UDMA(33)
+ *  hdb: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=6256/16/63, UDMA(33)
+ *  hde: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=3893/16/63, DMA
+ *  hdf: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=3158/16/63, DMA
+ *  hdi: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
+ *  hdj: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  PDC20262: IDE controller on PCI bus 00 dev a0
+ *  PDC20262: not 100% native mode: will probe irqs later
+ *  PDC20262: ROM enabled at 0xfebb0000
+ *  PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
+ *      ide0: BM-DMA at 0xef00-0xef07, BIOS settings: hda:pio, hdb:pio
+ *      ide1: BM-DMA at 0xef08-0xef0f, BIOS settings: hdc:pio, hdd:pio
+ *
+ *  UDMA 4/2 and UDMA 3/1 only differ by the testing bit 13 in word93.
+ *  Chipset timing speeds must be identical
+ *
+ *  drive_number
+ *      = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *      = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/config.h>      /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define PDC202XX_DEBUG_DRIVE_INFO              0
+#define PDC202XX_DECODE_REGISTER_INFO          0
+#define PDC202XX_FORCE_BURST_BIT               0
+#define PDC202XX_FORCE_MASTER_MODE             0
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/* A Register */
+#define        SYNC_ERRDY_EN   0xC0
+
+#define        SYNC_IN         0x80    /* control bit, different for master vs. slave drives */
+#define        ERRDY_EN        0x40    /* control bit, different for master vs. slave drives */
+#define        IORDY_EN        0x20    /* PIO: IOREADY */
+#define        PREFETCH_EN     0x10    /* PIO: PREFETCH */
+
+#define        PA3             0x08    /* PIO"A" timing */
+#define        PA2             0x04    /* PIO"A" timing */
+#define        PA1             0x02    /* PIO"A" timing */
+#define        PA0             0x01    /* PIO"A" timing */
+
+/* B Register */
+
+#define        MB2             0x80    /* DMA"B" timing */
+#define        MB1             0x40    /* DMA"B" timing */
+#define        MB0             0x20    /* DMA"B" timing */
+
+#define        PB4             0x10    /* PIO_FORCE 1:0 */
+
+#define        PB3             0x08    /* PIO"B" timing */     /* PIO flow Control mode */
+#define        PB2             0x04    /* PIO"B" timing */     /* PIO 4 */
+#define        PB1             0x02    /* PIO"B" timing */     /* PIO 3 half */
+#define        PB0             0x01    /* PIO"B" timing */     /* PIO 3 other half */
+
+/* C Register */
+#define        IORDYp_NO_SPEED 0x4F
+#define        SPEED_DIS       0x0F
+
+#define        DMARQp          0x80
+#define        IORDYp          0x40
+#define        DMAR_EN         0x20
+#define        DMAW_EN         0x10
+
+#define        MC3             0x08    /* DMA"C" timing */
+#define        MC2             0x04    /* DMA"C" timing */
+#define        MC1             0x02    /* DMA"C" timing */
+#define        MC0             0x01    /* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A          0x01
+#define REG_B          0x02
+#define REG_C          0x04
+#define REG_D          0x08
+
+static void decode_registers (byte registers, byte value)
+{
+       byte    bit = 0, bit1 = 0, bit2 = 0;
+
+       switch(registers) {
+               case REG_A:
+                       bit2 = 0;
+                       printk("A Register ");
+                       if (value & 0x80) printk("SYNC_IN ");
+                       if (value & 0x40) printk("ERRDY_EN ");
+                       if (value & 0x20) printk("IORDY_EN ");
+                       if (value & 0x10) printk("PREFETCH_EN ");
+                       if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+                       if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+                       if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+                       if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+                       printk("PIO(A) = %d ", bit2);
+                       break;
+               case REG_B:
+                       bit1 = 0;bit2 = 0;
+                       printk("B Register ");
+                       if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+                       if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+                       if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+                       printk("DMA(B) = %d ", bit1 >> 5);
+                       if (value & 0x10) printk("PIO_FORCED/PB4 ");
+                       if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+                       if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+                       if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+                       if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+                       printk("PIO(B) = %d ", bit2);
+                       break;
+               case REG_C:
+                       bit2 = 0;
+                       printk("C Register ");
+                       if (value & 0x80) printk("DMARQp ");
+                       if (value & 0x40) printk("IORDYp ");
+                       if (value & 0x20) printk("DMAR_EN ");
+                       if (value & 0x10) printk("DMAW_EN ");
+
+                       if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+                       if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+                       if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+                       if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+                       printk("DMA(C) = %d ", bit2);
+                       break;
+               case REG_D:
+                       printk("D Register ");
+                       break;
+               default:
+                       return;
+       }
+       printk("\n        %s ", (registers & REG_D) ? "DP" :
+                               (registers & REG_C) ? "CP" :
+                               (registers & REG_B) ? "BP" :
+                               (registers & REG_A) ? "AP" : "ERROR");
+       for (bit=128;bit>0;bit/=2)
+               printk("%s", (value & bit) ? "1" : "0");
+       printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+       struct hd_driveid *id   = drive->id;
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+
+       int                     err;
+       unsigned int            drive_conf;
+       byte                    drive_pci;
+       byte                    test1, test2, speed;
+       byte                    AP, BP, CP, DP, EP;
+       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       byte udma_66            = ((id->word93 & 0x2000) && (dev->device == PCI_DEVICE_ID_PROMISE_20262)) ? 1 : 0;
+       byte udma_33            = ultra ? (inb((dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0;
+
+       pci_read_config_byte(dev, 0x50, &EP);
+
+       switch(drive_number) {
+               case 0: drive_pci = 0x60;
+                       pci_read_config_dword(dev, drive_pci, &drive_conf);
+                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+                               goto chipset_is_set;
+                       pci_read_config_byte(dev, (drive_pci), &test1);
+                       if (!(test1 & SYNC_ERRDY_EN))
+                               pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
+                       break;
+               case 1: drive_pci = 0x64;
+                       pci_read_config_dword(dev, drive_pci, &drive_conf);
+                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+                               goto chipset_is_set;
+                       pci_read_config_byte(dev, 0x60, &test1);
+                       pci_read_config_byte(dev, (drive_pci), &test2);
+                       if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
+                               pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
+                       break;
+               case 2: drive_pci = 0x68;
+                       pci_read_config_dword(dev, drive_pci, &drive_conf);
+                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+                               goto chipset_is_set;
+                       pci_read_config_byte(dev, (drive_pci), &test1);
+                       if (!(test1 & SYNC_ERRDY_EN))
+                               pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
+                       break;
+               case 3: drive_pci = 0x6c;
+                       pci_read_config_dword(dev, drive_pci, &drive_conf);
+                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+                               goto chipset_is_set;
+                       pci_read_config_byte(dev, 0x68, &test1);
+                       pci_read_config_byte(dev, (drive_pci), &test2);
+                       if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
+                               pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
+                       break;
+               default:
+                       return ide_dma_off;
+       }
+
+       if (drive->media != ide_disk)
+               return ide_dma_off_quietly;
+
+       pci_read_config_byte(dev, (drive_pci), &AP);
+       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+       pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+       pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+       if (id->capability & 4) {               /* IORDY_EN */
+               pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+               pci_read_config_byte(dev, (drive_pci), &AP);
+       }
+
+       if (drive->media == ide_disk) {         /* PREFETCH_EN */
+               pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+               pci_read_config_byte(dev, (drive_pci), &AP);
+       }
+
+       if ((BP & 0xF0) && (CP & 0x0F)) {
+               /* clear DMA modes of upper 842 bits of B Register */
+               /* clear PIO forced mode upper 1 bit of B Register */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
+               pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+               /* clear DMA modes of lower 8421 bits of C Register */
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
+               pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+       }
+
+       pci_read_config_byte(dev, (drive_pci), &AP);
+       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+       pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+       if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
+               if (!((id->dma_ultra >> 8) & 16)) {
+                       drive->id->dma_ultra &= ~0xFF00;
+                       drive->id->dma_ultra |= 0x1010;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 8 == UDMA mode 4 == speed 6 plus cable */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01);
+               speed = XFER_UDMA_4;
+       } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
+               if (!((id->dma_ultra >> 8) & 8)) {
+                       drive->id->dma_ultra &= ~0xFF00;
+                       drive->id->dma_ultra |= 0x0808;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 7 == UDMA mode 3 == speed 5 plus cable */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02);
+               speed = XFER_UDMA_3;
+       } else if ((id->dma_ultra & 0x0004) && (udma_33)) {
+               if (!((id->dma_ultra >> 8) & 4)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0404;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 6 == UDMA mode 2 */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01);
+               speed = XFER_UDMA_2;
+       } else if ((id->dma_ultra & 0x0002) && (udma_33)) {
+               if (!((id->dma_ultra >> 8) & 2)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0202;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 5 == UDMA mode 1 */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02);
+               speed = XFER_UDMA_1;
+       } else if ((id->dma_ultra & 0x0001) && (udma_33)) {
+               if (!((id->dma_ultra >> 8) & 1)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0101;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 4 == UDMA mode 0 */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03);
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               if (!((id->dma_mword >> 8) & 4)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0404;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 4 == DMA mode 2 multi-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03);
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               if (!((id->dma_mword >> 8) & 2)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0202;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 3 == DMA mode 1 multi-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x04);
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_mword & 0x0001) {
+               if (!((id->dma_mword >> 8) & 1)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0101;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               /* speed 2 == DMA mode 0 multi-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05);
+               speed = XFER_MW_DMA_0;
+       } else if (id->dma_1word & 0x0004) {
+               if (!((id->dma_1word >> 8) & 4)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0404;
+               }
+               /* speed 2 == DMA mode 2 single-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05);
+               speed = XFER_SW_DMA_2;
+       } else if (id->dma_1word & 0x0002) {
+               if (!((id->dma_1word >> 8) & 2)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0202;
+               }
+               /* speed 1 == DMA mode 1 single-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x80);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x06);
+               speed = XFER_SW_DMA_1;
+       } else if (id->dma_1word & 0x0001) {
+               if (!((id->dma_1word >> 8) & 1)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0101;
+               }
+               /* speed 0 == DMA mode 0 single-word */
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|0xC0);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x0B);
+               speed = XFER_SW_DMA_0;
+       } else {
+               /* restore original pci-config space */
+               pci_write_config_dword(dev, drive_pci, drive_conf);
+               return ide_dma_off_quietly;
+       }
+
+       err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+
+#if PDC202XX_DECODE_REGISTER_INFO
+       pci_read_config_byte(dev, (drive_pci), &AP);
+       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+       pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+       decode_registers(REG_A, AP);
+       decode_registers(REG_B, BP);
+       decode_registers(REG_C, CP);
+       decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d 0x%08x ",
+               drive->name, ide_xfer_verbose(speed),
+               drive_number, drive_conf);
+       pci_read_config_dword(dev, drive_pci, &drive_conf);
+       printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+chipset_is_set:
+
+       return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+                       ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on : 
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+       ide_hwif_t *hwif = HWIF(drive);
+       ide_dma_action_t dma_func = ide_dma_off_quietly;
+
+       if (id && (id->capability & 1) && hwif->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       return HWIF(drive)->dmaproc(ide_dma_off, drive);
+               }
+
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x001F) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive, 1);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+                       }
+               } else if (id->field_valid & 2) {
+try_dma_modes:
+                       if ((id->dma_mword & 0x0004) ||
+                           (id->dma_1word & 0x0004)) {
+                               /* Force if Capable regular DMA modes */
+                               dma_func = config_chipset_for_dma(drive, 0);
+                       }
+               } else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
+                          (id->eide_dma_time > 150)) {
+                       /* Consult the list of known "good" drives */
+                       dma_func = config_chipset_for_dma(drive, 0);
+               }
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
+               default:
+                       break;
+       }
+       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
+}
+
+__initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name))
+{
+       unsigned long high_16   = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+       byte udma_speed_flag    = inb(high_16 + 0x001f);
+       byte primary_mode       = inb(high_16 + 0x001a);
+       byte secondary_mode     = inb(high_16 + 0x001b);
+
+       if (dev->rom_address) {
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+               printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
+       }
+
+       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+               byte irq = 0, irq2 = 0;
+               pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+               pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);    /* 0xbc */
+               if (irq != irq2) {
+                       pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+                       printk("%s: pci-config space interrupt mirror fixed.\n", name);
+               }
+       }
+
+       printk("%s: (U)DMA Burst Bit %sABLED " \
+               "Primary %s Mode " \
+               "Secondary %s Mode.\n",
+               name,
+               (udma_speed_flag & 1) ? "EN" : "DIS",
+               (primary_mode & 1) ? "MASTER" : "PCI",
+               (secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#if PDC202XX_FORCE_BURST_BIT
+       if (!(udma_speed_flag & 1)) {
+               printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
+               outb(udma_speed_flag|1, high_16 + 0x001f);
+               printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
+       }
+#endif /* PDC202XX_FORCE_BURST_BIT */
+
+#if PDC202XX_FORCE_MASTER_MODE
+       if (!(primary_mode & 1)) {
+               printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
+                       name, primary_mode, (primary_mode|1));
+               outb(primary_mode|1, high_16 + 0x001a);
+               printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+       }
+
+       if (!(secondary_mode & 1)) {
+               printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
+                       name, secondary_mode, (secondary_mode|1));
+               outb(secondary_mode|1, high_16 + 0x001b);
+               printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+       }
+#endif /* PDC202XX_FORCE_MASTER_MODE */
+       return dev->irq;
+}
+
+__initfunc(void ide_init_pdc202xx (ide_hwif_t *hwif))
+{
+       if (hwif->dma_base) {
+               hwif->dmaproc = &pdc202xx_dmaproc;
+       }
+}
index e032da579f5775d8d4cf620aa640f42d8090e585..5c05b1bd07debdd52cd90f71db48324e7d770653 100644 (file)
@@ -1,17 +1,18 @@
 /*  -*- linux-c -*-
- *  linux/drivers/block/pdc4030.c      Version 0.08  Nov 30, 1997
+ *  linux/drivers/block/pdc4030.c      Version 0.10  Jan 25, 1999
  *
- *  Copyright (C) 1995-1998  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
  */
 
 /*
  *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
  *
  *  This file provides support for the second port and cache of Promise
- *  IDE interfaces, e.g. DC4030, DC5030.
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
  *
  *  Thanks are due to Mark Lord for advice and patiently answering stupid
- *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this.
+ *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
+ *  especially Andre Hedrick.
  *
  *  Version 0.01       Initial version, #include'd in ide.c rather than
  *                      compiled separately.
@@ -29,6 +30,9 @@
  *  Version 0.07       Added support for DC4030 variants
  *                     Secondary interface autodetection
  *  Version 0.08       Renamed to pdc4030.c
+ *  Version 0.09       Obsolete - never released - did manual write request
+ *                     splitting before max_sectors[major][minor] available.
+ *  Version 0.10       Updated for 2.1 series of kernels
  */
 
 /*
  *
  *     'linux ide0=dc4030'
  *
- * As before, it seems that somewhere around 3Megs when writing, bad things
- * start to happen [timeouts/retries -ml]. If anyone can give me more feedback,
- * I'd really appreciate it.  [email: peterd@pnd-pc.demon.co.uk]
+ * It should now work as a second controller also ('ide1=dc4030') but only
+ * if you DON'T have BIOS V4.44, which has a bug. If you have this and EPROM
+ * programming facilities, I can tell you what to fix...
  *
+ * As of January 1999, Promise Technology Inc. have finally supplied me with
+ * some technical information which has shed a glimmer of light on some of the
+ * problems I was having, especially with writes. 
  */
 
+#define DEBUG_READ
+#define DEBUG_WRITE
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
 #include <asm/irq.h>
-#include "ide.h"
+
 #include "pdc4030.h"
 
 /* This is needed as the controller may not interrupt if the required data is
@@ -124,40 +135,48 @@ int init_pdc4030 (void)
 {
        ide_hwif_t *hwif = hwif_required;
         ide_drive_t *drive;
-       ide_hwif_t *second_hwif;
+       ide_hwif_t *hwif2;
        struct dc_ident ident;
        int i;
        
        if (!hwif) return 0;
 
        drive = &hwif->drives[0];
-       second_hwif = &ide_hwifs[hwif->index+1];
-       if(hwif->chipset == ide_pdc4030) /* we've already been found ! */
-           return 1;
+       hwif2 = &ide_hwifs[hwif->index+1];
+       if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+               return 1;
 
-       if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
-       {
-           return 0;
+       if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
+               return 0;
        }
        OUT_BYTE(0x08,IDE_CONTROL_REG);
-       if(pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
-           return 0;
+       if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
+               return 0;
        }
-       if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
-           printk("%s: Failed Promise read config!\n",hwif->name);
-           return 0;
+       if (ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+               printk(KERN_INFO
+                       "%s: Failed Promise read config!\n",hwif->name);
+               return 0;
        }
        ide_input_data(drive,&ident,SECTOR_WORDS);
-       if(ident.id[1] != 'P' || ident.id[0] != 'T') {
-            return 0;
+       if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+               return 0;
        }
-       printk("%s: Promise caching controller, ",hwif->name);
+       printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
        switch(ident.type) {
-            case 0x43: printk("DC4030VL-2, "); break;
-            case 0x41: printk("DC4030VL-1, "); break;
-           case 0x40:  printk("DC4030VL, "); break;
-            default:   printk("unknown - type 0x%02x - please report!\n"
+               case 0x43:      printk("DC4030VL-2, "); break;
+               case 0x41:      printk("DC4030VL-1, "); break;
+               case 0x40:      printk("DC4030VL, "); break;
+               default:
+                       printk("unknown - type 0x%02x - please report!\n"
                               ,ident.type);
+                       printk("Please e-mail the following data to "
+                              "promise@pnd-pc.demon.co.uk along with\n"
+                              "a description of your card and drives:\n");
+                       for (i=0; i < 0x90; i++) {
+                               printk("%02x ", ((unsigned char *)&ident)[i]);
+                               if ((i & 0x0f) == 0x0f) printk("\n");
+                       }
                        return 0;
        }
        printk("%dKB cache, ",(int)ident.cache_mem);
@@ -167,27 +186,35 @@ int init_pdc4030 (void)
             default:   hwif->irq = 15; break;
        }
        printk("on IRQ %d\n",hwif->irq);
-       hwif->chipset     = second_hwif->chipset    = ide_pdc4030;
-       hwif->mate        = second_hwif;
-       second_hwif->mate = hwif;
-       second_hwif->channel = 1;
-       hwif->selectproc  = second_hwif->selectproc = &promise_selectproc;
+       hwif->chipset   = hwif2->chipset = ide_pdc4030;
+       hwif->mate      = hwif2;
+       hwif2->mate     = hwif;
+       hwif2->channel  = 1;
+       hwif->selectproc = hwif2->selectproc = &promise_selectproc;
 /* Shift the remaining interfaces down by one */
        for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
                ide_hwif_t *h = &ide_hwifs[i];
 
-               printk("Shifting i/f %d values to i/f %d\n",i-1,i);
-               ide_init_hwif_ports(h->io_ports, (h-1)->io_ports[IDE_DATA_OFFSET], NULL);
-               h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET];
+#ifdef DEBUG
+               printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif
+               ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+               memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
                h->noprobe = (h-1)->noprobe;
        }
-       ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL);
-       second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET];
-       second_hwif->irq = hwif->irq;
+       ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
+       memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
+       hwif2->irq = hwif->irq;
+       hwif2->hw.irq = hwif->hw.irq = hwif->irq;
        for (i=0; i<2 ; i++) {
-            hwif->drives[i].io_32bit = 3;
-           second_hwif->drives[i].io_32bit = 3;
-           if(!ident.current_tm[i+2].cyl) second_hwif->drives[i].noprobe=1;
+               hwif->drives[i].io_32bit = 3;
+               hwif2->drives[i].io_32bit = 3;
+               hwif->drives[i].keep_settings = 1;
+               hwif2->drives[i].keep_settings = 1;
+               if (!ident.current_tm[i].cyl)
+                       hwif->drives[i].noprobe = 1;
+               if (!ident.current_tm[i+2].cyl)
+                       hwif2->drives[i].noprobe = 1;
        }
         return 1;
 }
@@ -198,7 +225,7 @@ int init_pdc4030 (void)
 static void promise_read_intr (ide_drive_t *drive)
 {
        byte stat;
-       int i;
+       int total_remaining;
        unsigned int sectors_left, sectors_avail, nsect;
        struct request *rq;
 
@@ -209,99 +236,140 @@ static void promise_read_intr (ide_drive_t *drive)
 
 read_again:
        do {
-           sectors_left = IN_BYTE(IDE_NSECTOR_REG);
-           IN_BYTE(IDE_SECTOR_REG);
+               sectors_left = IN_BYTE(IDE_NSECTOR_REG);
+               IN_BYTE(IDE_SECTOR_REG);
        } while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
        rq = HWGROUP(drive)->rq;
        sectors_avail = rq->nr_sectors - sectors_left;
+       if (!sectors_avail)
+               goto read_again;
 
 read_next:
        rq = HWGROUP(drive)->rq;
-       if ((nsect = rq->current_nr_sectors) > sectors_avail)
+       nsect = rq->current_nr_sectors;
+       if (nsect > sectors_avail)
                nsect = sectors_avail;
        sectors_avail -= nsect;
        ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
-#ifdef DEBUG
-       printk("%s:  promise_read: sectors(%ld-%ld), buffer=0x%08lx, "
-              "remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, 
-              (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
+#ifdef DEBUG_READ
+       printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+              "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+              rq->sector+nsect-1, (unsigned long) rq->buffer,
+              rq->nr_sectors-nsect);
 #endif
        rq->sector += nsect;
        rq->buffer += nsect<<9;
        rq->errors = 0;
-       i = (rq->nr_sectors -= nsect);
-       if ((rq->current_nr_sectors -= nsect) <= 0)
+       rq->nr_sectors -= nsect;
+       total_remaining = rq->nr_sectors;
+       if ((rq->current_nr_sectors -= nsect) <= 0) {
                ide_end_request(1, HWGROUP(drive));
-       if (i > 0) {
+       }
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
+       if (total_remaining > 0) {
                if (sectors_avail)
-                   goto read_next;
+                       goto read_next;
                stat = GET_STAT();
-               if(stat & DRQ_STAT)
-                   goto read_again;
-               if(stat & BUSY_STAT) {
-                   ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
-                   return;
+               if (stat & DRQ_STAT)
+                       goto read_again;
+               if (stat & BUSY_STAT) {
+#ifdef DEBUG_READ
+                       printk(KERN_DEBUG "%s: promise_read: waiting for"
+                              "interrupt\n", drive->name);
+#endif 
+                       ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
+                       return;
                }
-               printk("Ah! promise read intr: sectors left !DRQ !BUSY\n");
+               printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+                      "!DRQ !BUSY\n", drive->name);
                ide_error(drive, "promise read intr", stat);
        }
 }
 
+/*
+ * promise_write_intr()
+ * This interrupt is called after the particularly odd polling for completion
+ * of the write request, once all the data has been sent.
+ */ 
+static void promise_write_intr(ide_drive_t *drive)
+{
+       byte stat;
+       int i;
+       struct request *rq;
+
+       if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+               ide_error(drive, "promise_write_intr", stat);
+       }
+
+#ifdef DEBUG_WRITE
+       printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+#endif
+       rq = HWGROUP(drive)->rq;
+       for (i = rq->nr_sectors; i > 0;) {
+               i -= rq->current_nr_sectors;
+               ide_end_request(1, HWGROUP(drive));
+       }
+}
+
 /*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
 static void promise_write_pollfunc (ide_drive_t *drive)
 {
-       int i;
-       ide_hwgroup_t *hwgroup = HWGROUP(drive);
-       struct request *rq;
+       if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
+               if (time_before(jiffies, HWGROUP(drive)->poll_timeout)) {
+                       ide_set_handler (drive, &promise_write_pollfunc, 1);
+                       return; /* continue polling... */
+               }
+               printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+               ide_error (drive, "write timeout", GET_STAT());
+               return;
+       }
 
-        if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-            if (time_before(jiffies, hwgroup->poll_timeout)) {
-                ide_set_handler (drive, &promise_write_pollfunc, 1);
-                return; /* continue polling... */
-            }
-            printk("%s: write timed-out!\n",drive->name);
-            ide_error (drive, "write timeout", GET_STAT());
-            return;
-        }
-        
+#ifdef DEBUG_WRITE
+       printk(KERN_DEBUG "%s: Doing last 4 sectors\n", drive->name);
+#endif
        ide_multwrite(drive, 4);
-        rq = hwgroup->rq;
-        for (i = rq->nr_sectors; i > 0;) {
-            i -= rq->current_nr_sectors;
-            ide_end_request(1, hwgroup);
-        }
-        return;
+       ide_set_handler(drive, &promise_write_intr, WAIT_CMD);
+       return;
 }
 
 /*
  * promise_write() transfers a block of one or more sectors of data to a
  * drive as part of a disk write operation. All but 4 sectors are transfered
  * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transfered. Don't ask me why, but this is
- * how it's done in the drivers for other O/Ses. There is no interrupt
- * generated on writes, which is why we have to do it like this.
+ * before the final 4 sectors are transfered. The interrupt generated on 
+ * writes occurs after this process, which is why I got it wrong for so long!
  */
 static void promise_write (ide_drive_t *drive)
 {
-    ide_hwgroup_t *hwgroup = HWGROUP(drive);
-    struct request *rq = &hwgroup->wrq;
-    int i;
-
-    if (rq->nr_sectors > 4) {
-        ide_multwrite(drive, rq->nr_sectors - 4);
-        hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-        ide_set_handler (drive, &promise_write_pollfunc, 1);
-        return;
-    } else {
-        ide_multwrite(drive, rq->nr_sectors);
-        rq = hwgroup->rq;
-        for (i = rq->nr_sectors; i > 0;) {
-            i -= rq->current_nr_sectors;
-            ide_end_request(1, hwgroup);
-        }
-    }
+       ide_hwgroup_t *hwgroup = HWGROUP(drive);
+       struct request *rq = &hwgroup->wrq;
+
+#ifdef DEBUG_WRITE
+       printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+              "buffer=0x%08lx\n", drive->name, rq->sector,
+              rq->sector + rq->nr_sectors - 1, rq->buffer);
+#endif
+       if (rq->nr_sectors > 4) {
+               ide_multwrite(drive, rq->nr_sectors - 4);
+               hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+               ide_set_handler (drive, &promise_write_pollfunc, 1);
+               return;
+       } else {
+               ide_multwrite(drive, rq->nr_sectors);
+               ide_set_handler(drive, &promise_write_intr, WAIT_CMD);
+       }
 }
 
 /*
@@ -315,43 +383,54 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq)
        byte stat;
 
        if (rq->cmd == READ) {
-           ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
-           OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-/* The card's behaviour is odd at this point. If the data is
-   available, DRQ will be true, and no interrupt will be
-   generated by the card. If this is the case, we need to simulate
-   an interrupt. Ugh! Otherwise, if an interrupt will occur, bit0
-   of the SELECT register will be high, so we can just return and
-   be interrupted.*/
-           timeout = jiffies + HZ/20; /* 50ms wait */
-           do {
-               stat=GET_STAT();
-               if(stat & DRQ_STAT) {
-                    disable_irq(HWIF(drive)->irq);
-                   ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL);
-                    enable_irq(HWIF(drive)->irq);
-                   return;
-               }
-               if(IN_BYTE(IDE_SELECT_REG) & 0x01)
-                   return;
-               udelay(1);
-           } while (time_before(jiffies, timeout));
-           printk("%s: reading: No DRQ and not waiting - Odd!\n",
-                  drive->name);
-           return;
-       }
-       if (rq->cmd == WRITE) {
-           OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-           if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-               printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
-               return;
-           }
-           if (!drive->unmask)
-               __cli();        /* local CPU only */
-           HWGROUP(drive)->wrq = *rq; /* scratchpad */
-           promise_write(drive);
-           return;
+               OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
+               timeout = jiffies + HZ/20; /* 50ms wait */
+               do {
+                       stat=GET_STAT();
+                       if (stat & DRQ_STAT) {
+                               udelay(1);
+                               promise_read_intr(drive);
+                               return;
+                       }
+                       if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
+#ifdef DEBUG_READ
+                               printk(KERN_DEBUG "%s: read: waiting for "
+                                                 "interrupt\n", drive->name);
+#endif
+                               ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
+                               return;
+                       }
+                       udelay(1);
+               } while (time_before(jiffies, timeout));
+
+               printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
+                       drive->name);
+
+       } else if (rq->cmd == WRITE) {
+               OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
+               if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+                       printk(KERN_ERR "%s: no DRQ after issuing "
+                              "PROMISE_WRITE\n", drive->name);
+                       return;
+               }
+               if (!drive->unmask)
+                       __cli();        /* local CPU only */
+               HWGROUP(drive)->wrq = *rq; /* scratchpad */
+               promise_write(drive);
+
+       } else {
+               printk("KERN_WARNING %s: bad command: %d\n",
+                      drive->name, rq->cmd);
+               ide_end_request(0, HWGROUP(drive));
        }
-       printk("%s: bad command: %d\n", drive->name, rq->cmd);
-       ide_end_request(0, HWGROUP(drive));
 }
diff --git a/drivers/block/piix.c b/drivers/block/piix.c
new file mode 100644 (file)
index 0000000..d6efc89
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * linux/drivers/block/piix.c  Version 0.22    March 29, 1999
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
+ *
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 |
+ * | PIO 2 | SW2 | d0 | 90 | 4 |
+ * | PIO 3 | MW1 | e1 | a1 | 9 |
+ * | PIO 4 | MW2 | e3 | a3 | b |
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ * 
+ *    00|00 udma 0
+ *    01|01 udma 1
+ *    10|10 udma 2
+ *    11|11 reserved
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+#define PIIX_DMA_PROC                  0
+#define PIIX_DEBUG_SET_XFER            0
+#define PIIX_DEBUG_DRIVE_INFO          0
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be usefull if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, byte pio)
+{
+       unsigned long flags;
+       u16 master_data;
+       byte slave_data, speed;
+       int err;
+       int is_slave = (&HWIF(drive)->drives[1] == drive);
+       int master_port = HWIF(drive)->index ? 0x42 : 0x40;
+       int slave_port = 0x44;
+                          /* ISP  RTC */
+       byte timings[][2] = { { 0, 0 },
+                             { 0, 0 },
+                             { 1, 0 },
+                             { 2, 1 },
+                             { 2, 3 }, };
+                             
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
+       if (is_slave) {
+               master_data = master_data | 0x4000;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0070;
+               pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
+               slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
+               slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
+                                          << (HWIF(drive)->index ? 4 : 0)));
+       } else {
+               master_data = master_data & 0xccf8;
+               if (pio > 1)
+                       /* enable PPE, IE and TIME */
+                       master_data = master_data | 0x0007;
+               master_data = master_data | (timings[pio][0] << 12) |
+                             (timings[pio][1] << 8);
+       }
+       save_flags(flags);
+       cli();
+       pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
+       if (is_slave)
+               pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
+       restore_flags(flags);
+
+       switch(pio) {
+               case 4: speed = XFER_PIO_4;break;
+               case 3: speed = XFER_PIO_3;break;
+               case 2: speed = XFER_PIO_2;break;
+               case 1: speed = XFER_PIO_1;break;
+               default:
+                       speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+                       break;
+       }
+
+       err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+}
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
+{
+       struct hd_driveid *id = drive->id;
+       ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = hwif->pci_dev;
+
+       int                     sitre;
+       short                   reg4042, reg44, reg48, reg4a;
+       byte                    speed;
+       int                     u_speed;
+       byte maslave            = hwif->channel ? 0x42 : 0x40;                  
+       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       int a_speed             = 2 << (drive_number * 4);
+       int u_flag              = 1 << drive_number;
+
+       pci_read_config_word(dev, maslave, &reg4042);
+       sitre =  (reg4042 & 0x4000) ? 1 : 0;
+       pci_read_config_word(dev, 0x44, &reg44);
+       pci_read_config_word(dev, 0x48, &reg48);
+       pci_read_config_word(dev, 0x4a, &reg4a);
+
+#if PIIX_DEBUG_SET_XFER
+       printk("PIIX%s: DMA enable ",
+               (dev->device == PCI_DEVICE_ID_INTEL_82371FB_0) ? "a" :
+               (dev->device == PCI_DEVICE_ID_INTEL_82371FB_1) ? "b" :
+               (dev->device == PCI_DEVICE_ID_INTEL_82371SB_1) ? "3" :
+               (dev->device == PCI_DEVICE_ID_INTEL_82371AB)   ? "4" : " UNKNOWN" );
+#endif /* PIIX_DEBUG_SET_XFER */
+
+       if (id->dma_ultra && (ultra)) {
+               if (!(reg48 & u_flag)) {
+                       pci_write_config_word(dev, 0x48, reg48|u_flag);
+               }
+       } else {
+               pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+       }
+
+       if ((id->dma_ultra & 0x0004) && (ultra)) {
+               if (!((id->dma_ultra >> 8) & 4)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0404;
+               }
+               u_speed = 2 << (drive_number * 4);
+               if (!(reg4a & u_speed)) {
+                       pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+               }
+               speed = XFER_UDMA_2;
+       } else if ((id->dma_ultra & 0x0002) && (ultra)) {
+               if (!((id->dma_ultra >> 8) & 2)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0202;
+               }
+               u_speed = 1 << (drive_number * 4);
+               if (!(reg4a & u_speed)) {
+                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+                       pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+               }
+               speed = XFER_UDMA_1;
+       } else if ((id->dma_ultra & 0x0001) && (ultra)) {
+               if (!((id->dma_ultra >> 8) & 1)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0101;
+               }
+               u_speed = 0 << (drive_number * 4);
+               if (!(reg4a & u_speed)) {
+                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+                       pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+               }
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               drive->id->dma_ultra &= ~0x0F0F;
+               pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+               if (!((id->dma_mword >> 8) & 4)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0404;
+               }
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               drive->id->dma_ultra &= ~0x0F0F;
+               pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+               if (!((id->dma_mword >> 8) & 2)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0202;
+               }
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_1word & 0x0004) {
+               drive->id->dma_ultra &= ~0x0F0F;
+               pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+               if (!((id->dma_1word >> 8) & 4)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0404;
+               }
+               speed = XFER_SW_DMA_2;
+        } else {
+               return ide_dma_off_quietly;
+       }
+
+       (void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+
+#if PIIX_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d ",
+               drive->name,
+               ide_xfer_verbose(speed),
+               drive_number);
+       printk("\n");
+#endif /* PIIX_DEBUG_DRIVE_INFO */
+
+       return ((int)   ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+}
+
+static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+       int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0;
+       switch (func) {
+               case ide_dma_check:
+                       return piix_config_drive_for_dma(drive, ultra);
+               default :
+                       break;
+       }
+       /* Other cases are done by generic IDE-DMA code. */
+       return ide_dmaproc(func, drive);
+}
+
+void ide_init_piix (ide_hwif_t *hwif)
+{
+       hwif->tuneproc = &piix_tune_drive;
+#if PIIX_DMA_PROC
+       hwif->dmaproc = &piix_dmaproc;
+#endif /* PIIX_DMA_PROC */
+}
index 9c1d0ed71317b63173e06c44f02395f981a31a46..d7b2784d1985b442c8a4e4ca255886e79b1b6614 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
index fe8c229004db35e83218c4363ca9a1bb3e9890ee..ae8749813248d3f8ac3478c5515741926bb136a8 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <asm/io.h>
 #include <linux/pci.h>
-#include "ide.h"
+#include <linux/ide.h>
+
+#include <asm/io.h>
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 
index 7fca7d5d9777160721e4fa4c349c5bfd850c08f1..2f08740eadfe689d84d87c5010552253cd9f7c17 100644 (file)
@@ -8,11 +8,11 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include "ide.h"
 #include "ide_modes.h"
 
 void ide_init_sl82c105(ide_hwif_t *hwif)
index a502fedf679886602299af17b0514f54a1265ad9..c4f96d49206b43d2ae444e62f6c1be6eb6629915 100644 (file)
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 
-#include "ide.h"
-
 static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
        ide_hwif_t *hwif = HWIF(drive);
@@ -185,7 +184,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                        break;  /* always use PIO for writes */
 #endif
                case ide_dma_read:
-                       if (!(count = ide_build_dmatable(drive)))
+                       if (!(count = ide_build_dmatable(drive, func)))
                                break;          /* try PIO instead of DMA */
                        trm290_prepare_drive(drive, 1); /* select DMA xfer */
                        outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base);
index 77121ca3e017de88e9795c7bf46c4ea5315d14ef..13f5f39a7f55fda3b860d4f1cdd35a13899c353a 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
 #include "ide_modes.h"
 
 /*
index 28bf80c7628421d9426ded14add7ffc1e9a6077a..40720edbd300224c08f350b3dc863c6ddc388909 100644 (file)
@@ -1,18 +1,44 @@
 /*
- * linux/drivers/block/via82c586.c     Version 0.01    Aug 16, 1998
+ * linux/drivers/block/via82c586.c     Version 0.03    Nov. 19, 1998
  *
- *  Copyright (C) 1998 Michel Aubry
- *  Copyright (C) 1998 Andre Hedrick
+ *  Copyright (C) 1998 Michel Aubry, Maintainer
+ *  Copyright (C) 1998 Andre Hedrick, Integrater
  *
  *  The VIA MVP-3 is reported OK with UDMA.
+ *  The TX Pro III is also reported OK with UDMA.
  *
- *  VIA chips also have a single FIFO, with the same 64 bytes deep buffer (16 levels 
- *  of 4 bytes each).
- *  However, VIA chips can have the buffer split either 8:8 levels, 16:0 levels or 
- *  0:16 levels between both channels. One could think of using this feature, as even
- *  if no level of FIFO is given to a given channel, one can always reach ATAPI drives 
- *  through it, or, if one channel is unused, configuration defaults to an even split 
- *  FIFO levels.
+ *  VIA chips also have a single FIFO, with the same 64 bytes deep
+ *  buffer (16 levels of 4 bytes each).
+ *
+ *  However, VIA chips can have the buffer split either 8:8 levels,
+ *  16:0 levels or 0:16 levels between both channels. One could think
+ *  of using this feature, as even if no level of FIFO is given to a
+ *  given channel, one can for instance always reach ATAPI drives through
+ *  it, or, if one channel is unused, configuration defaults to
+ *  an even split FIFO levels.
+ *  
+ *  This feature is available only through a kernel command line :
+ *             "splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan".
+ *             where:  Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4.
+ *
+ *  If Chan == 1:
+ *     gives all the fifo to channel 0,
+ *     sets its threshold to Thr0/4,
+ *     and disables any dma access to channel 1.
+ *
+ *  If chan == 2:
+ *     gives all the fifo to channel 1,
+ *     sets its threshold to Thr1/4,
+ *     and disables any dma access to channel 0.
+ *
+ *  If chan == 3 or 4:
+ *     shares evenly fifo between channels,
+ *     gives channel 0 a threshold of Thr0/4,
+ *     and channel 1 a threshold of Thr1/4.
+ *
+ *  Note that by default (if no command line is provided) and if a channel
+ *  has been disabled in Bios, all the fifo is given to the active channel,
+ *  and its threshold is set to 3/4.
  */
 
 #include <linux/types.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/ide.h>
+
 #include <asm/io.h>
-#include "ide.h"
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char *FIFO_str[] = {
+       " 1 ",
+       "3/4",
+       "1/2",
+       "1/4"
+};
+
+static char *control3_str[] = {
+       "No limitation",
+       "64",
+       "128",
+       "192"
+};
+
+static int via_get_info(char *, char **, off_t, int, int);
+extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static char * print_apollo_drive_config (char *buf, struct pci_dev *dev)
+{
+       int rc;
+       unsigned int time;
+       byte tm;
+       char *p = buf;  
+       /* Drive Timing Control */
+       rc = pci_read_config_dword(dev, 0x48, &time);
+       p += sprintf(p, "Act Pls Width:  %02d          %02d           %02d          %02d\n",
+                       ((time & 0xf0000000)>>28) + 1,
+                       ((time & 0xf00000)>>20) + 1,
+                       ((time & 0xf000)>>12) + 1,
+                       ((time & 0xf0)>>4) + 1 );
+       p += sprintf(p, "Recovery Time:  %02d          %02d           %02d          %02d\n",
+                       ((time & 0x0f000000)>>24) + 1,
+                       ((time & 0x0f0000)>>16) + 1,
+                       ((time & 0x0f00)>>8) + 1,
+                       (time & 0x0f) + 1 );
+       /* Address Setup Time */
+       rc = pci_read_config_byte(dev, 0x4C, &tm);
+       p += sprintf(p, "Add. Setup T.:  %01dT          %01dT           %01dT          %01dT\n",
+                       ((tm & 0xc0)>>6) + 1,
+                       ((tm & 0x30)>>4) + 1,
+                       ((tm & 0x0c)>>2) + 1,
+                       (tm & 0x03) + 1 );
+       /* UltraDMA33 Extended Timing Control */
+       rc = pci_read_config_dword(dev, 0x50, &time);
+       p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n");
+       p += sprintf(p, "Enable Meth.:    %01d           %01d            %01d           %01d\n",
+                       (time & 0x80000000)     ? 1 : 0,
+                       (time & 0x800000)       ? 1 : 0,
+                       (time & 0x8000)         ? 1 : 0,
+                       (time & 0x80)           ? 1 : 0 );
+       p += sprintf(p, "Enable:         %s         %s          %s         %s\n",
+                       (time & 0x40000000)     ? "yes" : "no ",
+                       (time & 0x400000)       ? "yes" : "no ",
+                       (time & 0x4000)         ? "yes" : "no ",
+                       (time & 0x40)           ? "yes" : "no " );
+       p += sprintf(p, "Transfer Mode: %s         %s          %s         %s\n",
+                       (time & 0x20000000)     ? "PIO" : "DMA",
+                       (time & 0x200000)       ? "PIO" : "DMA",
+                       (time & 0x2000)         ? "PIO" : "DMA",
+                       (time & 0x20)           ? "PIO" : "DMA" );
+       p += sprintf(p, "Cycle Time:     %01dT          %01dT           %01dT          %01dT\n",
+                       ((time & 0x03000000)>>24) + 2,
+                       ((time & 0x030000)>>16) + 2,
+                       ((time & 0x0300)>>8) + 2,
+                       (time & 0x03) + 2 );
+       return (char *)p;
+}
+
+static char * print_apollo_ide_config (char *buf, struct pci_dev *dev)
+{
+       byte time, tmp; 
+       unsigned short size0, size1;
+       int rc;
+       char *p = buf;  
+       rc = pci_read_config_byte(dev, 0x41, &time);
+       p += sprintf(p, "Prefetch Buffer :      %s                     %s\n",
+               (time & 128)    ? "on " : "off",
+               (time & 32)     ? "on " : "off" );
+       p += sprintf(p, "Post Write Buffer:     %s                     %s\n",
+               (time & 64)     ? "on " : "off",
+               (time & 16)     ? "on " : "off" );
+       /* FIFO configuration */
+       rc = pci_read_config_byte(dev, 0x43, &time);
+       tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3);
+       p += sprintf(p, "FIFO Conf/Chan. :      %02d                      %02d\n",
+                       16 - tmp, tmp);
+       tmp = (time & 0x0F)>>2;
+       p += sprintf(p, "Threshold Prim. :      %s                     %s\n",
+                       FIFO_str[tmp],
+                       FIFO_str[time & 0x03] );
+       /* chipset Control3 */
+       rc = pci_read_config_byte(dev, 0x46, &time);
+       p += sprintf(p, "Read DMA FIFO flush:   %s                     %s\n",
+                       (time & 0x80)   ? "on " : "off",
+                       (time & 0x40)   ? "on " : "off" );
+       p += sprintf(p, "End Sect. FIFO flush:  %s                     %s\n",
+                       (time & 0x20)   ? "on " : "off",
+                       (time & 0x10)   ? "on " : "off" );
+       p += sprintf(p, "Max DRDY Pulse Width:  %s %s\n",
+                       control3_str[(time & 0x03)],
+                       (time & 0x03) ? "PCI clocks" : "" );
+       /* Primary and Secondary sector sizes */
+       rc = pci_read_config_word(dev, 0x60, &size0);
+       rc = pci_read_config_word(dev, 0x68, &size1);
+       p += sprintf(p, "Bytes Per Sector:      %03d                     %03d\n",
+                       size0 & 0xfff,
+                       size1 & 0xfff );
+
+       return (char *)p;
+}
+
+static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev)
+{
+       byte t;
+       int rc;
+       char *p = buf;  
+       unsigned short c;
+       byte l, l_max;   
+       rc = pci_read_config_word(dev, 0x04, &c);
+       rc = pci_read_config_byte(dev, 0x44, &t);
+       rc = pci_read_config_byte(dev, 0x0d, &l);
+       rc = pci_read_config_byte(dev, 0x3f, &l_max);
+
+       p += sprintf(p, "Command register = 0x%x\n", c);
+       p += sprintf(p, "Master Read  Cycle IRDY %d Wait State\n",
+                       (t & 64) >>6 );
+       p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n",
+                       (t & 32) >> 5 );
+       p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n",
+                       (t & 16) ? "on " : "off" );
+       p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n",
+                       (t & 8) ? "on " : "off" );
+       p += sprintf(p, "Latency timer = %d (max. = %d)\n",
+                       l, l_max);
+
+       return (char *)p;
+}
+static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev)
+{
+       byte t;
+       int rc;
+       char *p = buf;  
+       rc = pci_read_config_byte(dev, 0x45, &t);
+       p += sprintf(p, "Interrupt Steering Swap: %s\n",
+                       (t & 64) ? "on ":"off" );
+
+       return (char *)p;
+}
+static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev,
+                                               unsigned short n)
+{
+       /*
+        * at that point we can be sure that register 0x20 of the
+        * chipset contains the right address...
+        */
+       unsigned int bibma;
+       int rc;
+       byte c0, c1;    
+       char *p = buf; 
+       rc = pci_read_config_dword(dev, 0x20, &bibma);
+       bibma = (bibma & 0xfff0) ;
+       /*
+        * at that point bibma+0x2 et bibma+0xa are byte registers
+        * to investigate:
+        */
+       c0 = inb((unsigned short)bibma + 0x02);
+       c1 = inb((unsigned short)bibma + 0x0a);
+       if (n == 0) {
+        /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/
+               p += sprintf(p, "both channels togth:   %s                     %s\n",
+                               (c0&0x80) ? "no" : "yes",
+                               (c1&0x80) ? "no" : "yes" );
+       } else {
+        /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/
+               p += sprintf(p, "DMA enabled:    %s         %s          %s         %s\n",
+                               (c0&0x20) ? "yes" : "no ",
+                               (c0&0x40) ? "yes" : "no ",
+                               (c1&0x20) ? "yes" : "no ",
+                               (c1&0x40) ? "yes" : "no " );
+       }
+       return (char *)p;
+}
+
+static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+       /*
+        * print what /proc/via displays,
+        * if required from DISPLAY_APOLLO_TIMINGS
+        */
+       char *p = buffer;
+       /* Parameter of chipset : */
+
+       /* Miscellaneous control 1 */
+       p = print_apollo_chipset_control1(buffer, bmide_dev);
+
+       /* Miscellaneous control 2 */
+       p = print_apollo_chipset_control2(p, bmide_dev);
+       /* Parameters of drives: */
+
+       /* Header */
+       p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n");
+       p = print_apollo_chipset_control3(p, bmide_dev, 0);
+       p = print_apollo_ide_config(p, bmide_dev);
+       p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n");
+       p = print_apollo_chipset_control3(p, bmide_dev, 1);
+       p = print_apollo_drive_config(p, bmide_dev);
+       return p-buffer;        /* hoping it is less than 4K... */
+}
+
+#endif  /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ *  Used to set Fifo configuration via kernel command line:
+ */
+
+byte fifoconfig = 0;
+static byte newfifo = 0;
+
+/* Used to just intialize once Fifo configuration */
+static short int done = 0;
 
 /*
  *  Set VIA Chipset Timings for (U)DMA modes enabled.
 static void set_via_timings (ide_hwif_t *hwif)
 {
        struct pci_dev  *dev = hwif->pci_dev;
-       byte post  = hwif->channel ? 0xc0 : 0x30;
-       byte flush = hwif->channel ? 0xa0 : 0x50;
+       byte post  = hwif->channel ? 0x30 : 0xc0;
+       byte flush = hwif->channel ? 0x50 : 0xa0;
+       int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) :
+                                  (((newfifo & 0x60) == 0x60) ? 1 : 0);
        byte via_config = 0;
        int rc = 0, errors = 0;
 
        printk("%s: VIA Bus-Master ", hwif->name);
 
-       if (!hwif->dma_base) {
-               printk(" ERROR, NO DMA_BASE\n");
-               return;
-       }
-
-       /* setting IDE read prefetch buffer and IDE post write buffer.
+       /*
+        * setting IDE read prefetch buffer and IDE post write buffer.
         * (This feature allows prefetched reads and post writes).
         */
-       if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) {
-               errors++;
-               goto via_error;
-       }
-       if ((rc = pci_write_config_byte(dev, 0x41, via_config | post))) {
+       if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) 
                errors++;
-               goto via_error;
+
+       if (mask) {
+               if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post)))
+                       errors++;
+       } else {
+               if ((rc = pci_write_config_byte(dev, 0x41, via_config | post)))
+                       errors++;
        }
 
-       /* setting Channel read and End-of-sector FIFO flush.
+       /*
+        * setting Channel read and End-of-sector FIFO flush.
         * (This feature ensures that FIFO flush is enabled:
          *  - for read DMA when interrupt asserts the given channel.
          *  - at the end of each sector for the given channel.)
         */
-       if ((rc = pci_read_config_byte(dev, 0x46, &via_config))) {
+       if ((rc = pci_read_config_byte(dev, 0x46, &via_config)))
                errors++;
-               goto via_error;
+
+       if (mask) {
+               if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush)))
+                       errors++;
+       } else {
+               if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush)))
+                       errors++;
        }
-        if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush))) {
-               errors++;
-               goto via_error;
+
+       if (!hwif->dma_base)
+               printk("Config %s. No DMA Enabled\n",
+                       errors ? "ERROR":"Success");
+       else
+               printk("(U)DMA Timing Config %s\n",
+                       errors ? "ERROR" : "Success");
+}
+
+/*
+ *  Sets VIA 82c586 FIFO configuration:
+ *  This chipsets gets a splitable fifo. This can be driven either by command
+ *  line option (eg "splitfifo=2,2,3" which asks this driver to switch all the 
+ *  16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma 
+ *  triggering.
+ */
+
+static int via_set_fifoconfig(ide_hwif_t *hwif)
+{
+       byte fifo;
+       unsigned int timings;
+       struct pci_dev  *dev = hwif->pci_dev;
+
+       /* read port configuration */
+       if (pci_read_config_dword(dev, 0x40, &timings))
+               return 1;
+   
+       /* first read actual fifo config: */
+       if (pci_read_config_byte(dev, 0x43, &fifo))
+               return 1;
+
+       /* keep 4 and 7 bit as they seem to differ between chipsets flavors... */
+       newfifo = fifo & 0x90;
+
+       if (fifoconfig) {
+               /* we received a config request from kernel command line: */
+               newfifo |= fifoconfig & 0x6f;
+       } else {
+               /* If ever just one channel is unused, allocate all fifo levels to it
+                * and give it a 3/4 threshold for (u)dma transfers.
+                * Otherwise, share it evenly between channels:
+                */
+               if ((timings & 3) == 2) {
+                       /* only primary channel is  enabled
+                        * 16 buf. to prim. chan. thresh=3/4
+                        */
+                       newfifo |= 0x06;
+               } else if ((timings & 3) == 1) {
+                       /* only secondary channel is enabled!
+                        * 16 buffers to sec. ch. thresh=3/4
+                        */
+                       newfifo |= 0x69;
+               } else {
+                       /* fifo evenly distributed: */
+                       newfifo |= 0x2a;
+               }
        }
 
-via_error:
-       printk("(U)DMA Timing Config %s\n", errors ? "ERROR" : "Success");
+       /* write resulting configuration to chipset: */
+       if (pci_write_config_byte(dev, 0x43, newfifo))
+               return 1;
+
+       /* and then reread it to get the actual one */
+       if (pci_read_config_byte(dev, 0x43, &newfifo))
+               return 1;
+
+       /* print a kernel report: */
+       printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n",
+               ((newfifo & 0x60) == 0x60)      ? " 0" :
+               ((newfifo & 0x60)               ? " 8" : "16"),
+               !(newfifo & 0x0c)               ? "1" :
+               (!(newfifo & 0x08)              ? "3/4" :
+               (newfifo & 0x04)                ? "1/4" : "1/2"));
+
+       printk("                          %s Second. buffers, threshold = %s\n",
+               ((newfifo & 0x60) == 0x60)      ? "16" :
+               ((newfifo & 0x60)               ? " 8" : " 0"),
+               !(newfifo & 0x03)               ? "1" :
+               (!(newfifo & 0x02)              ? "3/4" :
+               (newfifo & 0x01)                ? "1/4" : "1/2"));
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+       bmide_dev = hwif->pci_dev;
+       via_display_info = &via_get_info;
+#endif /* DISPLAY_VIA_TIMINGS &&  CONFIG_PROC_FS*/
+       return 0;
+}
+
+/*
+ *  ide_dmacapable_via82c568(ide_hwif_t *, unsigned long)
+ *  checks if channel "channel" of if hwif is dma
+ *  capable or not, according to kernel command line,
+ *  and the new fifo settings.
+ *  It calls "ide_setup_dma" on capable mainboards, and
+ *  bypasses the setup if not capable.
+ */
+
+void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+       if (!done) {
+               via_set_fifoconfig(hwif);
+               done = 1;
+       }
+
+       /*
+        * check if any fifo is available for requested port:
+        */
+       if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) ||
+           ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) {
+               printk("    %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name);
+       } else {
+               ide_setup_dma(hwif, dmabase, 8);
+       }
 }
 
-void ide_init_via82c586 (ide_hwif_t *hwif)
+__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif))
 {
        set_via_timings(hwif);
 }
index e8c1effd6ba25219a9727b463a7c9268c608b434..7a3d4b5bcb88b6b2faff4fef4beecb2778e58d8a 100644 (file)
@@ -2571,6 +2571,9 @@ static int get_async_struct(int line, struct async_struct **ret_info)
                return -ENOMEM;
        }
        memset(info, 0, sizeof(struct async_struct));
+       init_waitqueue_head(&info->open_wait);
+       init_waitqueue_head(&info->close_wait);
+       init_waitqueue_head(&info->delta_msr_wait);
        info->magic = SERIAL_MAGIC;
        info->port = sstate->port;
        info->flags = sstate->flags;
index 92e2ee5449634f720fe6dd68903f668f85db349d..9f32ec5e67dcecddeabf72c857cb3d99674eeea1 100644 (file)
@@ -741,7 +741,6 @@ isdn_status_callback(isdn_ctrl * c)
                                isdn_free_queue(&dev->drv[di]->rpqueue[i]);
                        kfree(dev->drv[di]->rpqueue);
                        kfree(dev->drv[di]->rcv_waitq);
-                       kfree(dev->drv[di]->snd_waitq);
                        kfree(dev->drv[di]);
                        dev->drv[di] = NULL;
                        dev->drvid[di][0] = '\0';
@@ -785,7 +784,7 @@ isdn_getnum(char **p)
  * of the mapping (di,ch)<->minor, happen during the sleep? --he 
  */
 int
-isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
 {
        int left;
        int count;
@@ -2088,6 +2087,7 @@ register_isdn(isdn_if * i)
                return 0;
        }
        memset((char *) d, 0, sizeof(driver));
+       init_waitqueue_head(&d->st_waitq); 
        if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
                printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
                kfree(d);
@@ -2112,8 +2112,9 @@ register_isdn(isdn_if * i)
        for (j = 0; j < n; j++) {
                skb_queue_head_init(&d->rpqueue[j]);
        }
-       if (!(d->rcv_waitq = (struct wait_queue **)
-             kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
+       d->rcv_waitq = (wait_queue_head_t *)
+               kmalloc(sizeof(wait_queue_head_t) * 2 * n, GFP_KERNEL);
+       if (!d->rcv_waitq) { 
                printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
                kfree(d->rpqueue);
                kfree(d->rcvcount);
@@ -2121,18 +2122,11 @@ register_isdn(isdn_if * i)
                kfree(d);
                return 0;
        }
-       memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n);
-       if (!(d->snd_waitq = (struct wait_queue **)
-             kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
-               printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
-               kfree(d->rcv_waitq);
-               kfree(d->rpqueue);
-               kfree(d->rcvcount);
-               kfree(d->rcverr);
-               kfree(d);
-               return 0;
+       d->snd_waitq = d->rcv_waitq + n;                
+       for (j = 0; j < n; j++) { 
+               init_waitqueue_head(&d->rcv_waitq[n]); 
+               init_waitqueue_head(&d->snd_waitq[n]); 
        }
-       memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n);
        d->channels = n;
        d->loaded = 1;
        d->maxbufsize = i->maxbufsize;
@@ -2215,12 +2209,15 @@ isdn_init(void)
        memset((char *) dev, 0, sizeof(isdn_dev));
        init_timer(&dev->timer);
        dev->timer.function = isdn_timer_funct;
-       dev->sem = MUTEX;
+       init_MUTEX(&dev->sem);
+       init_waitqueue_head(&dev->info_waitq); 
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
                dev->drvmap[i] = -1;
                dev->chanmap[i] = -1;
                dev->m_idx[i] = -1;
                strcpy(dev->num[i], "???");
+               init_waitqueue_head(&dev->mdm.info[i].open_wait);
+               init_waitqueue_head(&dev->mdm.info[i].close_wait);
        }
        if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
                printk(KERN_WARNING "isdn: Could not register control devices\n");
index 6cb503b9f56682cc16ee20ec71feb225b56c0244..a8513fe5018ce455b9c5194abe16b6d56cff2335 100644 (file)
@@ -90,7 +90,7 @@ extern char *isdn_map_eaz2msn(char *msn, int di);
 extern void isdn_timer_ctrl(int tf, int onoff);
 extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
 extern int isdn_get_free_channel(int, int, int, int, int);
 extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int register_isdn(isdn_if * i);
index 5da3a49f034b2a195eafa15f510030918d37529b..aaaac3fdc7fa28ac30f1c67c8a42f09ef6537d5e 100644 (file)
@@ -359,8 +359,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 
        ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
 
-       if (ippp_table[lp->ppp_slot]->wq)
-               wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+       wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -377,7 +376,7 @@ isdn_ppp_closewait(int slot)
                return 0;
        is = ippp_table[slot];
 
-       if (is->state && is->wq)
+       if (is->state)
                wake_up_interruptible(&is->wq);
 
        is->state = IPPP_CLOSEWAIT;
@@ -437,8 +436,9 @@ isdn_ppp_open(int min, struct file *file)
        is->mru = 1524;         /* MRU, default 1524 */
        is->maxcid = 16;        /* VJ: maxcid */
        is->tk = current;
-       is->wq = NULL;          /* read() wait queue */
-       is->wq1 = NULL;         /* select() wait queue */
+       /* next two are redundant, but be paranoid */ 
+       init_waitqueue_head(&is->wq);  /* read() wait queue */
+       init_waitqueue_head(&is->wql);  /* select() wait queue */
        is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
        is->last = is->rq;
        is->minor = min;
@@ -777,8 +777,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
        is->last = bl->next;
        restore_flags(flags);
 
-       if (is->wq)
-               wake_up_interruptible(&is->wq);
+       wake_up_interruptible(&is->wq);
 
        return len;
 }
@@ -911,6 +910,8 @@ isdn_ppp_init(void)
                        return -1;
                }
                memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
+               init_waitqueue_head(&ippp_table[i]->wq); 
+               init_waitqueue_head(&ippp_table[i]->wql); 
                ippp_table[i]->state = 0;
                ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
                ippp_table[i]->last = ippp_table[i]->rq;
index a37178676938056aad13c505b86f17d7ef5433b3..1c77c6c009f6ff58ac4051b84e86872688e7e5b4 100644 (file)
@@ -1567,8 +1567,7 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 static int
 isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
 {
-       struct wait_queue wait =
-       {current, NULL};
+       DECLARE_WAITQUEUE(wait, current); 
        int do_clocal = 0;
        unsigned long flags;
        int retval;
@@ -2004,8 +2003,8 @@ isdn_tty_modem_init(void)
                info->blocked_open = 0;
                info->callout_termios = m->cua_modem.init_termios;
                info->normal_termios = m->tty_modem.init_termios;
-               info->open_wait = 0;
-               info->close_wait = 0;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->close_wait);
                info->isdn_driver = -1;
                info->isdn_channel = -1;
                info->drv_index = -1;
index da516f09ee6ceb593780c3eeaa01c44835ffb6d1..c845c33c260074e9a65e09091efd12b88e064edf 100644 (file)
@@ -203,6 +203,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( MOTOROLA,       MOTOROLA_MPC106,"MPC106 Grackle"),
        DEVICE( MOTOROLA,       MOTOROLA_RAVEN, "Raven"),
        DEVICE( PROMISE,        PROMISE_20246,  "IDE UltraDMA/33"),
+       DEVICE( PROMISE,        PROMISE_20262,  "IDE UltraDMA/66"),
        DEVICE( PROMISE,        PROMISE_5300,   "DC5030"),
        DEVICE( N9,             N9_I128,        "Imagine 128"),
        DEVICE( N9,             N9_I128_2,      "Imagine 128v2"),
@@ -290,11 +291,15 @@ struct pci_dev_info dev_info[] = {
        DEVICE( AL,             AL_M1523,       "M1523"),
        DEVICE( AL,             AL_M1531,       "M1531 Aladdin IV"),
        DEVICE( AL,             AL_M1533,       "M1533 Aladdin IV"),
+       DEVICE( AL,             AL_M1541,       "M1541 Aladdin V"),
+       DEVICE( AL,             AL_M1543,       "M1543 Aladdin V"),
        DEVICE( AL,             AL_M3307,       "M3307 MPEG-1 decoder"),
        DEVICE( AL,             AL_M4803,       "M4803"),
        DEVICE( AL,             AL_M5219,       "M5219"),
        DEVICE( AL,             AL_M5229,       "M5229 TXpro"),
        DEVICE( AL,             AL_M5237,       "M5237 USB"),
+       DEVICE( AL,             AL_M5243,       "M5243 AGP"),
+       DEVICE( AL,             AL_M7101,       "M7101 PMU"),
        DEVICE( SURECOM,        SURECOM_NE34,   "NE-34PCI LAN"),
        DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
        DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"),
index 632e3d08a5a886f8ed591ec348bacde4f12ece61..cb1d9f0883b3b3060c52e342d5002b6b4884f01b 100644 (file)
 mainmenu_option next_comment
 comment 'USB drivers - not for the faint of heart'
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
-  if [ ! "$CONFIG_USB" = "n" ]; then
-    bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
-    bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
-    bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
-    if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
-       bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
-    fi
-
-    bool 'USB mouse support' CONFIG_USB_MOUSE
-    bool 'USB keyboard support' CONFIG_USB_KBD
-    bool 'USB audio parsing support' CONFIG_USB_AUDIO
+tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
+if [ ! "$CONFIG_USB" = "n" ]; then
+  bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
+  bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+  bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
+  if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
+     bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
   fi
+
+  bool 'USB mouse support' CONFIG_USB_MOUSE
+  bool 'USB keyboard support' CONFIG_USB_KBD
+  bool 'USB audio parsing support' CONFIG_USB_AUDIO
 fi
 
 endmenu
index 6c6e7b091cc04ae9c04451982eb59d0a7b5ccdd0..bc40725d3460b882deb6b6ae2418f46cb7874da0 100644 (file)
@@ -32,6 +32,10 @@ ifeq ($(CONFIG_USB_AUDIO),y)
   USBX_OBJS += audio.o
 endif
 
+ifeq ($(CONFIG_USB_CPIA),y)
+  USBX_OBJS += cpia.o
+endif
+
 ifeq ($(CONFIG_USB), y)
   L_OBJS += $(USBX_OBJS)
 endif
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
new file mode 100644 (file)
index 0000000..004ea4e
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * USB CPiA Video Camera driver
+ *
+ * Supports CPiA based Video Camera's. Many manufacturers use this chipset.
+ * There's a good chance, if you have a USB video camera, it's a CPiA based
+ * one
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+#include "usb.h"
+#include "uhci.h"
+#include "cpia.h"
+
+#define MAX_FRAME_SIZE (384 * 288 * 3)
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+/* convert virtual user memory address to physical address */
+/* (virt_to_phys only works for kmalloced kernel memory) */
+
+static inline unsigned long uvirt_to_phys(unsigned long adr)
+{
+        pgd_t *pgd;
+        pmd_t *pmd;
+        pte_t *ptep, pte;
+  
+        pgd = pgd_offset(current->mm, adr);
+        if (pgd_none(*pgd))
+                return 0;
+        pmd = pmd_offset(pgd, adr);
+        if (pmd_none(*pmd))
+                return 0;
+        ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
+        pte = *ptep;
+        if(pte_present(pte))
+                return 
+                  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
+        return 0;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr) 
+{
+        return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
+}
+
+/* convert virtual kernel memory address to physical address */
+/* (virt_to_phys only works for kmalloced kernel memory) */
+
+static inline unsigned long kvirt_to_phys(unsigned long adr) 
+{
+        return uvirt_to_phys(VMALLOC_VMADDR(adr));
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr) 
+{
+        return uvirt_to_bus(VMALLOC_VMADDR(adr));
+}
+
+
+static void * rvmalloc(unsigned long size)
+{
+       void * mem;
+       unsigned long adr, page;
+        
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       mem=vmalloc(size);
+       if (mem) 
+       {
+               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+               adr=(unsigned long) mem;
+               while (size > 0) 
+               {
+                       page = kvirt_to_phys(adr);
+                       mem_map_reserve(MAP_NR(phys_to_virt(page)));
+                       adr+=PAGE_SIZE;
+                       if (size > PAGE_SIZE)
+                               size-=PAGE_SIZE;
+                       else
+                               size=0;
+               }
+       }
+       return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+       unsigned long adr, page;
+        
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       if (mem) 
+       {
+               adr=(unsigned long) mem;
+               while (size > 0) 
+               {
+                       page = kvirt_to_phys(adr);
+                       mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+                       adr+=PAGE_SIZE;
+                       if (size > PAGE_SIZE)
+                               size-=PAGE_SIZE;
+                       else
+                               size=0;
+               }
+               vfree(mem);
+       }
+}
+
+int usb_cpia_get_version(struct usb_device *dev, void *buf)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
+       dr.request = USB_REQ_CPIA_GET_VERSION;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 4;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4);
+}
+
+int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
+       dr.request = USB_REQ_CPIA_GET_PNP_ID;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 6;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6);
+}
+
+int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
+       dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 8;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8);
+}
+
+int usb_cpia_goto_hi_power(struct usb_device *dev)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_GOTO_HI_POWER;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_GET_VP_VERSION;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 4;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4);
+}
+
+int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_SET_SENSOR_FPS;
+       dr.value = (sensorclkdivisor << 8) + sensorbaserate;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_GRAB_FRAME;
+       dr.value = streamstartline << 8;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_UPLOAD_FRAME;
+       dr.value = forceupload;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_SET_GRAB_MODE;
+       dr.value = continuousgrab;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_SET_FORMAT;
+       dr.value = (subsample << 8) + size;
+       dr.index = order;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_SET_COMPRESSION;
+       dr.value = (decimation << 8) + compmode;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_INIT_STREAM_CAP;
+       dr.value = (streamstartline << 8) + skipframes;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_finistreamcap(struct usb_device *dev)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_FINI_STREAM_CAP;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_startstreamcap(struct usb_device *dev)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_START_STREAM_CAP;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_cpia_endstreamcap(struct usb_device *dev)
+{
+       devrequest dr;
+
+       dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
+       dr.request = USB_REQ_CPIA_END_STREAM_CAP;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+#define scratch_left(x)        (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
+
+static void cpia_parse_data(struct usb_cpia *cpia)
+{
+       unsigned char *data = cpia->scratch;
+       int done;
+
+       done = 0;
+       while (!done && scratch_left(data)) {
+               switch (cpia->state) {
+               case STATE_SCANNING:
+               {
+                       unsigned char *begin = data;
+
+                       /* We need atleast 2 bytes for the magic value */
+                       if (scratch_left(data) < 2) {
+                               done = 1;
+                               break;
+                       }
+
+                       printk("header: %X\n", (*data << 8) + *(data + 1));
+                       if ((*data == 0x19) && (*(data + 1) == 0x68)) {
+                               cpia->state = STATE_HEADER;
+                               printk("moving to header\n");
+                               break;
+                       }
+
+                       if (scratch_left(data) < 4) {
+                               done = 1;
+                               break;
+                       }
+
+                       printk("Scanning for end of frame\n");
+                       while (scratch_left(data) >= 4) {
+                               if ((*data == 0xFF) &&
+                                       (*(data + 1) == 0xFF) &&
+                                       (*(data + 2) == 0xFF) &&
+                                       (*(data + 3) == 0xFF)) {
+                                       data += 4;
+                                       break;
+                               }
+                               data++;
+                       }
+printk("scan: scanned %d bytes\n", data-begin);
+                       break;
+               }
+               case STATE_HEADER:
+                       /* We need atleast 64 bytes for the header */
+                       if (scratch_left(data) < 64) {
+                               done = 1;
+                               break;
+                       }
+
+printk("header: framerate %d\n", data[41]);
+
+                       data += 64;
+
+                       cpia->state = STATE_LINES;
+                               
+                       break;
+               case STATE_LINES:
+               {
+                       unsigned char *begin = data;
+                       int found = 0;
+
+                       while (scratch_left(data)) {
+                               if (*data == 0xFD) {
+                                       data++;
+                                       found = 1;
+                                       break;
+                               } else if ((*data == 0xFF) &&
+                                       (scratch_left(data) >= 3) &&
+                                       (*(data + 1) == 0xFF) &&
+                                       (*(data + 2) == 0xFF) &&
+                                       (*(data + 3) == 0xFF)) {
+                                       data+=4;
+                                       cpia->curline = 144;
+                                       found = 1;
+                                       break;
+                               }
+
+                               data++;
+                       }
+#if 0
+printk("line %d: scanned %d bytes\n", cpia->curline, data-begin);
+#endif
+if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
+       int i;
+       char *f = cpia->frame[cpia->curframe].data, *b = begin;
+
+#if 0
+printk("copying\n");
+#endif
+
+       b+=2;
+       f+=(cpia->frame[cpia->curframe].width*3)*cpia->curline;
+       for (i = 0; i < 176; i++)
+               f[(i * 3) + 0] =
+               f[(i * 3) + 1] =
+               f[(i * 3) + 2] =
+                       b[(i * 2)];
+}
+                       if (found) {
+                               cpia->curline++;
+                               if (cpia->curline >= 144) {
+                                       wake_up(&cpia->wq);
+                                       cpia->state = STATE_SCANNING;
+                                       cpia->curline = 0;
+                                       cpia->curframe = -1;
+                                       done = 1;
+                               }
+                       } else {
+                               data = begin;
+                               done = 1;
+                       }
+                       
+                       break;
+               }
+               }
+       }
+
+       {
+       int l;
+
+       l = scratch_left(data);
+       memmove(cpia->scratch, data, l);
+       cpia->scratchlen = l;
+       }
+}
+
+static int cpia_isoc_irq(int status, void *__buffer, void *dev_id)
+{
+       struct usb_cpia *cpia = dev_id;
+       struct usb_device *dev = cpia->dev;
+       struct cpia_sbuf *sbuf;
+       int i;
+       char *p;
+
+       if (!cpia->streaming) {
+               printk("oops, not streaming, but interrupt\n");
+               return 0;
+       }
+       
+       if (cpia->curframe < 0) {
+               if (cpia->frame[0].state == FRAME_READY) {
+                       cpia->curframe = 0;
+                       cpia->frame[0].state = FRAME_GRABBING;
+printk("capturing to frame 0\n");
+               } else if (cpia->frame[1].state == FRAME_READY) {
+                       cpia->curframe = 1;
+                       cpia->frame[1].state = FRAME_GRABBING;
+printk("capturing to frame 1\n");
+               } else
+printk("no frame available\n");
+       }
+
+       sbuf = &cpia->sbuf[cpia->receivesbuf];
+
+       uhci_unsched_isochronous(dev, sbuf->isodesc);
+
+       /* Do something to it now */
+       sbuf->len = uhci_compress_isochronous(dev, sbuf->isodesc);
+
+       if (sbuf->len)
+       printk("%d bytes received\n", sbuf->len);
+
+       if (sbuf->len && cpia->curframe >= 0) {
+               if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) {
+                       printk("overflow!\n");
+                       return 0;
+               }
+               memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len);
+               cpia->scratchlen += sbuf->len;
+
+               cpia_parse_data(cpia);
+       }
+
+       /* Reschedule this block of Isochronous desc */
+       uhci_sched_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
+
+       /* Move to the next one */
+       cpia->receivesbuf = (cpia->receivesbuf + 1) % 3;
+
+       return 1;
+}
+
+int cpia_init_isoc(struct usb_cpia *cpia)
+{
+       struct usb_device *dev = cpia->dev;
+
+       cpia->receivesbuf = 0;
+
+#if 0
+       cpia->parsesbuf = 0;
+       cpia->parsepos = 0;
+#endif
+       cpia->scratchlen = 0;
+       cpia->curline = 0;
+       cpia->state = STATE_SCANNING;
+
+       /* Allocate all of the memory necessary */
+       cpia->sbuf[0].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+       cpia->sbuf[1].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+       cpia->sbuf[2].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+
+       printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
+       printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
+       printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
+
+       /* Schedule the queues */
+       uhci_sched_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
+       uhci_sched_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+       uhci_sched_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
+
+       if (usb_set_interface(cpia->dev, 1, 3)) {
+               printk("cpia_set_interface error\n");
+               return -EINVAL;
+       }
+
+       usb_cpia_startstreamcap(cpia->dev);
+
+       cpia->streaming = 1;
+
+       return 0;
+}
+
+void cpia_stop_isoc(struct usb_cpia *cpia)
+{
+       struct usb_device *dev = cpia->dev;
+
+       if (!cpia->streaming)
+               return;
+
+       cpia->streaming = 0;
+
+       /* Stop the streaming */
+       usb_cpia_endstreamcap(cpia->dev);
+
+       /* Set packet size to 0 */
+       if (usb_set_interface(cpia->dev, 1, 0)) {
+               printk("cpia_set_interface error\n");
+               return -EINVAL;
+       }
+
+       /* Unschedule all of the iso td's */
+       uhci_unsched_isochronous(dev, cpia->sbuf[2].isodesc);
+       uhci_unsched_isochronous(dev, cpia->sbuf[1].isodesc);
+       uhci_unsched_isochronous(dev, cpia->sbuf[0].isodesc);
+
+       /* Delete them all */
+       uhci_delete_isochronous(dev, cpia->sbuf[2].isodesc);
+       uhci_delete_isochronous(dev, cpia->sbuf[1].isodesc);
+       uhci_delete_isochronous(dev, cpia->sbuf[0].isodesc);
+}
+
+/* Video 4 Linux API */
+static int cpia_open(struct video_device *dev, int flags)
+{
+       struct usb_cpia *cpia = (struct usb_cpia *)dev;
+
+printk("cpia_open\n");
+
+       cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
+       if (!cpia->fbuf)
+               return -ENOMEM;
+
+       cpia->frame[0].state = FRAME_DONE;
+       cpia->frame[1].state = FRAME_DONE;
+
+       cpia->frame[0].data = cpia->fbuf;
+       cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
+       printk("frame [0] @ %p\n", cpia->frame[0].data);
+       printk("frame [1] @ %p\n", cpia->frame[1].data);
+
+       cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
+       if (!cpia->sbuf[0].data)
+               return -ENOMEM;
+
+       cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
+       if (!cpia->sbuf[1].data)
+               return -ENOMEM;
+
+       cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
+       if (!cpia->sbuf[2].data)
+               return -ENOMEM;
+
+       printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
+       printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
+       printk("sbuf[2] @ %p\n", cpia->sbuf[2].data);
+
+       cpia->curframe = -1;
+       cpia->receivesbuf = 0;
+
+       usb_cpia_initstreamcap(cpia->dev, 0, 60);
+
+       cpia_init_isoc(cpia);
+
+       return 0;
+}
+
+static void cpia_close(struct video_device *dev)
+{
+       struct usb_cpia *cpia = (struct usb_cpia *)dev;
+
+printk("cpia_close\n");
+
+       cpia_stop_isoc(cpia);
+
+       usb_cpia_finistreamcap(cpia->dev);
+
+       rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
+
+       kfree(cpia->sbuf[2].data);
+       kfree(cpia->sbuf[1].data);
+       kfree(cpia->sbuf[0].data);
+}
+
+static int cpia_init_done(struct video_device *dev)
+{
+       return 0;
+}
+
+static long cpia_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+       return -EINVAL;
+}
+
+#if 0
+       if (usb_set_interface(dev, 1, 3)) {
+               printk("cpia_set_interface error\n");
+               return -EINVAL;
+       }
+
+       if (usb_cpia_grab_frame(dev, 0)) {
+               printk("cpia_grab_frame error\n");
+               return -EINVAL;
+       }
+
+       if (usb_cpia_upload_frame(dev, 0)) {
+               printk("cpia_upload_frame error\n");
+               return -EINVAL;
+       }
+
+       buf = cpia->ibuf;
+       uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 176*144*4);
+
+       {
+       printk("header magic: %X\n", (buf[0] << 8) + buf[1]);
+
+       while ((buf[0] != 0x19) || (buf[1] != 0x68)) {
+               int i;
+
+               printk("resync'ing\n");
+               for (i=0;i<(176*144*4)-4;i++, buf++)
+                       if (
+                               (buf[0] == 0xFF) &&
+                               (buf[1] == 0xFF) &&
+                               (buf[2] == 0xFF) &&
+                               (buf[3] == 0xFF)) {
+                               buf+=4;
+                               i+=4;
+                               break;
+                       }
+
+               memmove(cpia->ibuf, buf, (176*144*4) - i);
+               uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->ibuf + (176*144*4) - i, i);
+               buf = cpia->ibuf;
+
+#if 0
+               printk("header magic: %X\n", (buf[0] << 8) + buf[1]);
+#endif
+       }
+
+       printk("size: %d, sample: %d, order: %d\n", buf[16], buf[17], buf[18]);
+       printk("comp: %d, decimation: %d\n", buf[28], buf[29]);
+       printk("roi: top left: %d, %d bottom right: %d, %d\n",
+               buf[26] * 4, buf[24] * 8,
+               buf[27] * 4, buf[25] * 8);
+
+       printk("vm->frame: %d\n", vm->frame);
+
+       {
+       int i, i1;
+       char *b = buf + 64, *fbuf = &cpia->fbuffer[MAX_FRAME_SIZE * (vm->frame & 1)];
+       for (i=0;i<144;i++) {
+#if 0
+               printk("line len: %d\n", (b[1] << 8) + b[0]);
+#endif
+               b += 2;
+               for (i1=0;i1<176;i1++) {
+                       fbuf[(i * vm->width * 3) + (i1 * 3)] = 
+                       fbuf[(i * vm->width * 3) + (i1 * 3) + 1] = 
+                       fbuf[(i * vm->width * 3) + (i1 * 3) + 2] = 
+                               b[i1 * 2];
+#if 0
+                       *((short *)&fbuf[(i * vm->width * 2) + (i1 * 2)]) =
+                               ((b[i1 * 2] >> 3) << 11) + ((b[i1 * 2] >> 2) << 6) + (b[i1 * 2] >> 3);
+#endif
+               }
+               b += (176 * 2) + 1;
+       }
+       }
+
+       }
+
+       if (usb_set_interface(dev, 1, 0)) {
+               printk("cpia_set_interface error\n");
+               return -EINVAL;
+       }
+#endif
+
+static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct usb_cpia *cpia = (struct usb_cpia *)dev;
+
+       switch (cmd) {
+               case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+
+                       strcpy(b.name, "CPiA USB Camera");
+                       b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */;
+                       b.channels = 1;
+                       b.audios = 0;
+                       b.maxwidth = 176 /* 352 */;
+                       b.maxheight = 144 /* 240 */;
+                       b.minwidth = 176 /* (Something small?) */;
+                       b.minheight = 144 /* "         " */;
+
+                       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;
+                       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)))
+                               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)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCSTUNER:
+               {
+                       struct video_tuner v;
+
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               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;      /* Damn British people :) */
+                       p.hue = 0x8000;
+                       p.brightness = 180 << 8;        /* XXX */
+                       p.contrast = 192 << 8;          /* XXX */
+                       p.whiteness = 105 << 8;         /* XXX */
+#if 0
+                       p.depth = 24;
+#endif
+                       p.depth = 16;
+                       p.palette = VIDEO_PALETTE_YUYV;
+
+                       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;
+
+printk("Attempting to set palette %d, depth %d\n", p.palette, p.depth);
+
+#if 0
+                       if (p.palette != VIDEO_PALETTE_YUYV)
+                               return -EINVAL;
+                       if (p.depth != 16)
+                               return -EINVAL;
+#endif
+
+                       return 0;
+               }
+               case VIDIOCSWIN:
+               {
+                       struct video_window vw;
+
+printk("VIDIOCSWIN\n");
+                       if (copy_from_user(&vw, arg, sizeof(vw)))
+                               return -EFAULT;
+                       if (vw.flags)
+                               return -EINVAL;
+                       if (vw.clipcount)
+                               return -EINVAL;
+                       if (vw.height != 176)
+                               return -EINVAL;
+                       if (vw.width != 144)
+                               return -EINVAL;
+
+                       return 0;
+               }
+               case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+
+printk("VIDIOCGWIN\n");
+                       vw.x = 0;
+                       vw.y = 0;
+                       vw.width = 176;
+                       vw.height = 144;
+                       vw.chromakey = 0;
+                       vw.flags = 0;
+
+                       if (copy_to_user(arg, &vw, sizeof(vw)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCGMBUF:
+               {
+                       struct video_mbuf vm;
+
+                       memset(&vm, 0, sizeof(vm));
+                       vm.size = MAX_FRAME_SIZE * 2;
+                       vm.frames = 2;
+                       vm.offsets[0] = 0;
+                       vm.offsets[1] = MAX_FRAME_SIZE;
+
+                       if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap vm;
+
+                       if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+                               return -EFAULT;
+
+printk("MCAPTURE\n");
+printk("frame: %d, size: %dx%d, format: %d\n", vm.frame, vm.width, vm.height, vm.format);
+
+                       if (vm.format != VIDEO_PALETTE_RGB24)
+                               return -EINVAL;
+
+                       if ((vm.frame != 0) && (vm.frame != 1))
+                               return -EINVAL;
+
+                       cpia->frame[vm.frame].width = vm.width;
+                       cpia->frame[vm.frame].height = vm.height;
+
+                       /* Mark it as free */
+                       cpia->frame[vm.frame].state = FRAME_READY;
+
+                       return 0;
+               }
+               case VIDIOCSYNC:
+               {
+                       int frame;
+
+                       if (copy_from_user((void *)&frame, arg, sizeof(int)))
+                               return -EFAULT;
+
+                       printk("syncing to frame %d\n", frame);
+                       switch (cpia->frame[frame].state) {
+                               case FRAME_UNUSED:
+                                       return -EINVAL;
+                               case FRAME_READY:
+                               case FRAME_GRABBING:
+                                       interruptible_sleep_on(&cpia->wq);
+                               case FRAME_DONE:
+                                       cpia->frame[frame].state = FRAME_UNUSED;
+                                       break;
+                       }
+                       printk("synced to frame %d\n", frame);
+                       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 cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+       struct usb_cpia *cpia = (struct usb_cpia *)dev;
+       int len;
+
+       printk("cpia_read: %d bytes\n", count);
+#if 0
+       len = cpia_capture(cpia, buf, count);
+
+       return len;
+#endif
+       return 0;
+}
+
+static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+       struct usb_cpia *cpia = (struct usb_cpia *)dev;
+       unsigned long start = (unsigned long)adr;
+       unsigned long page, pos;
+
+       printk("mmap: %d (%X) bytes\n", size, size);
+       if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+               return -EINVAL;
+
+#if 0
+       if (!cpia->fbuffer) {
+               if ((cpia->fbuffer = rvmalloc(2 * MAX_FRAME_SIZE)) == NULL)
+                       return -EINVAL;
+       }
+#endif
+
+       pos = (unsigned long)cpia->fbuf;
+       while (size > 0)
+       {
+               page = kvirt_to_phys(pos);
+               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+               start+=PAGE_SIZE;
+               pos+=PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size-=PAGE_SIZE;
+               else
+                       size=0;
+       }
+
+       return 0;
+}
+
+static struct video_device cpia_template = {
+       "CPiA USB Camera",
+       VID_TYPE_CAPTURE,
+       VID_HARDWARE_CPIA,
+       cpia_open,
+       cpia_close,
+       cpia_read,
+       cpia_write,
+       NULL,
+       cpia_ioctl,
+       cpia_mmap,
+       cpia_init_done,
+       NULL,
+       0,
+       0
+};
+
+static void usb_cpia_configure(struct usb_cpia *cpia)
+{
+       struct usb_device *dev = cpia->dev;
+       unsigned char version[4];
+       unsigned char pnpid[6];
+       unsigned char camerastat[8];
+       unsigned char *buf;
+
+       usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+
+       if (usb_cpia_get_version(dev, version)) {
+               printk("cpia_get_version error\n");
+               return;
+       }
+
+       printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
+               version[0], version[1], version[2], version[3]);
+
+       if (usb_cpia_get_pnp_id(dev, pnpid)) {
+               printk("cpia_get_pnp_id error\n");
+               return;
+       }
+
+       printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n",
+               (pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2],
+               (pnpid[5] << 8) + pnpid[4]);
+
+       memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
+
+       init_waitqueue_head(&cpia->wq);
+
+       if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
+               printk("video_register_device failed\n");
+               return;
+       }
+
+       if (usb_cpia_goto_hi_power(dev)) {
+               printk("cpia_goto_hi_power error\n");
+               return;
+       }
+
+       if (usb_cpia_get_vp_version(dev, version)) {
+               printk("cpia_get_vp_version error\n");
+               return;
+       }
+
+       printk("cpia: VP v%d rev %d\n", version[0], version[1]);
+       printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
+
+       /* Turn off continuous grab */
+       if (usb_cpia_set_grab_mode(dev, 1)) {
+               printk("cpia_set_grab_mode error\n");
+               return;
+       }
+
+       /* Set up the sensor to be 30fps */
+       if (usb_cpia_set_sensor_fps(dev, 1, 0)) {
+               printk("cpia_set_sensor_fps error\n");
+               return;
+       }
+
+       /* Set video into QCIF mode, and order into YUYV mode */
+       if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) {
+               printk("cpia_set_format error\n");
+               return;
+       }
+
+       /* Turn off compression */
+       if (usb_cpia_set_compression(dev, 0, 0)) {
+               printk("cpia_set_compression error\n");
+               return;
+       }
+
+#if 0
+       if (usb_cpia_grab_frame(dev, 0)) {
+               printk("cpia_grab_frame error\n");
+               return;
+       }
+
+       if (usb_cpia_upload_frame(dev, 1)) {
+               printk("cpia_upload_frame error\n");
+               return;
+       }
+
+       buf = (void *)__get_free_page(GFP_KERNEL);
+
+       {
+       int i;
+       for (i=0;i<448;i++)
+               buf[i]=0;
+       }
+       uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 448);
+
+       {
+       int i;
+       for (i=0;i<448;i++) {
+               printk("%02X ", buf[i]);
+               if ((i % 16) == 15)
+                       printk("\n");
+       }
+       printk("\n");
+       }
+
+       free_page((unsigned long)buf);
+#endif
+}
+
+static int cpia_probe(struct usb_device *dev)
+{
+       struct usb_interface_descriptor *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_cpia *cpia;
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -1;
+
+#if 0
+       /* We don't handle multi-interface hubs */
+       if (dev->config[0].bNumInterfaces != 1)
+               return -1;
+#endif
+
+       interface = &dev->config[0].interface[0];
+
+       /* Is it a CPiA? */
+/*
+Apr 24 17:49:04 bjorn kernel:   Vendor:  0545 
+Apr 24 17:49:04 bjorn kernel:   Product: 8080 
+*/
+/*
+       if (dev->descriptor.idVendor != 0x0545)
+               return -1;
+       if (dev->descriptor.idProduct != 0x8080)
+               return -1;
+       if (interface->bInterfaceClass != 0xFF)
+               return -1;
+       if (interface->bInterfaceSubClass != 0xFF)
+               return -1;
+*/
+       if (dev->descriptor.idVendor != 0x0553)
+               return -1;
+       if (dev->descriptor.idProduct != 0x0002)
+               return -1;
+       if (interface->bInterfaceClass != 0xFF)
+               return -1;
+       if (interface->bInterfaceSubClass != 0x00)
+               return -1;
+
+#if 0
+       /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+       if (interface->bNumEndpoints != 1)
+               return -1;
+
+       endpoint = &interface->endpoint[0];
+
+       /* Output endpoint? Curiousier and curiousier.. */
+       if (!(endpoint->bEndpointAddress & 0x80))
+               return -1;
+
+       /* If it's not an interrupt endpoint, we'd better punt! */
+       if ((endpoint->bmAttributes & 3) != 3)
+               return -1;
+#endif
+
+       /* We found a CPiA */
+       printk("USB CPiA camera found\n");
+
+       if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
+               printk("couldn't kmalloc cpia struct\n");
+               return -1;
+       }
+
+       memset(cpia, 0, sizeof(*cpia));
+
+       dev->private = cpia;
+       cpia->dev = dev;
+
+       usb_cpia_configure(cpia);
+
+#if 0
+       usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), pport_irq, endpoint->bInterval, pport);
+#endif
+
+       return 0;
+}
+
+static void cpia_disconnect(struct usb_device *dev)
+{
+       struct usb_cpia *cpia = dev->private;
+
+       video_unregister_device(&cpia->vdev);
+
+       /* Free the memory */
+       kfree(cpia);
+}
+
+static struct usb_driver cpia_driver = {
+       "cpia",
+       cpia_probe,
+       cpia_disconnect,
+       { NULL, NULL }
+};
+
+/*
+ * This should be a separate module.
+ */
+int cpia_init(void)
+{
+       usb_register(&cpia_driver);
+
+       return 0;
+}
+
diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h
new file mode 100644 (file)
index 0000000..51ff43e
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef __LINUX_CPIA_H
+#define __LINUX_CPIA_H
+
+#include <linux/list.h>
+
+#define USB_REQ_CPIA_GET_VERSION               0x01
+#define USB_REQ_CPIA_GET_PNP_ID                        0x02
+#define USB_REQ_CPIA_GET_CAMERA_STATUS         0x03
+#define USB_REQ_CPIA_GOTO_HI_POWER             0x04
+#define USB_REQ_CPIA_GOTO_LO_POWER             0x05
+/* No 0x06 */
+#define USB_REQ_CPIA_GOTO_SUSPEND              0x07
+#define USB_REQ_CPIA_GOTO_PASS_THROUGH         0x08
+/* No 0x09 */
+#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS      0x0A
+
+#define USB_REQ_CPIA_READ_VC_REGS              0x21
+#define USB_REQ_CPIA_WRITE_BC_REG              0x22
+#define USB_REQ_CPIA_READ_MC_PORTS             0x23
+#define USB_REQ_CPIA_WRITE_MC_PORT             0x24
+#define USB_REQ_CPIA_SET_BAUD_RATE             0x25
+#define USB_REQ_CPIA_SET_ECP_TIMING            0x26
+#define USB_REQ_CPIA_READ_IDATA                        0x27
+#define USB_REQ_CPIA_WRITE_IDATA               0x28
+#define USB_REQ_CPIA_GENERIC_CALL              0x29
+#define USB_REQ_CPIA_I2CSTART                  0x2A
+#define USB_REQ_CPIA_I2CSTOP                   0x2B
+#define USB_REQ_CPIA_I2CWRITE                  0x2C
+#define USB_REQ_CPIA_I2CREAD                   0x2D
+
+#define USB_REQ_CPIA_GET_VP_VERSION            0xA1
+#define USB_REQ_CPIA_SET_COLOUR_PARAMS         0xA3
+#define USB_REQ_CPIA_SET_EXPOSURE              0xA4
+/* No 0xA5 */
+#define USB_REQ_CPIA_SET_COLOUR_BALANCE                0xA6
+#define USB_REQ_CPIA_SET_SENSOR_FPS            0xA7
+#define USB_REQ_CPIA_SET_VP_DEFAULTS           0xA8
+#define USB_REQ_CPIA_SET_APCOR                 0xA9
+#define USB_REQ_CPIA_SET_FLICKER_CTRL          0xAA
+#define USB_REQ_CPIA_SET_VL_OFFSET             0xAB
+
+#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS     0xB0
+#define USB_REQ_CPIA_GET_COLOUR_BALANCE                0xB1
+#define USB_REQ_CPIA_GET_EXPOSURE              0xB2
+#define USB_REQ_CPIA_SET_SENSOR_MATRIX         0xB3
+
+#define USB_REQ_CPIA_COLOUR_BARS               0xBD
+#define USB_REQ_CPIA_READ_VP_REGS              0xBE
+#define USB_REQ_CPIA_WRITE_VP_REGS             0xBF
+
+#define USB_REQ_CPIA_GRAB_FRAME                        0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME              0xC2
+#define USB_REQ_CPIA_SET_GRAB_MODE             0xC3
+#define USB_REQ_CPIA_INIT_STREAM_CAP           0xC4
+#define USB_REQ_CPIA_FINI_STREAM_CAP           0xC5
+#define USB_REQ_CPIA_START_STREAM_CAP          0xC6
+#define USB_REQ_CPIA_END_STREAM_CAP            0xC7
+#define USB_REQ_CPIA_SET_FORMAT                        0xC8
+#define USB_REQ_CPIA_SET_ROI                   0xC9
+#define USB_REQ_CPIA_SET_COMPRESSION           0xCA
+#define USB_REQ_CPIA_SET_COMPRESSION_TARGET    0xCB
+#define USB_REQ_CPIA_SET_YUV_THRESH            0xCC
+#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS    0xCD
+#define USB_REQ_CPIA_DISCARD_FRAME             0xCE
+
+#define USB_REQ_CPIA_OUTPUT_RS232              0xE1
+#define USB_REQ_CPIA_ABORT_PROCESS             0xE4
+#define USB_REQ_CPIA_SET_DRAM_PAGE             0xE5
+#define USB_REQ_CPIA_START_DRAM_UPLOAD         0xE6
+#define USB_REQ_CPIA_START_DUMMY_STREAM                0xE8
+#define USB_REQ_CPIA_ABORT_STREAM              0xE9
+#define USB_REQ_CPIA_DOWNLOAD_DRAM             0xEA
+/* #define USB_REQ_CPIA_NULL_CMD               0x?? */
+
+#define CPIA_QCIF      0
+#define CPIA_CIF       1
+
+#define CPIA_YUYV      0
+#define CPIA_UYVY      1
+
+#define STREAM_BUF_SIZE        (PAGE_SIZE * 4)
+
+#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+
+enum {
+       STATE_SCANNING,         /* Scanning for start */
+       STATE_HEADER,           /* Parsing header */
+       STATE_LINES,            /* Parsing lines */
+};
+
+struct usb_device;
+
+struct cpia_sbuf {
+       char *data;
+       int len;
+       void *isodesc;
+};
+
+enum {
+       FRAME_READY,            /* Ready to grab into */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+};
+
+struct cpia_frame {
+       char *data;
+       int width;
+       int height;
+       int state;
+};
+
+struct usb_cpia {
+       struct video_device vdev;
+
+       /* Device structure */
+       struct usb_device *dev;
+
+       int streaming;
+
+       char *fbuf;                     /* Videodev buffer area */
+
+       int curframe;
+       struct cpia_frame frame[2];     /* Double buffering */
+
+       int receivesbuf;                /* Current receiving sbuf */
+       struct cpia_sbuf sbuf[3];       /* Triple buffering */
+
+       int state;                      /* Current scanning state */
+       int curline;
+
+       char scratch[SCRATCH_BUF_SIZE];
+       int scratchlen;
+
+       wait_queue_head_t wq;
+};
+
+#endif
+
index 59b93bd82f6c2369181d49a9944515ee6ac200ea..1e98f5e8d42a67b832f06e0db79ae5a9112d70f8 100644 (file)
@@ -54,11 +54,7 @@ struct mouse_state {
        /* but we will also need a list of file pointers to identify it */
 };
 
-static struct mouse_state static_mouse_state = {
-       0, 0, 0, 0,
-       0, 0, 0,
-       __WAIT_QUEUE_HEAD_INITIALIZER(static_mouse_state.wait),
-};
+static struct mouse_state static_mouse_state;
 
 spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
 
@@ -281,7 +277,7 @@ int usb_mouse_init(void)
        misc_register(&usb_mouse);
 
        mouse->present = mouse->active = 0;
-       mouse->wait = NULL;
+       init_waitqueue_head(&mouse->wait);
        mouse->fasync = NULL;
 
        usb_register(&mouse_driver);
index c9a57627aa215d7155f44d87777e6649a3c81d44..f0fb1332d9da8b18626d487c012f8644ddc754de 100644 (file)
@@ -61,15 +61,17 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
        /* Some debugging code */
        if (status) {
                int i = 10;
-               struct uhci_td *tmp = dev->control_td;
+               struct uhci_td *tmp = td->first;
                printk("uhci_td_result() failed with status %d\n", status);
                show_status(dev->uhci);
                do {
                        show_td(tmp);
-                       tmp++;
+                       if ((tmp->link & 1) || (tmp->link & 2))
+                               break;
+                       tmp = bus_to_virt(tmp->link & ~0xF);
                        if (!--i)
                                break;
-               } while (tmp <= td);
+               } while (1);
        }
        return status;          
 }
@@ -279,7 +281,7 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
        unsigned int destination, status;
 
        /* Destination: pipe destination with INPUT */
-       destination = (pipe & 0x0007ff00)  |  0x69;
+       destination = (pipe & 0x0007ff00) | 0x69;
 
        /* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
        status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
@@ -292,6 +294,7 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
        td->status = status;                    /* In */
        td->info = destination | (7 << 21);     /* 8 bytes of data */
        td->buffer = virt_to_bus(dev->data);
+       td->first = td;
        td->qh = interrupt_qh;
        interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh;
 
@@ -304,6 +307,202 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
        return 0;
 }
 
+/*
+ * Isochronous thread operations
+ */
+
+int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
+{
+       struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
+       char *data = isodesc->data;
+       int i, totlen = 0;
+
+       for (i = 0; i < isodesc->num; i++) {
+               char *cdata = bus_to_virt(isodesc->td[i].buffer & ~0xF);
+               int n = (isodesc->td[i].status + 1) & 0x7FF;
+
+               if ((cdata != data) && (n))
+                       memmove(data, cdata, n);
+
+#if 0
+if (n && n != 960)
+       printk("underrun: %d %d\n", i, n);
+#endif
+if ((isodesc->td[i].status >> 16) & 0xFF)
+       printk("error: %d %X\n", i, (isodesc->td[i].status >> 16));
+
+               data += n;
+               totlen += n;
+       }
+
+       return totlen;
+}
+
+int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       struct uhci *uhci = dev->uhci;
+       struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
+       int i;
+
+       if ((isodesc->frame < 0) || (isodesc->frame > 1023))
+               return 1;
+
+       /* Remove from previous frames */
+       for (i = 0; i < isodesc->num; i++) {
+               /* Turn off Active and IOC bits */
+               isodesc->td[i].status &= ~(3 << 23);
+               uhci->fl->frame[(isodesc->frame + i) % 1024] = isodesc->td[i].link;
+       }
+
+       isodesc->frame = -1;
+
+       return 0;
+}
+       
+/* td points to the one td we allocated for isochronous transfers */
+int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       struct uhci *uhci = dev->uhci;
+       struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
+       struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc;
+       int frame, i;
+
+       if (isodesc->frame != -1) {
+               printk("isoc queue not removed\n");
+               uhci_unsched_isochronous(usb_dev, isodesc);
+       }
+
+       /* Insert TD into list */
+       if (!pisodesc) {
+               frame = inw(uhci->io_addr + USBFRNUM) % 1024;
+               /* HACK: Start 2 frames from now */
+               frame = (frame + 2) % 1024;
+       } else
+               frame = (pisodesc->endframe + 1) % 1024;
+
+#if 0
+printk("scheduling first at frame %d\n", frame);
+#endif
+
+       for (i = 0; i < isodesc->num; i++) {
+               /* Active */
+               isodesc->td[i].status |= (1 << 23);
+               isodesc->td[i].backptr = &uhci->fl->frame[(frame + i) % 1024];
+               isodesc->td[i].link = uhci->fl->frame[(frame + i) % 1024];
+               uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(&isodesc->td[i]);
+       }
+
+#if 0
+printk("last at frame %d\n", (frame + i - 1) % 1024);
+#endif
+
+       /* Interrupt */
+       isodesc->td[i - 1].status |= (1 << 24);
+
+       isodesc->frame = frame;
+       isodesc->endframe = (frame + isodesc->num - 1) % 1024;
+
+#if 0
+       return uhci_td_result(dev, td[num - 1]);
+#endif
+       return 0;
+}
+
+/*
+ * Initialize isochronous queue
+ */
+void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       unsigned long destination, status;
+       struct uhci_td *td;
+       int ret, i;
+       struct uhci_iso_td *isodesc;
+
+       isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
+       if (!isodesc) {
+               printk("Couldn't allocate isodesc!\n");
+               return NULL;
+       }
+       memset(isodesc, 0, sizeof(*isodesc));
+
+       /* Carefully work around the non contiguous pages */
+       isodesc->num = (len / PAGE_SIZE) * (PAGE_SIZE / maxsze);
+       isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL);
+       isodesc->frame = isodesc->endframe = -1;
+       isodesc->data = data;
+       isodesc->maxsze = maxsze;
+       
+       if (!isodesc->td) {
+               printk("Couldn't allocate td's\n");
+               kfree(isodesc);
+               return NULL;
+       }
+
+       isodesc->frame = isodesc->endframe = -1;
+
+       /*
+        * Build the DATA TD's
+        */
+       i = 0;
+       do {
+               /* Build the TD for control status */
+               td = &isodesc->td[i];
+
+               /* The "pipe" thing contains the destination in bits 8--18 */
+               destination = (pipe & 0x0007ff00);
+
+               if (usb_pipeout(pipe))
+                       destination |= 0xE1;    /* OUT */
+               else
+                       destination |= 0x69;    /* IN */
+
+               /* Status:    slow/fast,       Active,       Isochronous */
+               status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 25);
+
+               /*
+                * Build the TD for the control request
+                */
+               td->status = status;
+               td->info = destination | ((maxsze - 1) << 21);
+               td->buffer = virt_to_bus(data);
+               td->first = td;
+               td->backptr = NULL;
+
+               i++;
+
+               data += maxsze;
+
+               if (((int)data % PAGE_SIZE) + maxsze >= PAGE_SIZE)
+                       data = (char *)(((int)data + maxsze) & ~(PAGE_SIZE - 1));
+               
+               len -= maxsze;
+       } while (i < isodesc->num);
+
+       /* IOC on the last TD */
+       td->status |= (1 << 24);
+       uhci_add_irq_list(dev->uhci, td, completed, dev_id);
+
+       return isodesc;
+}
+
+void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
+{
+       struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
+
+       /* If it's still scheduled, unschedule them */
+       if (isodesc->frame)
+               uhci_unsched_isochronous(usb_dev, isodesc);
+
+       /* Remove it from the IRQ list */
+       uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]);
+
+       kfree(isodesc->td);
+       kfree(isodesc);
+}
+
 /*
  * Control thread operations: we just mark the last TD
  * in a control thread as an interrupt TD, and wake up
@@ -420,6 +619,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
        td->status = status;                            /* Try forever */
        td->info = destination | (7 << 21);             /* 8 bytes of data */
        td->buffer = virt_to_bus(cmd);
+       td->first = td;
 
        /*
         * If direction is "send", change the frame from SETUP (0x2D)
@@ -450,6 +650,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
                td->status = status;                                    /* Status */
                td->info = destination | ((pktsze-1) << 21);            /* pktsze bytes of data */
                td->buffer = virt_to_bus(data);
+               td->first = first;
                td->backptr = &prevtd->link;
 
                prevtd = td;
@@ -470,6 +671,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
        td->status = status | (1 << 24);                /* IOC */
        td->info = destination | (0x7ff << 21);         /* 0 bytes of data */
        td->buffer = 0;
+       td->first = first;
        td->backptr = &prevtd->link;
 
        /* Start it up.. */
@@ -554,12 +756,16 @@ static int uhci_usb_deallocate(struct usb_device *usb_dev)
        for (i = 0; i < UHCI_MAXTD; ++i) {
                struct uhci_td *td = dev->td + i;
 
-               /* And remove it from the irq list, if it's active */
-               if (td->status & (1 << 23))
-                       uhci_remove_irq_list(td);
-
-               if (td->inuse)
+               if (td->inuse) {
                        uhci_remove_td(td);
+
+                       /* And remove it from the irq list, if it's active */
+                       if (td->status & (1 << 23))
+                               td->status &= ~(1 << 23);
+#if 0
+                               uhci_remove_irq_list(td);
+#endif
+               }
        }
 
        /* Remove the td from any queues */
@@ -710,15 +916,18 @@ static void uhci_interrupt_notify(struct uhci *uhci)
                        __list_del(tmp->prev, next);
                        INIT_LIST_HEAD(tmp);
                        if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) {
-                               struct uhci_qh *interrupt_qh = td->qh;
-
                                list_add(&td->irq_list, &uhci->interrupt_list);
-                               td->info ^= 1 << 19; /* toggle between data0 and data1 */
-                               td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
 
-                               /* Remove then readd? Is that necessary */
-                               uhci_remove_td(td);
-                               uhci_insert_td_in_qh(interrupt_qh, td);
+                               if (!(td->status & (1 << 25))) {
+                                       struct uhci_qh *interrupt_qh = td->qh;
+
+                                       td->info ^= 1 << 19; /* toggle between data0 and data1 */
+                                       td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
+
+                                       /* Remove then readd? Is that necessary */
+                                       uhci_remove_td(td);
+                                       uhci_insert_td_in_qh(interrupt_qh, td);
+                               }
                        }
                        /* If completed wants to not reactivate, then it's */
                        /* responsible for free'ing the TD's and QH's */
@@ -764,6 +973,9 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
        status = inw(io_addr + USBSTS);
        outw(status, io_addr + USBSTS);
 
+       if ((status & ~0x21) != 0)
+               printk("interrupt: %X\n", status);
+
        /* Walk the list of pending TD's to see which ones completed.. */
        uhci_interrupt_notify(uhci);
 
@@ -787,6 +999,7 @@ static void uhci_init_ticktd(struct uhci *uhci)
        td->status = (1 << 24);                                 /* interrupt on completion */
        td->info = (15 << 21) | 0x7f69;                         /* (ignored) input packet, 16 bytes, device 127 */
        td->buffer = 0;
+       td->first = td;
        td->qh = NULL;
 
        uhci->fl->frame[0] = virt_to_bus(td);
@@ -1047,11 +1260,12 @@ static int uhci_control_thread(void * __uhci)
                }
        }
 
-#if 0
+       {
+       int i;
        if(uhci->root_hub)
                for(i = 0; i < uhci->root_hub->usb->maxchild; i++)
                        usb_disconnect(uhci->root_hub->usb->children + i);
-#endif
+       }
 
        cleanup_drivers();
 
@@ -1195,6 +1409,9 @@ int uhci_init(void)
 #ifdef CONFIG_USB_AUDIO                
                usb_audio_init();
 #endif         
+#ifdef CONFIG_USB_CPIA
+               cpia_init();
+#endif
 #ifdef CONFIG_APM
                apm_register_callback(&handle_apm_event);
 #endif
index f063356acc5807084cbb19f9cf7dcb900d54b8ae..3f511eedb5affb9f14c5adfda9c36eadc6a462b3 100644 (file)
@@ -91,8 +91,20 @@ struct uhci_td {
        void *dev_id;
        int inuse;                      /* Inuse? */
        struct uhci_qh *qh;
+       struct uhci_td *first;
 } __attribute__((aligned(32)));
 
+struct uhci_iso_td {
+       int num;
+       char *data;
+       int maxsze;
+
+       struct uhci_td *td;
+
+       int frame;
+       int endframe;
+};
+
 /*
  * Note the alignment requirements of the entries
  *
@@ -102,7 +114,7 @@ struct uhci_td {
  */
 struct uhci;
 
-#define UHCI_MAXTD 64
+#define UHCI_MAXTD     64
 
 #define UHCI_MAXQH     16
 
@@ -124,9 +136,11 @@ struct uhci_device {
  * The root hub pre-allocated QH's and TD's have
  * some special global uses..
  */
+#if 0
 #define control_td     td              /* Td's 0-30 */
 /* This is only for the root hub's TD list */
 #define tick_td                td[31]
+#endif
 
 /*
  * There are various standard queues. We set up several different
@@ -225,5 +239,11 @@ void show_td(struct uhci_td * td);
 void show_status(struct uhci *uhci);
 void show_queues(struct uhci *uhci);
 
+int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc);
+int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc);
+int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
+void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id);
+void uhci_delete_isochronous(struct usb_device *dev, void *_isodesc);
+
 #endif
 
index f5e89ea8986cc2ae16ef9209a698ba223a4ecb44..2040c69ba96ae92a7d991ebef14ec3abbf1edb38 100644 (file)
@@ -124,7 +124,7 @@ static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desc
                        
                if (n_len < 2 || n_len > len)
                {
-                       printk("Short descriptor.\n");
+                       printk("Short descriptor\n");
                        return -1;
                }
                printk(
@@ -152,9 +152,12 @@ static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desct
 {
        int n_len = ptr[0];
 
+       if (len <= 0)
+               return -1;
+
        if (n_len < 2 || n_len > len)
        {
-               printk("Short descriptor.\n");
+               printk("Short descriptor. (%d, %d)\n", len, n_len);
                return -1;
        }
 
@@ -247,6 +250,11 @@ static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor
        len -= *ptr;
        parsed += *ptr;
 
+       if (config->MaxPower == 200) {
+               printk("bNumInterfaces kludge\n");
+               config->bNumInterfaces += 3;
+       }
+
        if (config->bNumInterfaces > USB_MAXINTERFACES)
        {
                printk(KERN_WARNING "usb: too many interfaces.\n");
@@ -298,8 +306,10 @@ int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes)
                if (retval < 0)
                        return retval;
                ptr += retval;
-               bytes += retval;
+               bytes -= retval;
        }
+       if (bytes)
+               printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes);
        return 0;
 }
 
@@ -534,6 +544,23 @@ int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
        return 0;
 }
 
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+       devrequest dr;
+
+       dr.requesttype = 1;
+       dr.request = USB_REQ_SET_INTERFACE;
+       dr.value = alternate;
+       dr.index = interface;
+       dr.length = 0;
+
+       if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+               return -1;
+
+       return 0;
+}
+
+
 int usb_set_configuration(struct usb_device *dev, int configuration)
 {
        devrequest dr;
index 10379ef88da4d97ef56299e86ef834086f42dd51..903e4d852d10e110abe7b39b2260dd01117ebdb7 100644 (file)
@@ -326,6 +326,8 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
 /* Create control pipes.. */
 #define usb_sndctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint))
 #define usb_rcvctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_sndisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint) | 0x80)
 #define usb_snddefctrl(dev)            ((2 << 30) | __default_pipe(dev))
 #define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | 0x80)
 
index 7c2d2259f6c5190ed6c7fbc6dfcd40d99453265f..738bb40b896af02e0ecbbfda5fce7aad9930377e 100644 (file)
@@ -138,9 +138,6 @@ int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp)
        struct super_block *sb;
        int i, size;
 
-       if (!inode)
-               return 0;
-
        sb = inode->i_sb;
 
        size = 2048 >> sb->s_blocksize_bits;
index df3b5e457addeac687bf226fde8e8aa9a828b858..4e41c0975c17adce359464fe5c31e1c926a948a7 100644 (file)
@@ -46,9 +46,6 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
        unsigned long parent_object_id, dir_object_id;
        int buffers, pos;
 
-       if (!S_ISDIR(dir->i_mode))
-               return 0;
-
        sb = dir->i_sb;
 
        if (adfs_inode_validate (dir)) {
@@ -57,9 +54,6 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
                return 0;
        }
 
-       if (namelen > ADFS_NAME_LEN)
-               return 0;
-
        if (!(buffers = adfs_dir_read (dir, bh))) {
                adfs_error (sb, "adfs_find_entry", "unable to read directory");
                return 0;
index d6944e889d4ff919d98a55dbf9ce66c45ac4917d..425df657734236896ef6e41dd9cabc613c740cb5 100644 (file)
@@ -16,8 +16,6 @@ static int autofs_dir_readdir(struct file *filp,
                               void *dirent, filldir_t filldir)
 {
        struct inode *inode=filp->f_dentry->d_inode;
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -ENOTDIR;
 
        switch((unsigned long) filp->f_pos)
        {
index c0caee9df5653e406ef9f7a2ae53bbfc276d8158..c1b57ec6e96923fc2f844630855e52fb1429fa35 100644 (file)
@@ -72,9 +72,6 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
        struct inode * inode = filp->f_dentry->d_inode;
        off_t onr, nr;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -ENOTDIR;
-
        sbi = autofs_sbi(inode->i_sb);
        dirhash = &sbi->dirhash;
        nr = filp->f_pos;
index 2fe2f199b55d4df58500de4e86f486989bb52d0b..831bcdf206d3efbd9831614ebf3661c11954ef3c 100644 (file)
@@ -100,8 +100,7 @@ union bdflush_param{
                                each time we call refill */
                int nref_dirt; /* Dirty buffer threshold for activating bdflush
                                  when trying to refill buffers. */
-               int interval;  /* Interval (seconds) between spontaneous
-                                 bdflush runs */
+               int dummy1;    /* unused */
                int age_buffer;  /* Time for normal buffer to age before 
                                    we flush it */
                int age_super;  /* Time for superblock to age before we 
@@ -110,10 +109,10 @@ union bdflush_param{
                int dummy3;    /* unused */
        } b_un;
        unsigned int data[N_PARAM];
-} bdf_prm = {{40, 2000, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  1,   1*HZ,   1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
@@ -1556,14 +1555,15 @@ void __init buffer_init(unsigned long memory_size)
  * response to dirty buffers.  Once this process is activated, we write back
  * a limited number of buffers to the disks and then go back to sleep again.
  */
+static DECLARE_WAIT_QUEUE_HEAD(bdflush_wait);
 static DECLARE_WAIT_QUEUE_HEAD(bdflush_done);
 struct task_struct *bdflush_tsk = 0;
 
 void wakeup_bdflush(int wait)
 {
-       if (current == bdflush_tsk || !bdflush_tsk)
+       if (current == bdflush_tsk)
                return;
-       wake_up_process(bdflush_tsk);
+       wake_up(&bdflush_wait);
        if (wait) {
                run_task_queue(&tq_disk);
                sleep_on(&bdflush_done);
@@ -1572,107 +1572,82 @@ void wakeup_bdflush(int wait)
 
 
 /* 
- * Here we attempt to write back old buffers.
- * To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- *     out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- *     (otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- *     with running out of free buffers for loop's "real" device).
-*/
+ * Here we attempt to write back old buffers.  We also try to flush inodes 
+ * and supers as well, since this function is essentially "update", and 
+ * otherwise there would be no way of ensuring that these quantities ever 
+ * get written back.  Ideally, we would have a timestamp on the inodes
+ * and superblocks so that we could write back only the old ones as well
+ */
 
-static inline void sync_old_buffers(void)
+static int sync_old_buffers(void)
 {
        int i;
-       int ndirty = 0;
-       int wrta_cmd = WRITEA;
-#ifdef DEBUG
-       int ncount = 0, nwritten = 0;
-#endif
+       int ndirty, nwritten;
+       int nlist;
+       int ncount;
        struct buffer_head * bh, *next;
 
-#ifdef DEBUG
-       bh = lru_list[BUF_CLEAN];
-       if(bh)
-               for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
-                       next = bh->b_next_free;
+       sync_supers(0);
+       sync_inodes(0);
 
-                       /* Dirty/locked buffer on clean list?  Refile it */
-                       if (buffer_locked(bh) || buffer_dirty(bh)) {
-                               ncount++;
-                               refile_buffer(bh);
-                       }
-               }
+       ncount = 0;
+#ifdef DEBUG
+       for(nlist = 0; nlist < NR_LIST; nlist++)
+#else
+       for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
 #endif
+       {
+               ndirty = 0;
+               nwritten = 0;
+       repeat:
 
-       bh = lru_list[BUF_LOCKED];
-       if(bh)
-               for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
-                       next = bh->b_next_free;
-
-                       /* Unlocked buffer on locked list?  Refile it */
-                       if (!buffer_locked(bh))
-                               refile_buffer(bh);
-               }
-
- restart:
-       bh = lru_list[BUF_DIRTY];
-       if(bh) 
-               for (i = nr_buffers_type[BUF_DIRTY];
-                    i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
-                    bh = next) {
-                       /* We may have stalled while waiting for
-                          I/O to complete. */
-                       if(bh->b_list != BUF_DIRTY)
-                               goto restart;
-                       next = bh->b_next_free;
-                       if(!lru_list[BUF_DIRTY]) {
-                               printk("Dirty list empty %d\n", i);
-                               break;
-                       }
-                                         
-                       /* Clean buffer on dirty list?  Refile it */
-                       if (!buffer_dirty(bh)) {
-                               refile_buffer(bh);
-                               continue;
-                       }
-                                         
-                       if (buffer_locked(bh))
-                               continue;
-                       /* Should we write back buffers that are
-                          shared or not??  Currently dirty buffers
-                          are not shared, so it does not matter */
-                       next->b_count++;
-                       bh->b_count++;
-                       ndirty++;
-                       bh->b_flushtime = 0;
-                       if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
-                               ll_rw_block(wrta_cmd,1, &bh);
-                               wrta_cmd = WRITEA;
-                               if (buffer_dirty(bh))
-                                       --ndirty;
-                       }
-                       else
-                               ll_rw_block(WRITE, 1, &bh);
-                       bh->b_count--;
-                       next->b_count--;
-               }
-       /* If we didn't write anything, but there are still
-        * dirty buffers, then make the next write to a
-        * loop device to be a blocking write.
-        * This lets us block--which we _must_ do! */
-       if (ndirty == 0
-           && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
-               wrta_cmd = WRITE;
-               goto restart;
+               bh = lru_list[nlist];
+               if(bh) 
+                        for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
+                                /* We may have stalled while waiting for I/O to complete. */
+                                if(bh->b_list != nlist) goto repeat;
+                                next = bh->b_next_free;
+                                if(!lru_list[nlist]) {
+                                        printk("Dirty list empty %d\n", i);
+                                        break;
+                                }
+                                
+                                /* Clean buffer on dirty list?  Refile it */
+                                if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
+                                        refile_buffer(bh);
+                                        continue;
+                                }
+                                 
+                                 /* Unlocked buffer on locked list?  Refile it */
+                                 if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
+                                         refile_buffer(bh);
+                                         continue;
+                                 }
+                                
+                                if (buffer_locked(bh) || !buffer_dirty(bh))
+                                         continue;
+                                ndirty++;
+                                if(time_before(jiffies, bh->b_flushtime))
+                                       continue;
+                                nwritten++;
+                                next->b_count++;
+                                bh->b_count++;
+                                bh->b_flushtime = 0;
+#ifdef DEBUG
+                                if(nlist != BUF_DIRTY) ncount++;
+#endif
+                                ll_rw_block(WRITE, 1, &bh);
+                                bh->b_count--;
+                                next->b_count--;
+                        }
        }
-
+       run_task_queue(&tq_disk);
 #ifdef DEBUG
        if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-       printk("wrote %d/%d buffers...", nwritten, ndirty);
+       printk("Wrote %d/%d buffers\n", nwritten, ndirty);
 #endif
        run_task_queue(&tq_disk);
+       return 0;
 }
 
 
@@ -1689,12 +1664,10 @@ asmlinkage int sys_bdflush(int func, long data)
        if (!capable(CAP_SYS_ADMIN))
                goto out;
 
-       if (func == 1)
-               /* Func 1 used to call sync_old_buffers; a user space
-                  daemon would call it periodically.  This is no
-                  longer necessary.  Returning -EPERM here makes the
-                  daemon silently exit.  */
-               goto out;
+       if (func == 1) {
+                error = sync_old_buffers();
+                goto out;
+       }
 
        /* Basically func 1 means read param 1, 2 means write param 1, etc */
        if (func >= 2) {
@@ -1723,17 +1696,27 @@ out:
        return error;
 }
 
-/* This is the actual bdflush daemon itself. It used to be started
- * from the syscall above, but now we launch it ourselves internally
- * with kernel_thread(...)  directly after the first thread in
- * init/main.c.  Every so often, or when woken up by another task that
- * needs memory, we call sync_old_buffers to partially clear the dirty list.
- */
+/* This is the actual bdflush daemon itself. It used to be started from
+ * the syscall above, but now we launch it ourselves internally with
+ * kernel_thread(...)  directly after the first thread in init/main.c */
 
+/* To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *     out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *     (otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *     with running out of free buffers for loop's "real" device).
+*/
 int bdflush(void * unused) 
 {
-       long remaining = HZ * bdf_prm.b_un.interval;
-       struct task_struct *tsk = current;
+       int i;
+       int ndirty;
+       int nlist;
+       int ncount;
+       struct buffer_head * bh, *next;
+       int major;
+       int wrta_cmd = WRITEA;  /* non-blocking write for LOOP */
 
        /*
         *      We have a bare-bones task_struct, and really should fill
@@ -1741,12 +1724,10 @@ int bdflush(void * unused)
         *      display semi-sane things. Not real crucial though...  
         */
 
-       tsk->session = 1;
-       tsk->pgrp = 1;
-       tsk->dumpable = 0;  /* inhibit ptrace() */
-       strcpy(tsk->comm, "kflushd");
-       sigfillset(&tsk->blocked);
-       bdflush_tsk = tsk;
+       current->session = 1;
+       current->pgrp = 1;
+       sprintf(current->comm, "kflushd");
+       bdflush_tsk = current;
 
        /*
         *      As a kernel thread we want to tamper with system buffers
@@ -1756,36 +1737,93 @@ int bdflush(void * unused)
        lock_kernel();
                 
        for (;;) {
-               tsk->state = TASK_INTERRUPTIBLE;
-               remaining = schedule_timeout(remaining);
-
 #ifdef DEBUG
                printk("bdflush() activated...");
 #endif
-               CHECK_EMERGENCY_SYNC
 
-               if (remaining == 0) {
-                       /*
-                        * Also try to flush inodes and supers, since
-                        * otherwise there would be no way of ensuring
-                        * that these quantities ever get written
-                        * back.  Ideally, we would have a timestamp
-                        * on the inodes and superblocks so that we
-                        * could write back only the old ones.
-                        */
-                       sync_supers(0);
-                       sync_inodes(0);
-                       remaining = HZ * bdf_prm.b_un.interval;
-               }
-                       
-               /* Keep flushing till there aren't very many dirty buffers */
-               do {
-                       sync_old_buffers();
-               } while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+               CHECK_EMERGENCY_SYNC
 
-               wake_up(&bdflush_done);
+               ncount = 0;
 #ifdef DEBUG
+               for(nlist = 0; nlist < NR_LIST; nlist++)
+#else
+               for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
+#endif
+                {
+                        ndirty = 0;
+                repeat:
+
+                        bh = lru_list[nlist];
+                        if(bh) 
+                                 for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
+                                      bh = next) {
+                                         /* We may have stalled while waiting for I/O to complete. */
+                                         if(bh->b_list != nlist) goto repeat;
+                                         next = bh->b_next_free;
+                                         if(!lru_list[nlist]) {
+                                                 printk("Dirty list empty %d\n", i);
+                                                 break;
+                                         }
+                                         
+                                         /* Clean buffer on dirty list?  Refile it */
+                                         if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
+                                                 refile_buffer(bh);
+                                                 continue;
+                                         }
+                                         
+                                         /* Unlocked buffer on locked list?  Refile it */
+                                         if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
+                                                 refile_buffer(bh);
+                                                 continue;
+                                         }
+                                         
+                                         if (buffer_locked(bh) || !buffer_dirty(bh))
+                                                  continue;
+                                         major = MAJOR(bh->b_dev);
+                                         /* Should we write back buffers that are shared or not??
+                                            currently dirty buffers are not shared, so it does not matter */
+                                         next->b_count++;
+                                         bh->b_count++;
+                                         ndirty++;
+                                         bh->b_flushtime = 0;
+                                         if (major == LOOP_MAJOR) {
+                                                 ll_rw_block(wrta_cmd,1, &bh);
+                                                 wrta_cmd = WRITEA;
+                                                 if (buffer_dirty(bh))
+                                                         --ndirty;
+                                         }
+                                         else
+                                         ll_rw_block(WRITE, 1, &bh);
+#ifdef DEBUG
+                                         if(nlist != BUF_DIRTY) ncount++;
+#endif
+                                         bh->b_count--;
+                                         next->b_count--;
+                                 }
+                }
+#ifdef DEBUG
+               if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
                printk("sleeping again.\n");
 #endif
+               /* If we didn't write anything, but there are still
+                * dirty buffers, then make the next write to a
+                * loop device to be a blocking write.
+                * This lets us block--which we _must_ do! */
+               if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+                       wrta_cmd = WRITE;
+                       continue;
+               }
+               run_task_queue(&tq_disk);
+               wake_up(&bdflush_done);
+               
+               /* If there are still a lot of dirty buffers around, skip the sleep
+                  and flush some more */
+               if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
+                       spin_lock_irq(&current->sigmask_lock);
+                       flush_signals(current);
+                       spin_unlock_irq(&current->sigmask_lock);
+
+                       interruptible_sleep_on(&bdflush_wait);
+               }
        }
 }
index bad8d364abfcdff3b52777464d9dc07057f10098..dfef0a63ab415375c1bf371bb9042336c481d98c 100644 (file)
@@ -195,7 +195,7 @@ static inline void remove_inuse(struct dquot *dquot)
 
 static void __wait_on_dquot(struct dquot *dquot)
 {
-       struct wait_queue wait = { current, NULL };
+       DECLARE_WAITQUEUE(wait, current);
 
        add_wait_queue(&dquot->dq_wait, &wait);
 repeat:
@@ -429,6 +429,7 @@ static void grow_dquots(void)
 
                nr_dquots++;
                memset((caddr_t)dquot, 0, sizeof(struct dquot));
+               init_waitqueue_head(&dquot->dq_wait);
                /* all dquots go on the inuse_list */
                put_inuse(dquot);
                put_dquot_head(dquot);
index 6bfa7041d5f13771e30220d83fe78358d4befdea..822207251e2682ed3412dd050de03bbdb2ea26e3 100644 (file)
@@ -841,7 +841,8 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
                if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX)
+               if (!new_inode && new_dir!=old_dir &&
+                               new_dir->i_nlink >= EXT2_LINK_MAX)
                        goto end_rename;
        }
        if (!new_bh) {
index 7460cca626657a8ade19e52053ff02ed65c6153c..189b0107e1544688270f71fa37c9b4b1bbad4d2a 100644 (file)
@@ -237,10 +237,6 @@ static int cap_readdir(struct file * filp,
         struct hfs_cat_entry *entry;
        struct inode *dir = filp->f_dentry->d_inode;
 
-       if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-               return -EBADF;
-       }
-
        entry = HFS_I(dir)->entry;
        type = HFS_ITYPE(dir->i_ino);
        skip_dirs = (type == HFS_CAP_RDIR);
index e5ad805116741abc7119129269cc2906ef3ea01d..17e53798a763aed61edc877b039a4b8aa61c1c8b 100644 (file)
@@ -201,10 +201,6 @@ static int dbl_readdir(struct file * filp,
         struct hfs_cat_entry *entry;
        struct inode *dir = filp->f_dentry->d_inode;
 
-       if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-               return -EBADF;
-       }
-
        entry = HFS_I(dir)->entry;
 
        if (filp->f_pos == 0) {
index f9f131a17f2ffda99687458a32d712c757877439..be6974b6663f27e17b7e1997fb8a666e40e67c1e 100644 (file)
@@ -225,10 +225,6 @@ static int nat_readdir(struct file * filp,
         struct hfs_cat_entry *entry;
        struct inode *dir = filp->f_dentry->d_inode;
 
-       if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
-               return -EBADF;
-       }
-
        entry = HFS_I(dir)->entry;
        type = HFS_ITYPE(dir->i_ino);
        skip_dirs = (type == HFS_NAT_HDIR);
index 6c1f1558cefc44ffbe922b632f238f40a3f74cdd..878797b8adaa9952860c3670d28b8374f486efd0 100644 (file)
@@ -322,7 +322,6 @@ init_module(void)
        init_MUTEX(&nlmsvc_sema);
        nlmsvc_users = 0;
        nlmsvc_pid = 0;
-       init_waitqueue_head(&lockd_exit);
        nlmxdr_init();
        return 0;
 }
index c2366ae4b200f04cd21a5d0243a04f00db03a6c2..0af91237a69dea2404ef94d5fc78272b091fae4a 100644 (file)
@@ -45,8 +45,6 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
        struct minix_dir_entry *de;
 
        *res_dir = NULL;
-       if (!dir->i_sb)
-               return NULL;
        info = &dir->i_sb->u.minix_sb;
        if (namelen > info->s_namelen) {
 #ifdef NO_TRUNCATE
@@ -161,8 +159,6 @@ static int minix_add_entry(struct inode * dir,
 
        *res_buf = NULL;
        *res_dir = NULL;
-       if (!dir || !dir->i_sb)
-               return -ENOENT;
        info = &dir->i_sb->u.minix_sb;
        if (namelen > info->s_namelen) {
 #ifdef NO_TRUNCATE
@@ -331,8 +327,6 @@ static int empty_dir(struct inode * inode)
        struct minix_dir_entry * de;
        struct minix_sb_info * info;
 
-       if (!inode || !inode->i_sb)
-               return 1;
        info = &inode->i_sb->u.minix_sb;
        block = 0;
        bh = NULL;
@@ -431,26 +425,12 @@ int minix_unlink(struct inode * dir, struct dentry *dentry)
        struct buffer_head * bh;
        struct minix_dir_entry * de;
 
-repeat:
        retval = -ENOENT;
-       inode = NULL;
+       inode = dentry->d_inode;
        bh = minix_find_entry(dir, dentry->d_name.name,
                              dentry->d_name.len, &de);
-       if (!bh)
+       if (!bh || de->inode != inode->i_ino)
                goto end_unlink;
-       inode = dentry->d_inode;
-
-       retval = -EPERM;
-       if (de->inode != inode->i_ino) {
-               brelse(bh);
-               current->counter = 0;
-               schedule();
-               goto repeat;
-       }
-       if (de->inode != inode->i_ino) {
-               retval = -ENOENT;
-               goto end_unlink;
-       }
        if (!inode->i_nlink) {
                printk("Deleting nonexistent file (%s:%lu), %d\n",
                        kdevname(inode->i_dev),
@@ -551,12 +531,6 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
 (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
 
 /*
- * rename uses retrying to avoid race-conditions: at least they should be minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
@@ -570,24 +544,15 @@ int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
        int retval;
 
        info = &old_dir->i_sb->u.minix_sb;
-       goto start_up;
-try_again:
-       brelse(old_bh);
-       brelse(new_bh);
-       brelse(dir_bh);
-       current->counter = 0;
-       schedule();
-start_up:
-       old_inode = new_inode = NULL;
-       old_bh = new_bh = dir_bh = NULL;
+       new_bh = dir_bh = NULL;
+       old_inode = old_dentry->d_inode;
+       new_inode = new_dentry->d_inode;
        old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
                                  old_dentry->d_name.len, &old_de);
        retval = -ENOENT;
-       if (!old_bh)
+       if (!old_bh || old_de->inode != old_inode->i_ino)
                goto end_rename;
-       old_inode = old_dentry->d_inode;
        retval = -EPERM;
-       new_inode = new_dentry->d_inode;
        new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
                                  new_dentry->d_name.len, &new_de);
        if (new_bh) {
@@ -609,7 +574,8 @@ start_up:
                if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= info->s_link_max)
+               if (!new_inode && new_dir != old_dir &&
+                               new_dir->i_nlink >= info->s_link_max)
                        goto end_rename;
        }
        if (!new_bh) {
@@ -620,22 +586,15 @@ start_up:
                if (retval)
                        goto end_rename;
        }
-/* sanity checking before doing the rename - avoid races */
-       if (new_inode && (new_de->inode != new_inode->i_ino))
-               goto try_again;
-       if (new_de->inode && !new_inode)
-               goto try_again;
-       if (old_de->inode != old_inode->i_ino)
-               goto try_again;
 /* ok, that's it */
-       old_de->inode = 0;
        new_de->inode = old_inode->i_ino;
+       old_de->inode = 0;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-       mark_inode_dirty(old_dir);
        old_dir->i_version = ++event;
+       mark_inode_dirty(old_dir);
        new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-       mark_inode_dirty(new_dir);
        new_dir->i_version = ++event;
+       mark_inode_dirty(new_dir);
        if (new_inode) {
                new_inode->i_nlink--;
                new_inode->i_ctime = CURRENT_TIME;
index 8fc3a0994039d8932c6b85413d036f0541d21802..3ed52b390c18640ebdc23c6e71ef4fad9328a027 100644 (file)
@@ -354,16 +354,7 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
        int len = dentry->d_name.len;      
        struct ncpfs_inode_info finfo;
        __u8 __name[dentry->d_name.len + 1];
-
-        if (!dentry->d_inode) {
-                DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n");
-                return 0;
-        }
         
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n");
-               goto finished;
-       }
        server = NCP_SERVER(dir);
 
        if (!ncp_conn_valid(server))
index 35f5fd2eff73d739bdc3f8d06073234be21f25f7..b7766ba0af95dac131cfe764c02d24ab34045e12 100644 (file)
@@ -36,6 +36,7 @@ static void smb_put_inode(struct inode *);
 static void smb_delete_inode(struct inode *);
 static void smb_put_super(struct super_block *);
 static int  smb_statfs(struct super_block *, struct statfs *, int);
+static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
 
 static struct super_operations smb_sops =
 {
@@ -67,9 +68,7 @@ smb_invent_inos(unsigned long n)
        return ino;
 }
 
-static struct smb_fattr *read_fattr = NULL;
-static DECLARE_MUTEX(read_semaphore);
-
+/* We are always generating a new inode here */
 struct inode *
 smb_iget(struct super_block *sb, struct smb_fattr *fattr)
 {
@@ -77,11 +76,19 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
 
        pr_debug("smb_iget: %p\n", fattr);
 
-       down(&read_semaphore);
-       read_fattr = fattr;
-       result = iget(sb, fattr->f_ino);
-       read_fattr = NULL;
-       up(&read_semaphore);
+       result = get_empty_inode();
+       result->i_sb = sb;
+       result->i_dev = sb->s_dev;
+       result->i_ino = fattr->f_ino;
+       memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
+       smb_set_inode_attr(result, fattr);
+       if (S_ISREG(result->i_mode))
+               result->i_op = &smb_file_inode_operations;
+       else if (S_ISDIR(result->i_mode))
+               result->i_op = &smb_dir_inode_operations;
+       else
+               result->i_op = NULL;
+       insert_inode_hash(result)
        return result;
 }
 
@@ -147,24 +154,9 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
 static void
 smb_read_inode(struct inode *inode)
 {
-       pr_debug("smb_iget: %p\n", read_fattr);
-
-       if (!read_fattr || inode->i_ino != read_fattr->f_ino)
-       {
-               printk("smb_read_inode called from invalid point\n");
-               return;
-       }
-
-       inode->i_dev = inode->i_sb->s_dev;
-       memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
-       smb_set_inode_attr(inode, read_fattr);
-
-       if (S_ISREG(inode->i_mode))
-               inode->i_op = &smb_file_inode_operations;
-       else if (S_ISDIR(inode->i_mode))
-               inode->i_op = &smb_dir_inode_operations;
-       else
-               inode->i_op = NULL;
+       /* Now it can be called only by NFS */
+       printk("smb_read_inode called from invalid point\n");
+       return;
 }
 
 /*
@@ -609,8 +601,6 @@ init_module(void)
        smb_current_vmalloced = 0;
 #endif
 
-       init_MUTEX(&read_semaphore);
-
        return init_smb_fs();
 }
 
index f15445e4b7ca047297afd4a9066aa8b4d9d09bbd..e9454389743b4e70eaed16632d6024a2ffcea355 100644 (file)
@@ -953,16 +953,19 @@ static int do_remount(const char *dir,int flags,char *data)
        if (!IS_ERR(dentry)) {
                struct super_block * sb = dentry->d_inode->i_sb;
 
-               retval = -EINVAL;
-               if (dentry == sb->s_root) {
-                       /*
-                        * Shrink the dcache and sync the device.
-                        */
-                       shrink_dcache_sb(sb);
-                       fsync_dev(sb->s_dev);
-                       if (flags & MS_RDONLY)
-                               acct_auto_close(sb->s_dev);
-                       retval = do_remount_sb(sb, flags, data);
+               retval = -ENODEV;
+               if (sb) {
+                       retval = -EINVAL;
+                       if (dentry == sb->s_root) {
+                               /*
+                                * Shrink the dcache and sync the device.
+                                */
+                               shrink_dcache_sb(sb);
+                               fsync_dev(sb->s_dev);
+                               if (flags & MS_RDONLY)
+                                       acct_auto_close(sb->s_dev);
+                               retval = do_remount_sb(sb, flags, data);
+                       }
                }
                dput(dentry);
        }
index 18f98d3536973ad625e8ff48030553d4285522af..90804fe7c08fead6d64a65370acb7a9a22ce3f83 100644 (file)
@@ -892,7 +892,6 @@ void sysv_read_inode(struct inode * inode)
                for (block = 0; block < 10+1+1+1; block++)
                        inode->u.sysv_i.i_data[block] =
                                read3byte(&raw_inode->i_a.i_addb[3*block]);
-       brelse(bh);
        if (S_ISREG(inode->i_mode))
                inode->i_op = &sysv_file_inode_operations;
        else if (S_ISDIR(inode->i_mode))
@@ -901,6 +900,7 @@ void sysv_read_inode(struct inode * inode)
                inode->i_op = &sysv_symlink_inode_operations;
        else
                init_special_inode(inode, inode->i_mode,raw_inode->i_a.i_rdev);
+       brelse(bh);
 }
 
 /* To avoid inconsistencies between inodes in memory and inodes on disk. */
index 455d34b7acdb2389188f03b22e152ae8dfa817a0..d025cbc850316ecb5f8402d5ca92053a920e060b 100644 (file)
@@ -144,8 +144,6 @@ static int sysv_add_entry(struct inode * dir,
 
        *res_buf = NULL;
        *res_dir = NULL;
-       if (!dir)
-               return -ENOENT;
        sb = dir->i_sb;
        if (namelen > SYSV_NAMELEN) {
                if (sb->sv_truncate)
@@ -323,8 +321,6 @@ static int empty_dir(struct inode * inode)
        struct buffer_head * bh;
        struct sysv_dir_entry * de;
 
-       if (!inode)
-               return 1;
        block = 0;
        bh = NULL;
        pos = offset = 2*SYSV_DIRSIZE;
@@ -380,22 +376,16 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry)
        struct buffer_head * bh;
        struct sysv_dir_entry * de;
 
-       inode = NULL;
-       bh = sysv_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
+       inode = dentry->d_inode;
+       bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
        retval = -ENOENT;
-       if (!bh)
+       if (!bh || de->inode != inode->i_ino)
                goto end_rmdir;
-       inode = dentry->d_inode;
 
        if (!empty_dir(inode)) {
                retval = -ENOTEMPTY;
                goto end_rmdir;
        }
-       if (de->inode != inode->i_ino) {
-               retval = -ENOENT;
-               goto end_rmdir;
-       }
        if (!list_empty(&dentry->d_hash)) {
                retval = -EBUSY;
                goto end_rmdir;
@@ -405,9 +395,9 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry)
        de->inode = 0;
        mark_buffer_dirty(bh, 1);
        inode->i_nlink=0;
-       mark_inode_dirty(inode);
        dir->i_nlink--;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       mark_inode_dirty(inode);
        mark_inode_dirty(dir);
        d_delete(dentry);
        retval = 0;
@@ -423,26 +413,11 @@ int sysv_unlink(struct inode * dir, struct dentry * dentry)
        struct buffer_head * bh;
        struct sysv_dir_entry * de;
 
-repeat:
        retval = -ENOENT;
-       inode = NULL;
-       bh = sysv_find_entry(dir, dentry->d_name.name,
-                             dentry->d_name.len, &de);
-       if (!bh)
-               goto end_unlink;
        inode = dentry->d_inode;
-
-       retval = -EPERM;
-       if (de->inode != inode->i_ino) {
-               brelse(bh);
-               current->counter = 0;
-               schedule();
-               goto repeat;
-       }
-       if (de->inode != inode->i_ino) {
-               retval = -ENOENT;
+       bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+       if (!bh || de->inode != inode->i_ino)
                goto end_unlink;
-       }
        if (!inode->i_nlink) {
                printk("Deleting nonexistent file (%s:%lu), %d\n",
                        kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
@@ -561,12 +536,6 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir,
 (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
 
 /*
- * rename uses retrying to avoid race-conditions: at least they should be minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
@@ -578,24 +547,15 @@ int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
        struct sysv_dir_entry * old_de, * new_de;
        int retval;
 
-       goto start_up;
-try_again:
-       brelse(old_bh);
-       brelse(new_bh);
-       brelse(dir_bh);
-       current->counter = 0;
-       schedule();
-start_up:
-       old_inode = new_inode = NULL;
-       old_bh = new_bh = dir_bh = NULL;
+       old_inode = old_dentry->d_inode;
+       new_inode = new_dentry->d_inode;
+       new_bh = dir_bh = NULL;
        old_bh = sysv_find_entry(old_dir, old_dentry->d_name.name,
                                old_dentry->d_name.len, &old_de);
        retval = -ENOENT;
-       if (!old_bh)
+       if (!old_bh || old_de->inode != old_inode->i_ino)
                goto end_rename;
-       old_inode = old_dentry->d_inode;        /* don't cross mnt-points */
        retval = -EPERM;
-       new_inode = new_dentry->d_inode;
        new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
                                new_dentry->d_name.len, &new_de);
        if (new_bh) {
@@ -617,7 +577,8 @@ start_up:
                if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
                        goto end_rename;
                retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
+               if (!new_inode && new_dir != old_dir &&
+                               new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
                        goto end_rename;
        }
        if (!new_bh) {
@@ -626,16 +587,8 @@ start_up:
                if (retval)
                        goto end_rename;
        }
-/* sanity checking before doing the rename - avoid races */
-       if (new_inode && (new_de->inode != new_inode->i_ino))
-               goto try_again;
-       if (new_de->inode && !new_inode)
-               goto try_again;
-       if (old_de->inode != old_inode->i_ino)
-               goto try_again;
-/* ok, that's it */
-       old_de->inode = 0;
        new_de->inode = old_inode->i_ino;
+       old_de->inode = 0;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
        new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
diff --git a/include/asm-alpha/hdreg.h b/include/asm-alpha/hdreg.h
new file mode 100644 (file)
index 0000000..2d94547
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ *  linux/include/asm-alpha/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef __ASMalpha_HDREG_H
+#define __ASMalpha_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASMalpha_HDREG_H */
index e8de11f1273115f844a1290dee0ac62d9bd9ee2c..2ef5de9356594ddde289faa3e94720a67c2cbe38 100644 (file)
@@ -13,8 +13,6 @@
 
 #ifdef __KERNEL__
 
-typedef unsigned short ide_ioreg_t;
-
 #ifndef MAX_HWIFS
 #define MAX_HWIFS      4
 #endif
@@ -45,18 +43,42 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
        }
 }
 
-static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-       ide_ioreg_t port = base;
-       int i = 8;
+       ide_ioreg_t reg = data_port;
+       int i;
 
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+       }
        if (irq != NULL)
                *irq = 0;
 }
 
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifdef __DO_I_NEED_THIS
+       hw_regs_t hw;
+       int index;
+
+       for (index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* __DO_I_NEED_THIS */
+}
+
 typedef union {
        unsigned all                    : 8;    /* all of the bits together */
        struct {
@@ -68,51 +90,19 @@ typedef union {
        } b;
        } select_t;
 
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                       unsigned long flags, const char *device, void *dev_id)
-{
-       return request_irq(irq, handler, flags, device, dev_id);
-}                      
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-       free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-       return check_region(from, extent);
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-       request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-       release_region(from, extent);
-}
+#define ide_request_irq(irq,hand,flg,dev,id)   request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)               free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)          check_region((from), (extent))
+#define ide_request_region(from,extent,name)   request_region((from), (extent), (name))
+#define ide_release_region(from,extent)                release_region((from), (extent))
 
 /*
  * The following are not needed for the non-m68k ports
  */
-static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
-{
-       return(1);
-}
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-}
-
-static __inline__ void ide_release_lock (int *ide_lock)
-{
-}
-
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
-{
-}
+#define ide_ack_intr(hwif)             (1)
+#define ide_fix_driveid(id)            do {} while (0)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
 
 #endif /* __KERNEL__ */
 
index dc976cb5fca71750b6053e894806da37d9356fbe..f908f74640adf7d9b30296fcd98a45955af34632 100644 (file)
@@ -356,6 +356,12 @@ out:
 #endif
 #define RTC_ALWAYS_BCD 0
 
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ALPHA_IO_H */
index 2fc6ce282855ac2a5f7046211ae62c809da37e3d..031225380f39f77f9112d18a146fc2f1ba29acb2 100644 (file)
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
 
-       memset(hw, 0, sizeof(*hw));
-
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
                hw->io_ports[i] = reg;
                reg += 1;
        }
        hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-       hw->irq = irq;
+       hw->irq = *irq;
 }
 
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
  */
-static __inline__ void
-ide_init_default_hwifs(void)
+static __inline__ void ide_init_default_hwifs(void)
 {
 #ifdef CONFIG_ARCH_A5K
        hw_regs_t hw;
 
-       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+        memset(hw, 0, sizeof(*hw));
+
+       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+       hw.irq = IRQ_HARDDISK;
        ide_register_hw(&hw, NULL);
 #endif
 }
index b0071a45b2b0ed737796e93c9427255d591b0f00..d86a6f98a93d04c6c33f0beeb42f838401950999 100644 (file)
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
 
-       memset(hw, 0, sizeof(*hw));
-
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
                hw->io_ports[i] = reg;
                reg += 1;
        }
        hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-       hw->irq = irq;
+       hw->irq = *irq;
 }
 
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
  */
-static __inline__ void
-ide_init_default_hwifs(void)
+static __inline__ void ide_init_default_hwifs(void)
 {
+#if 0
+       hw_regs_t hw;
+
+       memset(hw, 0, sizeof(*hw));
+
+       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+       hw.irq = IRQ_HARDDISK;
+       ide_register_hw(&hw, NULL);
+#endif
 }
index ccbc7cf76aa6f3f9895536595c328aad4f050634..9826f15f59341a5d451faac93bf550deedb284ca 100644 (file)
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
 {
        ide_ioreg_t reg = (ide_ioreg_t) data_port;
        int i;
 
-       memset(hw, 0, sizeof(*hw));
-
        for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
                hw->io_ports[i] = reg;
                reg += 1;
        }
        hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-       hw->irq = irq;
+       hw->irq = *irq;
 }
 
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
  */
-static __inline__ void
-ide_init_default_hwifs(void)
+static __inline__ void ide_init_default_hwifs(void)
 {
        hw_regs_t hw;
 
-       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+        memset(hw, 0, sizeof(*hw));
+
+       ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+       hw.irq = IRQ_HARDDISK;
        ide_register_hw(&hw, NULL);
 }
diff --git a/include/asm-arm/hdreg.h b/include/asm-arm/hdreg.h
new file mode 100644 (file)
index 0000000..81bc05e
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *  linux/include/asm-arm/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef __ASMARM_HDREG_H
+#define __ASMARM_HDREG_H
+
+typedef unsigned long ide_ioreg_t;
+
+#endif /* __ASMARM_HDREG_H */
+
index 76da8806b6a46386fe0b8ab8d9977c4bd072e644..6bd9d3c02045b2d004409dd71054bcd5f2b9f088 100644 (file)
@@ -48,4 +48,4 @@ typedef union {
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMi386_IDE_H */
+#endif /* __ASMARM_IDE_H */
index 35db8e667f056eb5247f096b20d32f97e783cc2d..cfa021bcdf682ca9421c74591307006f15d539a5 100644 (file)
@@ -189,10 +189,21 @@ __IO(l,"",long)
 #define inl_p(port) __inl_p((port))
 #endif
 
-#endif
+/* Nothing to do */
 
+#ifndef dma_cache_inv
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#endif
+#ifndef dma_cache_wback
+#define dma_cache_wback(_start,_size)          do { } while (0)
 #ifndef ARCH_READWRITE
+#ifndef dma_cache_wback_inv
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+#endif
+
+#endif /* __KERNEL__ */
 
+#endif /* __ASM_ARM_IO_H */
 /* for panic */
 #include <linux/kernel.h>
 
diff --git a/include/asm-i386/hdreg.h b/include/asm-i386/hdreg.h
new file mode 100644 (file)
index 0000000..1ad5c07
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ *  linux/include/asm-i386/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef __ASMi386_HDREG_H
+#define __ASMi386_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASMi386_HDREG_H */
index a6d1fc868e9f32af934e4714cba845cc2bab96ae..6876f9f60ef8e3e0cf3c84762c39b69a14a95c0e 100644 (file)
 
 #ifdef __KERNEL__
 
-typedef unsigned short ide_ioreg_t;
-
 #ifndef MAX_HWIFS
-#define MAX_HWIFS      6
+#define MAX_HWIFS      8
 #endif
 
 #define ide__sti()     __sti()
@@ -49,18 +47,38 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
        }
 }
 
-static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-       ide_ioreg_t port = base;
-       int i = 8;
+       ide_ioreg_t reg = data_port;
+       int i;
 
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+       }
        if (irq != NULL)
                *irq = 0;
 }
 
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifdef __DO_I_NEED_THIS
+       hw_regs_t hw;
+       int index;
+
+       for(index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* __DO_I_NEED_THIS */
+}
+
 typedef union {
        unsigned all                    : 8;    /* all of the bits together */
        struct {
@@ -72,51 +90,19 @@ typedef union {
        } b;
        } select_t;
 
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                       unsigned long flags, const char *device, void *dev_id)
-{
-       return request_irq(irq, handler, flags, device, dev_id);
-}                      
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-       free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-       return check_region(from, extent);
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-       request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-       release_region(from, extent);
-}
+#define ide_request_irq(irq,hand,flg,dev,id)   request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)               free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)          check_region((from), (extent))
+#define ide_request_region(from,extent,name)   request_region((from), (extent), (name))
+#define ide_release_region(from,extent)                release_region((from), (extent))
 
 /*
  * The following are not needed for the non-m68k ports
  */
-static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
-{
-       return(1);
-}
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-}
-
-static __inline__ void ide_release_lock (int *ide_lock)
-{
-}
-
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
-{
-}
+#define ide_ack_intr(hwif)             (1)
+#define ide_fix_driveid(id)            do {} while (0)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
 
 #endif /* __KERNEL__ */
 
index 155ff14193c393d448e58e2ae0ec50e458bb0304..93fd0c1b52d39eb77c7d7cd118108dc041fab010 100644 (file)
@@ -183,6 +183,12 @@ out:
        return retval;
 }
 
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* __KERNEL__ */
 
 #endif
index c5b82c84bec45a310ebf7fba233b5f91ffe3ba23..870fad7b2815e431f64fdeed4c9fb3c658262e9a 100644 (file)
@@ -34,7 +34,7 @@ struct semaphore {
        int waking;
        wait_queue_head_t wait;
 #if WAITQUEUE_DEBUG
-       int __magic;
+       long __magic;
 #endif
 };
 
diff --git a/include/asm-m68k/hdreg.h b/include/asm-m68k/hdreg.h
new file mode 100644 (file)
index 0000000..16249bd
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *  linux/include/asm-m68k/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef _M68K_HDREG_H
+#define _M68K_HDREG_H
+
+typedef unsigned int   q40ide_ioreg_t;
+typedef unsigned char * ide_ioreg_t;
+
+#endif /* _M68K_HDREG_H */
index da5753ee77f535e6f73db1b76182128def2ae9d8..e4a83371d5e9e41406700b5a9bafdb93bc4c2a76 100644 (file)
 #include <asm/macints.h>
 #endif
 
-
-typedef unsigned int   q40ide_ioreg_t;
-
-
-typedef unsigned char * ide_ioreg_t;
-
-
 #ifndef MAX_HWIFS
 #define MAX_HWIFS      4       /* same as the other archs */
 #endif
@@ -65,19 +58,39 @@ static __inline__ int ide_default_irq(ide_ioreg_t base)
        else return 0;
 }
 
+int q40ide_default_io_base(int);
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+       if (MACH_IS_Q40)
+               return q40ide_default_io_base(index);
+       else return 0;
+}
 
 /*
  *  Can we do this in a generic manner??
  */
-void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq);
+void q40_ide_init_hwif_ports (hw_regs_t *hw, q40ide_ioreg_t data_port, q40ide_ioreg_t ctrl_port, int *irq);
 
-static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+/*
+ * Set up a hw structure for a specified data port, control port and IRQ.
+ * This should follow whatever the default interface uses.
+ */
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 #ifdef CONFIG_Q40
-    if (MACH_IS_Q40)
-      return q40_ide_init_hwif_ports((q40ide_ioreg_t *)p,(q40ide_ioreg_t)base,irq);
+       if (MACH_IS_Q40)
+               return q40_ide_init_hwif_ports(hw, (q40ide_ioreg_t) data_port, (q40ide_ioreg_t) ctrl_port, irq);
 #endif
-    printk("ide_init_hwif_ports: must not be called\n");
+       printk("ide_init_hwif_ports: must not be called\n");
+}
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void ide_init_default_hwifs(void)
+{
 }
 
 typedef union {
@@ -487,7 +500,7 @@ static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *,
 #endif /* CONFIG_ATARI */
 }
 
-#define ide_ack_intr(hwif)     ((hwif)->ack_intr ? (hwif)->ack_intr(hwif) : 1)
+#define ide_ack_intr(hwif)     ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
 
 /*
  * On the Atari, we sometimes can't enable interrupts:
index 168077b26e89e7753b660e27d6f237462603e83f..7843b8f092ed664fb95a946cd5f1f9337fb9d81c 100644 (file)
@@ -72,6 +72,12 @@ extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
 
 extern void iounmap(void *addr);
 
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_IO_H */
diff --git a/include/asm-mips/hdreg.h b/include/asm-mips/hdreg.h
new file mode 100644 (file)
index 0000000..189dfc5
--- /dev/null
@@ -0,0 +1,18 @@
+/* $Id: hdreg.h,v 1.4 1998/05/08 21:05:26 davem Exp $
+ *
+ *  linux/include/asm-mips/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the MIPS architecture specific IDE code.
+ */
+
+#ifndef __ASM_MIPS_HDREG_H
+#define __ASM_MIPS_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASM_MIPS_HDREG_H */
+
index f9aa1e57dd642b40170bd2c1928caa3c4bae5c46..81fda3fbbc902cdc242af1da062700eaa4ceb2d0 100644 (file)
@@ -14,8 +14,6 @@
 
 #ifdef __KERNEL__
 
-typedef unsigned short ide_ioreg_t;
-
 #ifndef MAX_HWIFS
 #define MAX_HWIFS      6
 #endif
@@ -25,7 +23,7 @@ typedef unsigned short ide_ioreg_t;
 struct ide_ops {
        int (*ide_default_irq)(ide_ioreg_t base);
        ide_ioreg_t (*ide_default_io_base)(int index);
-       void (*ide_init_hwif_ports)(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+       void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
        int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
                               struct pt_regs *), unsigned long flags,
                               const char *device, void *dev_id);
@@ -48,10 +46,29 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
        return ide_ops->ide_default_io_base(index);
 }
 
-static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base,
-                                           int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
-       ide_ops->ide_init_hwif_ports(p, base, irq);
+       ide_ops->ide_init_hwif_ports(hw->io_ports, data_port, ctrl_port, &hw->irq);
+
+       hw->irq = ide_ops->ide_default_irq(data_port);
+}
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifdef __DO_I_NEED_THIS
+       hw_regs_t hw;
+       int index;
+
+       for (index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* __DO_I_NEED_THIS */
 }
 
 typedef union {
@@ -96,26 +113,10 @@ static __inline__ void ide_release_region(ide_ioreg_t from,
 /*
  * The following are not needed for the non-m68k ports
  */
-static __inline__ int ide_ack_intr (ide_ioreg_t status_port,
-                                    ide_ioreg_t irq_port)
-{
-       return 1;
-}
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-}
-
-static __inline__ void ide_release_lock (int *ide_lock)
-{
-}
-
-static __inline__ void ide_get_lock (int *ide_lock,
-                                     void (*handler)(int, void *,
-                                                    struct pt_regs *),
-                                     void *data)
-{
-}
+#define ide_ack_intr(hwif)             (1)
+#define ide_fix_driveid(id)            do {} while (0)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
 
 #endif /* __KERNEL__ */
 
index 2319c27c99638011dfb58c70d9125c30f59c2237..d167d7ccdc518359086b0d2040630993fe6cd6d8 100644 (file)
@@ -389,4 +389,8 @@ __OUTS(w,l,4)
 extern void (*dma_cache_wback_inv)(unsigned long start, unsigned long size);
 extern void (*dma_cache_inv)(unsigned long start, unsigned long size);
 
+/* Nothing to do */
+
+#define dma_cache_wback(_start,_size)          do { } while (0)
+
 #endif /* __ASM_MIPS_IO_H */
diff --git a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h
new file mode 100644 (file)
index 0000000..5812353
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ *  linux/include/asm-ppc/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the ppc architecture specific IDE code.
+ */
+
+#ifndef __ASMPPC_HDREG_H
+#define __ASMPPC_HDREG_H
+
+typedef unsigned int ide_ioreg_t;
+
+#endif /* __ASMPPC_HDREG_H */
+
index c53267b77e0aa648644976964d55f73e61fdd048..30a53876ee8427ea8050876fafbe2033f679efa2 100644 (file)
@@ -18,7 +18,7 @@
 #define MAX_HWIFS      4
 #endif
 
-typedef unsigned int ide_ioreg_t;
+#include <asm/hdreg.h>
 
 #ifdef __KERNEL__
 
@@ -49,16 +49,17 @@ struct ide_machdep_calls {
         void        (*release_region)(ide_ioreg_t from,
                                       unsigned int extent);
         void        (*fix_driveid)(struct hd_driveid *id);
-        void        (*ide_init_hwif)(ide_ioreg_t *p,
-                                     ide_ioreg_t base,
-                                     int *irq); 
+        void        (*ide_init_hwif)(hw_regs_t *hw,
+                                     ide_ioreg_t data_port,
+                                     ide_ioreg_t ctrl_port,
+                                     int *irq);
 
         int io_base;
 };
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
 void ide_insw(ide_ioreg_t port, void *buf, int ns);
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
@@ -90,6 +91,20 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
        return ppc_ide_md.default_io_base(index);
 }
 
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifdef __DO_I_NEED_THIS
+       hw_regs_t hw;
+       int index;
+
+       for(index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* __DO_I_NEED_THIS */
+}
+
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
        return ppc_ide_md.check_region(from, extent);
@@ -131,21 +146,13 @@ typedef union {
        } b;
 } select_t;
 
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                       unsigned long flags, const char *device, void *dev_id)
-{
-       return request_irq(irq, handler, flags, device, dev_id);
-}                      
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-       free_irq(irq, dev_id);
-}
+#define ide_request_irq(irq,hand,flg,dev,id)   request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)               free_irq((irq), (dev_id))
 
 /*
  * The following are not needed for the non-m68k ports
  */
-#define ide_ack_intr(base, irq)                (1)
+#define ide_ack_intr(hwif)             (1)
 #define ide_release_lock(lock)         do {} while (0)
 #define ide_get_lock(lock, hdlr, data) do {} while (0)
 
index 92ac97729ff54855410610d2b5ce301939804a68..bd8a7d16cd7deb4e14570d94336a9c60515858df 100644 (file)
@@ -277,6 +277,13 @@ static inline int check_signature(unsigned long io_addr,
 out:
        return retval;
 }
+
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* __KERNEL__ */
 
 #endif
index a26453b2fc1f8bf288d6d624556f6674e589a011..80596ffcb84d26b16cfbc3dfec1460d981d3015f 100644 (file)
@@ -162,4 +162,10 @@ static __inline__ void *sparc_dvma_malloc(int size, char *name, __u32 *dvmaaddr_
 #define virt_to_phys(x) __pa((unsigned long)(x))
 #define phys_to_virt(x) __va((unsigned long)(x))
 
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* !(__SPARC_IO_H) */
diff --git a/include/asm-sparc64/hdreg.h b/include/asm-sparc64/hdreg.h
new file mode 100644 (file)
index 0000000..06885e3
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Id: hdreg.h,v 1.9 1998/05/08 21:05:28 davem Exp $
+ * hdreg.h: Ultra/PCI specific IDE glue.
+ *
+ * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998  Eddie C. Dost   (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_HDREG_H
+#define __SPARC64_HDREG_H
+
+typedef unsigned long ide_ioreg_t;
+
+#endif /* __SPARC64_HDREG_H */
index 191b95cb2c8e54c8660c4bc8689f0ffcbb32b835..6666e97376ba668ebdfee1c0b899936db5e1103c 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <asm/pgtable.h>
 
-typedef unsigned long ide_ioreg_t;
-
 #undef  MAX_HWIFS
 #define MAX_HWIFS      2
 
@@ -29,21 +27,42 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
        return 0;
 }
 
-static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
+       ide_ioreg_t reg =  data_port;
        int i;
 
-       /* These are simply offsets from base. */
-       for (i = 0; i < 8; i++)
-               *p++ = base++;
-       /* PCI code needs to figure out these. */
-       for ( ; i < 10; i++)
-               *p++ = 0;
-       /* PCI code needs to figure out this. */
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw->io_ports[i] = reg;
+               reg += 1;
+       }
+       if (ctrl_port) {
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+       } else {
+               hw->io_ports[IDE_CONTROL_OFFSET] = 0;
+       }
        if (irq != NULL)
                *irq = 0;
 }
 
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifdef __DO_I_NEED_THIS
+       hw_regs_t hw;
+       int index;
+
+       for (index = 0; index < MAX_HWIFS; index++) {
+               ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, 0);
+               hw.irq = ide_default_irq(ide_default_io_base(index));
+               ide_register_hw(&hw, NULL);
+       }
+#endif /* __DO_I_NEED_THIS */
+}
+
 typedef union {
        unsigned int            all     : 8;    /* all of the bits together */
        struct {
@@ -92,11 +111,6 @@ static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
 #undef  HD_DATA
 #define HD_DATA ((ide_ioreg_t)0)
 
-static __inline__ int ide_ack_intr(ide_ioreg_t status_port, ide_ioreg_t irq_port)
-{
-       return 1;
-}
-
 /* From m68k code... */
 
 #ifdef insl
@@ -255,13 +269,12 @@ static __inline__ void ide_fix_driveid(struct hd_driveid *id)
        }
 }
 
-static __inline__ void ide_release_lock (int *ide_lock)
-{
-}
-
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
-{
-}
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)             (1)
+#define ide_release_lock(lock)         do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
 
 #endif /* __KERNEL__ */
 
index c9e3c84609d72845fee7a103956009d8e5757572..3af29e5fd6da900c90dd4188644092821067f989 100644 (file)
@@ -226,4 +226,10 @@ extern void *sparc_alloc_io(u32 pa, void *va, int sz, char *name,
 extern void sparc_free_io (void *va, int sz);
 extern void *sparc_dvma_malloc (int sz, char *name, __u32 *dvma_addr);
 
+/* Nothing to do */
+
+#define dma_cache_inv(_start,_size)            do { } while (0)
+#define dma_cache_wback(_start,_size)          do { } while (0)
+#define dma_cache_wback_inv(_start,_size)      do { } while (0)
+
 #endif /* !(__SPARC64_IO_H) */
index e467ae9b6545c9a5f422f99082e01768c6c0895a..2fee75fec10e989afce6af7c27026de6d5b6428f 100644 (file)
 #define SMART_STATUS           0xda
 #define SMART_AUTO_OFFLINE     0xdb
 
+/* WIN_SETFEATURES sub-commands */
+
+#define SETFEATURES_EN_WCACHE  0x02    /* Enable write cache */
+#define SETFEATURES_XFER       0x03    /* Set transfer mode */
+#      define XFER_UDMA_4      0x44    /* 0100|0100 */
+#      define XFER_UDMA_3      0x43    /* 0100|0011 */
+#      define XFER_UDMA_2      0x42    /* 0100|0010 */
+#      define XFER_UDMA_1      0x41    /* 0100|0001 */
+#      define XFER_UDMA_0      0x40    /* 0100|0000 */
+#      define XFER_MW_DMA_2    0x22    /* 0010|0010 */
+#      define XFER_MW_DMA_1    0x21    /* 0010|0001 */
+#      define XFER_MW_DMA_0    0x20    /* 0010|0000 */
+#      define XFER_SW_DMA_2    0x12    /* 0001|0010 */
+#      define XFER_SW_DMA_1    0x11    /* 0001|0001 */
+#      define XFER_SW_DMA_0    0x10    /* 0001|0000 */
+#      define XFER_PIO_4       0x0C    /* 0000|1100 */
+#      define XFER_PIO_3       0x0B    /* 0000|1011 */
+#      define XFER_PIO_2       0x0A    /* 0000|1010 */
+#      define XFER_PIO_1       0x09    /* 0000|1001 */
+#      define XFER_PIO_0       0x08    /* 0000|1000 */
+#      define XFER_PIO_SLOW    0x00    /* 0000|0000 */
+#define SETFEATURES_EN_APM     0x05    /* Enable advanced power management */
+#define SETFEATURES_DIS_MSN    0x31    /* Disable Media Status Notification */
+#define SETFEATURES_DIS_RLA    0x55    /* Disable read look-ahead feature */
+#define SETFEATURES_EN_RI      0x5D    /* Enable release interrupt */
+#define SETFEATURES_EN_SI      0x5E    /* Enable SERVICE interrupt */
+#define SETFEATURES_DIS_RPOD   0x66    /* Disable reverting to power on defaults */
+#define SETFEATURES_DIS_WCACHE 0x82    /* Disable write cache */
+#define SETFEATURES_DIS_APM    0x85    /* Disable advanced power management */
+#define SETFEATURES_EN_MSN     0x95    /* Enable Media Status Notification */
+#define SETFEATURES_EN_RLA     0xAA    /* Enable read look-ahead feature */
+#define SETFEATURES_EN_RPOD    0xCC    /* Enable reverting to power on defaults */
+#define SETFEATURES_DIS_RI     0xDD    /* Disable release interrupt */
+#define SETFEATURES_DIS_SI     0xDE    /* Disable SERVICE interrupt */
+
 /* WIN_SECURITY sub-commands */
+
 #define SECURITY_SET_PASSWORD          0xBA    /* 0xF1 */
 #define SECURITY_UNLOCK                        0xBB    /* 0xF2 */
 #define SECURITY_ERASE_PREPARE         0xBC    /* 0xF3 */
diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h
new file mode 100644 (file)
index 0000000..10bd724
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _LINUX_HDSMART_H
+#define _LINUX_HDSMART_H
+
+/*
+ * This file contains some defines for the AT-hd-controller.
+ * Various sources.  
+ */
+
+#define NR_ATTRIBUTES  30
+
+typedef struct threshold_s {
+       unsigned char   id;
+       unsigned char   threshold;
+       unsigned char   reserved[10];
+} __attribute__ ((packed)) threshold_t;
+
+typedef struct thresholds_s {
+       unsigned short  revision;
+       threshold_t     thresholds[NR_ATTRIBUTES];
+       unsigned char   reserved[18];
+       unsigned char   vendor[131];
+       unsigned char   checksum;
+} __attribute__ ((packed)) thresholds_t;
+
+typedef struct value_s {
+       unsigned char   id;
+       unsigned short  status;
+       unsigned char   value;
+       unsigned char   vendor[8];
+} __attribute__ ((packed)) value_t;
+
+typedef struct values_s {
+       unsigned short  revision;
+       value_t         values[NR_ATTRIBUTES];
+       unsigned char   offline_status;
+       unsigned char   vendor1;
+       unsigned short  offline_timeout;
+       unsigned char   vendor2;
+       unsigned char   offline_capability;
+       unsigned short  smart_capability;
+       unsigned char   reserved[16];
+       unsigned char   vendor[125];
+       unsigned char   checksum;
+} __attribute__ ((packed)) values_t;
+
+#if !defined(__KERNEL__) || defined(_IDE_DISK_C)
+#define NR_OFFLINE_TEXTS       5
+struct {
+       unsigned char   value;
+       char            *text;
+} offline_status_text[NR_OFFLINE_TEXTS] = {
+       { 0x00, "NeverStarted" },
+       { 0x02, "Completed" },
+       { 0x04, "Suspended" },
+       { 0x05, "Aborted" },
+       { 0x06, "Failed" }
+};
+#endif /* !defined(__KERNEL__) || defined(_IDE_DISK_C) */
+
+#endif /* _LINUX_HDSMART_H */
diff --git a/include/linux/ide.h b/include/linux/ide.h
new file mode 100644 (file)
index 0000000..a06b9f0
--- /dev/null
@@ -0,0 +1,821 @@
+#ifndef _IDE_H
+#define _IDE_H
+/*
+ *  linux/drivers/block/ide.h
+ *
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/hdsmart.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <asm/hdreg.h>
+
+/*
+ * This is the multiple IDE interface driver, as evolved from hd.c.
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * There can be up to two drives per interface, as per the ATA-2 spec.
+ *
+ * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
+ * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
+ * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ */
+
+/******************************************************************************
+ * IDE driver configuration options (play with these as desired):
+ *
+ * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
+ */
+#undef REALLY_FAST_IO                  /* define if ide ports are perfect */
+#define INITIAL_MULT_COUNT     0       /* off=0; on=2,4,8,16,32, etc.. */
+
+#ifndef SUPPORT_SLOW_DATA_PORTS                /* 1 to support slow data ports */
+#define SUPPORT_SLOW_DATA_PORTS        1       /* 0 to reduce kernel size */
+#endif
+#ifndef SUPPORT_VLB_SYNC               /* 1 to support weird 32-bit chips */
+#define SUPPORT_VLB_SYNC       1       /* 0 to reduce kernel size */
+#endif
+#ifndef DISK_RECOVERY_TIME             /* off=0; on=access_delay_time */
+#define DISK_RECOVERY_TIME     0       /*  for hardware that needs it */
+#endif
+#ifndef OK_TO_RESET_CONTROLLER         /* 1 needed for good error recovery */
+#define OK_TO_RESET_CONTROLLER 1       /* 0 for use with AH2372A/B interface */
+#endif
+#ifndef FAKE_FDISK_FOR_EZDRIVE         /* 1 to help linux fdisk with EZDRIVE */
+#define FAKE_FDISK_FOR_EZDRIVE         1       /* 0 to reduce kernel size */
+#endif
+#ifndef FANCY_STATUS_DUMPS             /* 1 for human-readable drive errors */
+#define FANCY_STATUS_DUMPS     1       /* 0 to reduce kernel size */
+#endif
+
+#ifdef CONFIG_BLK_DEV_CMD640
+#if 0  /* change to 1 when debugging cmd640 problems */
+void cmd640_dump_regs (void);
+#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
+#endif
+#endif  /* CONFIG_BLK_DEV_CMD640 */
+
+/*
+ * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
+ */
+#define IDE_DRIVE_CMD          99      /* (magic) undef to reduce kernel size*/
+
+/*
+ *  "No user-serviceable parts" beyond this point  :)
+ *****************************************************************************/
+
+typedef unsigned char  byte;   /* used everywhere */
+
+/*
+ * Probably not wise to fiddle with these
+ */
+#define ERROR_MAX      8       /* Max read/write errors per sector */
+#define ERROR_RESET    3       /* Reset controller every 4th retry */
+#define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
+
+/*
+ * Ensure that various configuration flags have compatible settings
+ */
+#ifdef REALLY_SLOW_IO
+#undef REALLY_FAST_IO
+#endif
+
+#define HWIF(drive)            ((ide_hwif_t *)((drive)->hwif))
+#define HWGROUP(drive)         ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
+
+/*
+ * Definitions for accessing IDE controller registers
+ */
+#define IDE_NR_PORTS           (10)
+
+#define IDE_DATA_OFFSET                (0)
+#define IDE_ERROR_OFFSET       (1)
+#define IDE_NSECTOR_OFFSET     (2)
+#define IDE_SECTOR_OFFSET      (3)
+#define IDE_LCYL_OFFSET                (4)
+#define IDE_HCYL_OFFSET                (5)
+#define IDE_SELECT_OFFSET      (6)
+#define IDE_STATUS_OFFSET      (7)
+#define IDE_CONTROL_OFFSET     (8)
+#define IDE_IRQ_OFFSET         (9)
+
+#define IDE_FEATURE_OFFSET     IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET     IDE_STATUS_OFFSET
+
+#define IDE_DATA_REG           (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG          (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG                (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG         (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG           (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG           (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG         (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG         (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG                (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_IRQ_REG            (HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
+
+#define IDE_FEATURE_REG                IDE_ERROR_REG
+#define IDE_COMMAND_REG                IDE_STATUS_REG
+#define IDE_ALTSTATUS_REG      IDE_CONTROL_REG
+#define IDE_IREASON_REG                IDE_NSECTOR_REG
+#define IDE_BCOUNTL_REG                IDE_LCYL_REG
+#define IDE_BCOUNTH_REG                IDE_HCYL_REG
+
+#ifdef REALLY_FAST_IO
+#define OUT_BYTE(b,p)          outb((b),(p))
+#define IN_BYTE(p)             (byte)inb(p)
+#else
+#define OUT_BYTE(b,p)          outb_p((b),(p))
+#define IN_BYTE(p)             (byte)inb_p(p)
+#endif /* REALLY_FAST_IO */
+
+#define GET_ERR()              IN_BYTE(IDE_ERROR_REG)
+#define GET_STAT()             IN_BYTE(IDE_STATUS_REG)
+#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
+#define BAD_R_STAT             (BUSY_STAT   | ERR_STAT)
+#define BAD_W_STAT             (BAD_R_STAT  | WRERR_STAT)
+#define BAD_STAT               (BAD_R_STAT  | DRQ_STAT)
+#define DRIVE_READY            (READY_STAT  | SEEK_STAT)
+#define DATA_READY             (DRQ_STAT)
+
+/*
+ * Some more useful definitions
+ */
+#define IDE_MAJOR_NAME "ide"   /* the same for all i/f; see also genhd.c */
+#define MAJOR_NAME     IDE_MAJOR_NAME
+#define PARTN_BITS     6       /* number of minor dev bits for partitions */
+#define PARTN_MASK     ((1<<PARTN_BITS)-1)     /* a useful bit mask */
+#define MAX_DRIVES     2       /* per interface; 2 assumed by lots of code */
+#define SECTOR_WORDS   (512 / 4)       /* number of 32bit words per sector */
+#define IDE_LARGE_SEEK(b1,b2,t)        (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
+#define IDE_MIN(a,b)   ((a)<(b) ? (a):(b))
+#define IDE_MAX(a,b)   ((a)>(b) ? (a):(b))
+
+/*
+ * Timeouts for various operations:
+ */
+#define WAIT_DRQ       (5*HZ/100)      /* 50msec - spec allows up to 20ms */
+#ifdef CONFIG_APM
+#define WAIT_READY     (5*HZ)          /* 5sec - some laptops are very slow */
+#else
+#define WAIT_READY     (3*HZ/100)      /* 30msec - should be instantaneous */
+#endif /* CONFIG_APM */
+#define WAIT_PIDENTIFY (10*HZ) /* 10sec  - should be less than 3ms (?)
+                                           if all ATAPI CD is closed at boot */
+#define WAIT_WORSTCASE (30*HZ) /* 30sec  - worst case when spinning up */
+#define WAIT_CMD       (10*HZ) /* 10sec  - maximum wait for an IRQ to happen */
+#define WAIT_MIN_SLEEP (2*HZ/100)      /* 20msec - minimum sleep time */
+
+#define SELECT_DRIVE(hwif,drive)                               \
+{                                                              \
+       if (hwif->selectproc)                                   \
+               hwif->selectproc(drive);                        \
+       OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+}
+
+/*
+ * Check for an interrupt and acknowledge the interrupt status
+ */
+struct hwif_s;
+typedef int (ide_ack_intr_t)(struct hwif_s *);
+
+/*
+ * Structure to hold all information about the location of this port
+ */
+typedef struct hw_regs_s {
+       ide_ioreg_t     io_ports[IDE_NR_PORTS]; /* task file registers */
+       int             irq;                    /* our irq number */
+       ide_ack_intr_t  *ack_intr;              /* acknowledge interrupt */
+       void            *priv;                  /* interface specific data */
+} hw_regs_t;
+
+/*
+ * Register new hardware with ide
+ */
+int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
+
+/*
+ * Set up hw_regs_t structure before calling ide_register_hw (optional)
+ */
+void ide_setup_ports(  hw_regs_t *hw,
+                       ide_ioreg_t base,
+                       int *offsets,
+                       ide_ioreg_t ctrl,
+                       ide_ioreg_t intr,
+                       ide_ack_intr_t *ack_intr,
+                       int irq);
+
+#include <asm/ide.h>
+
+/*
+ * Now for the data we need to maintain per-drive:  ide_drive_t
+ */
+
+#define ide_scsi       0x21
+#define ide_disk       0x20
+#define ide_optical    0x7
+#define ide_cdrom      0x5
+#define ide_tape       0x1
+#define ide_floppy     0x0
+
+typedef union {
+       unsigned all                    : 8;    /* all of the bits together */
+       struct {
+               unsigned set_geometry   : 1;    /* respecify drive geometry */
+               unsigned recalibrate    : 1;    /* seek to cyl 0      */
+               unsigned set_multmode   : 1;    /* set multmode count */
+               unsigned set_tune       : 1;    /* tune interface for drive */
+               unsigned reserved       : 4;    /* unused */
+               } b;
+       } special_t;
+
+typedef struct ide_drive_s {
+       struct request          *queue; /* request queue */
+       struct ide_drive_s      *next;  /* circular list of hwgroup drives */
+       unsigned long sleep;            /* sleep until this time */
+       unsigned long service_start;    /* time we started last request */
+       unsigned long service_time;     /* service time of last request */
+       special_t       special;        /* special action flags */
+       byte     keep_settings;         /* restore settings after drive reset */
+       byte     using_dma;             /* disk is using dma for read/write */
+       byte     waiting_for_dma;       /* dma currently in progress */
+       byte     unmask;                /* flag: okay to unmask other irqs */
+       byte     slow;                  /* flag: slow data port */
+       byte     bswap;                 /* flag: byte swap data */
+       byte     dsc_overlap;           /* flag: DSC overlap */
+       byte     nice1;                 /* flag: give potential excess bandwidth */
+       unsigned present        : 1;    /* drive is physically present */
+       unsigned noprobe        : 1;    /* from:  hdx=noprobe */
+       unsigned busy           : 1;    /* currently doing revalidate_disk() */
+       unsigned removable      : 1;    /* 1 if need to do check_media_change */
+       unsigned forced_geom    : 1;    /* 1 if hdx=c,h,s was given at boot */
+       unsigned no_unmask      : 1;    /* disallow setting unmask bit */
+       unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
+       unsigned nobios         : 1;    /* flag: do not probe bios for drive */
+       unsigned revalidate     : 1;    /* request revalidation */
+       unsigned atapi_overlap  : 1;    /* flag: ATAPI overlap (not supported) */
+       unsigned nice0          : 1;    /* flag: give obvious excess bandwidth */
+       unsigned nice2          : 1;    /* flag: give a share in our own bandwidth */
+       unsigned doorlocking    : 1;    /* flag: for removable only: door lock/unlock works */
+       unsigned autotune       : 2;    /* 1=autotune, 2=noautotune, 0=default */
+#if FAKE_FDISK_FOR_EZDRIVE
+       unsigned remap_0_to_1   : 1;    /* flag: partitioned with ezdrive */
+#endif /* FAKE_FDISK_FOR_EZDRIVE */
+       byte            media;          /* disk, cdrom, tape, floppy, ... */
+       select_t        select;         /* basic drive/head select reg value */
+       byte            ctl;            /* "normal" value for IDE_CONTROL_REG */
+       byte            ready_stat;     /* min status value for drive ready */
+       byte            mult_count;     /* current multiple sector setting */
+       byte            mult_req;       /* requested multiple sector setting */
+       byte            tune_req;       /* requested drive tuning setting */
+       byte            io_32bit;       /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+       byte            bad_wstat;      /* used for ignoring WRERR_STAT */
+       byte            nowerr;         /* used for ignoring WRERR_STAT */
+       byte            sect0;          /* offset of first sector for DM6:DDO */
+       byte            usage;          /* current "open()" count for drive */
+       byte            head;           /* "real" number of heads */
+       byte            sect;           /* "real" sectors per track */
+       byte            bios_head;      /* BIOS/fdisk/LILO number of heads */
+       byte            bios_sect;      /* BIOS/fdisk/LILO sectors per track */
+       unsigned short  bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
+       unsigned short  cyl;            /* "real" number of cyls */
+       unsigned int    drive_data;     /* for use by tuneproc/selectproc as needed */
+       void              *hwif;        /* actually (ide_hwif_t *) */
+       wait_queue_head_t wqueue;       /* used to wait for drive in open() */
+       struct hd_driveid *id;          /* drive model identification info */
+       struct hd_struct  *part;        /* drive partition table */
+       char            name[4];        /* drive name, such as "hda" */
+       void            *driver;        /* (ide_driver_t *) */
+       void            *driver_data;   /* extra driver data */
+       struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
+       void            *settings;      /* /proc/ide/ drive settings */
+       char            driver_req[10]; /* requests specific driver */
+#if 1
+       struct thresholds_s     *smart_thresholds;
+       struct values_s         *smart_values;
+#else
+       thresholds_t            smart_thresholds;
+       values_t                smart_values;
+#endif
+       } ide_drive_t;
+
+/*
+ * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case the caller
+ * should either try again later, or revert to PIO for the current request.
+ */
+typedef enum { ide_dma_read,   ide_dma_write,          ide_dma_begin,
+               ide_dma_end,    ide_dma_check,          ide_dma_on,
+               ide_dma_off,    ide_dma_off_quietly,    ide_dma_test_irq,
+               ide_dma_bad_drive,                      ide_dma_good_drive
+       } ide_dma_action_t;
+
+typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
+
+
+/*
+ * An ide_tuneproc_t() is used to set the speed of an IDE interface
+ * to a particular PIO mode.  The "byte" parameter is used
+ * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
+ * indicates that the interface driver should "auto-tune" the PIO mode
+ * according to the drive capabilities in drive->id;
+ *
+ * Not all interface types support tuning, and not all of those
+ * support all possible PIO settings.  They may silently ignore
+ * or round values as they see fit.
+ */
+typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
+
+/*
+ * This is used to provide support for strange interfaces
+ */
+typedef void (ide_selectproc_t) (ide_drive_t *);
+
+/*
+ * hwif_chipset_t is used to keep track of the specific hardware
+ * chipset used by each IDE interface, if known.
+ */
+typedef enum { ide_unknown,    ide_generic,    ide_pci,
+               ide_cmd640,     ide_dtc2278,    ide_ali14xx,
+               ide_qd6580,     ide_umc8672,    ide_ht6560b,
+               ide_pdc4030,    ide_rz1000,     ide_trm290,
+               ide_cmd646,     ide_cy82c693,   ide_4drives
+       } hwif_chipset_t;
+
+typedef struct ide_pci_devid_s {
+       unsigned short  vid;
+       unsigned short  did;
+} ide_pci_devid_t;
+
+#define IDE_PCI_DEVID_NULL     ((ide_pci_devid_t){0,0})
+#define IDE_PCI_DEVID_EQ(a,b)  (a.vid == b.vid && a.did == b.did)
+
+typedef struct hwif_s {
+       struct hwif_s   *next;          /* for linked-list in ide_hwgroup_t */
+       void            *hwgroup;       /* actually (ide_hwgroup_t *) */
+       ide_ioreg_t     io_ports[IDE_NR_PORTS]; /* task file registers */
+       hw_regs_t       hw;             /* Hardware info */
+       ide_drive_t     drives[MAX_DRIVES];     /* drive info */
+       struct gendisk  *gd;            /* gendisk structure */
+       ide_tuneproc_t  *tuneproc;      /* routine to tune PIO mode for drives */
+       ide_selectproc_t *selectproc;   /* tweaks hardware to select drive */
+       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 long   dma_base;       /* base addr for dma ports */
+       unsigned        dma_extra;      /* extra 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 */
+       char            name[6];        /* name of interface, eg. "ide0" */
+       byte            index;          /* 0 for ide0; 1 for ide1; ... */
+       hwif_chipset_t  chipset;        /* sub-module for tuning.. */
+       unsigned        noprobe    : 1; /* don't probe for this interface */
+       unsigned        present    : 1; /* this interface exists */
+       unsigned        serialized : 1; /* serialized operation with mate hwif */
+       unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
+       unsigned        reset      : 1; /* reset after probe */
+       unsigned        autodma    : 1; /* automatically try to enable DMA at boot */
+       byte            channel;        /* for dual-port chips: 0=primary, 1=secondary */
+       struct pci_dev  *pci_dev;       /* for pci chipsets */
+       ide_pci_devid_t pci_devid;      /* for pci chipsets: {VID,DID} */
+#if (DISK_RECOVERY_TIME > 0)
+       unsigned long   last_time;      /* time when previous rq was done */
+#endif
+       } ide_hwif_t;
+
+/*
+ *  internal ide interrupt handler type
+ */
+typedef void (ide_handler_t)(ide_drive_t *);
+
+typedef struct hwgroup_s {
+       spinlock_t              spinlock; /* protects "busy" and "handler" */
+       ide_handler_t           *handler;/* irq handler, if active */
+       int                     busy;   /* BOOL: protects all fields below */
+       ide_drive_t             *drive; /* current drive */
+       ide_hwif_t              *hwif;  /* ptr to current hwif in linked-list */
+       struct request          *rq;    /* current request */
+       struct timer_list       timer;  /* failsafe timer */
+       struct request          wrq;    /* local copy of current write rq */
+       unsigned long           poll_timeout;   /* timeout value during long polls */
+       } ide_hwgroup_t;
+
+/*
+ * configurable drive settings
+ */
+
+#define TYPE_INT       0
+#define TYPE_INTA      1
+#define TYPE_BYTE      2
+#define TYPE_SHORT     3
+
+#define SETTING_READ   (1 << 0)
+#define SETTING_WRITE  (1 << 1)
+#define SETTING_RW     (SETTING_READ | SETTING_WRITE)
+
+typedef int (ide_procset_t)(ide_drive_t *, int);
+typedef struct ide_settings_s {
+       char                    *name;
+       int                     rw;
+       int                     read_ioctl;
+       int                     write_ioctl;
+       int                     data_type;
+       int                     min;
+       int                     max;
+       int                     mul_factor;
+       int                     div_factor;
+       void                    *data;
+       ide_procset_t           *set;
+       int                     auto_remove;
+       struct ide_settings_s   *next;
+} ide_settings_t;
+
+void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set);
+void ide_remove_setting(ide_drive_t *drive, char *name);
+ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name);
+int ide_read_setting(ide_drive_t *t, ide_settings_t *setting);
+int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val);
+void ide_add_generic_settings(ide_drive_t *drive);
+
+/*
+ * /proc/ide interface
+ */
+typedef struct {
+       const char      *name;
+       mode_t          mode;
+       read_proc_t     *read_proc;
+       write_proc_t    *write_proc;
+} ide_proc_entry_t;
+
+#ifdef CONFIG_PROC_FS
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
+void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_capacity;
+read_proc_t proc_ide_read_geometry;
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{                                      \
+       len -= off;                     \
+       if (len < count) {              \
+               *eof = 1;               \
+               if (len <= 0)           \
+                       return 0;       \
+       } else                          \
+               len = count;            \
+       *start = page + off;            \
+       return len;                     \
+}
+#else
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
+#endif
+
+/*
+ * Subdrivers support.
+ */
+#define IDE_SUBDRIVER_VERSION  1
+
+typedef int    (ide_cleanup_proc)(ide_drive_t *);
+typedef void   (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
+typedef void   (ide_end_request_proc)(byte, ide_hwgroup_t *);
+typedef int    (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+typedef int    (ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
+typedef void   (ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
+typedef int    (ide_check_media_change_proc)(ide_drive_t *);
+typedef void   (ide_pre_reset_proc)(ide_drive_t *);
+typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
+typedef void   (ide_special_proc)(ide_drive_t *);
+typedef void   (ide_setting_proc)(ide_drive_t *);
+
+typedef struct ide_driver_s {
+       const char                      *name;
+       const char                      *version;
+       byte                            media;
+       unsigned busy                   : 1;
+       unsigned supports_dma           : 1;
+       unsigned supports_dsc_overlap   : 1;
+       ide_cleanup_proc                *cleanup;
+       ide_do_request_proc             *do_request;
+       ide_end_request_proc            *end_request;
+       ide_ioctl_proc                  *ioctl;
+       ide_open_proc                   *open;
+       ide_release_proc                *release;
+       ide_check_media_change_proc     *media_change;
+       ide_pre_reset_proc              *pre_reset;
+       ide_capacity_proc               *capacity;
+       ide_special_proc                *special;
+       ide_proc_entry_t                *proc;
+       } ide_driver_t;
+
+#define DRIVER(drive)          ((ide_driver_t *)((drive)->driver))
+
+/*
+ * IDE modules.
+ */
+#define IDE_CHIPSET_MODULE             0       /* not supported yet */
+#define IDE_PROBE_MODULE               1
+#define IDE_DRIVER_MODULE              2
+
+typedef int    (ide_module_init_proc)(void);
+
+typedef struct ide_module_s {
+       int                             type;
+       ide_module_init_proc            *init;
+       void                            *info;
+       struct ide_module_s             *next;
+} ide_module_t;
+
+/*
+ * ide_hwifs[] is the master data structure used to keep track
+ * of just about everything in ide.c.  Whenever possible, routines
+ * should be using pointers to a drive (ide_drive_t *) or
+ * pointers to a hwif (ide_hwif_t *), rather than indexing this
+ * structure directly (the allocation/layout may change!).
+ *
+ */
+#ifndef _IDE_C
+extern ide_hwif_t      ide_hwifs[];            /* master data repository */
+extern  ide_module_t   *ide_modules;
+#endif
+
+/*
+ * We need blk.h, but we replace its end_request by our own version.
+ */
+#define IDE_DRIVER             /* Toggle some magic bits in blk.h */
+#define LOCAL_END_REQUEST      /* Don't generate end_request in blk.h */
+#include <linux/blk.h>
+
+void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
+
+/*
+ * This is used for (nearly) all data transfers from/to the IDE interface
+ */
+void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+
+/*
+ * This is used on exit from the driver, to designate the next irq handler
+ * and also to start the safety timer.
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout);
+
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * ide_error() takes action based on the error returned by the controller.
+ * The calling function must return afterwards, to restart the request.
+ */
+void ide_error (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * Issue a simple drive command
+ * The drive must be selected beforehand.
+ */
+void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+
+/*
+ * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+ * removing leading/trailing blanks and compressing internal blanks.
+ * It is primarily used to tidy up the model name/number fields as
+ * returned by the WIN_[P]IDENTIFY commands.
+ */
+void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error() -- caller should return.
+ *
+ */
+int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+
+/*
+ * This routine is called from the partition-table code in genhd.c
+ * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
+ *
+ * The second parameter, "xparm", determines exactly how the translation
+ * will be handled:
+ *              0 = convert to CHS with fewer than 1024 cyls
+ *                     using the same method as Ontrack DiskManager.
+ *              1 = same as "0", plus offset everything by 63 sectors.
+ *             -1 = similar to "0", plus redirect sector 0 to sector 1.
+ *             >1 = convert to a CHS geometry with "xparm" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
+ */
+int ide_xlate_1024 (kdev_t, int, const char *);
+
+/*
+ * Start a reset operation for an IDE interface.
+ * The caller should return immediately after invoking this.
+ */
+void ide_do_reset (ide_drive_t *);
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_cmd (struct request *rq);
+
+/*
+ * "action" parameter type for ide_do_drive_cmd() below.
+ */
+typedef enum
+       {ide_wait,      /* insert rq at end of list, and wait for it */
+        ide_next,      /* insert rq immediately after current request */
+        ide_preempt,   /* insert rq in front of current request */
+        ide_end}       /* insert rq at end of list, but don't wait for it */
+ ide_action_t;
+
+/*
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * If action is ide_wait, then the rq is queued at the end of the
+ * request queue, and the function sleeps until it has been processed.
+ * This is for use when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then the rq is queued at the head of
+ * the request queue, displacing the currently-being-processed
+ * request and this function returns immediately without waiting
+ * for the new rq to be completed.  This is VERY DANGEROUS, and is
+ * intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_next, then the rq is queued immediately after
+ * the currently-being-processed-request (if any), and the function
+ * returns without waiting for the new rq to be completed.  As above,
+ * This is VERY DANGEROUS, and is intended for careful use by the
+ * ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code.
+ */
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+
+/*
+ * Clean up after success/failure of an explicit drive cmd.
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ */
+void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+
+/*
+ * Issue ATA command and wait for completion.
+ */
+int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+
+void ide_delay_50ms (void);
+
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ */
+int ide_system_bus_speed (void);
+
+/*
+ * ide_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multwrite operation.
+ */
+void ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+
+/*
+ * ide_stall_queue() can be used by a drive to give excess bandwidth back
+ * to the hwgroup by sleeping for timeout jiffies.
+ */
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
+
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+struct request **ide_get_queue (kdev_t dev);
+
+/*
+ * CompactFlash cards and their brethern pretend to be removable hard disks,
+ * but they never have a slave unit, and they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ */
+int drive_is_flashcard (ide_drive_t *drive);
+
+int  ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags);
+void ide_timer_expiry (unsigned long data);
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
+void ide_geninit (struct gendisk *gd);
+void do_ide0_request (void);
+#if MAX_HWIFS > 1
+void do_ide1_request (void);
+#endif
+#if MAX_HWIFS > 2
+void do_ide2_request (void);
+#endif
+#if MAX_HWIFS > 3
+void do_ide3_request (void);
+#endif
+#if MAX_HWIFS > 4
+void do_ide4_request (void);
+#endif
+#if MAX_HWIFS > 5
+void do_ide5_request (void);
+#endif
+#if MAX_HWIFS > 6
+void do_ide6_request (void);
+#endif
+#if MAX_HWIFS > 7
+void do_ide7_request (void);
+#endif
+void ide_init_subdrivers (void);
+
+#ifndef _IDE_C
+extern struct file_operations ide_fops[];
+#endif
+
+#ifdef _IDE_C
+#ifdef CONFIG_BLK_DEV_IDE
+int ideprobe_init (void);
+#endif /* CONFIG_BLK_DEV_IDE */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_init (void);
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_init (void);
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_init (void);
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_init (void);
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_init (void);
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+#endif /* _IDE_C */
+
+int ide_register_module (ide_module_t *module);
+void ide_unregister_module (ide_module_t *module);
+ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
+int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
+int ide_unregister_subdriver (ide_drive_t *drive);
+int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#define ON_BOARD               1
+#define NEVER_BOARD            0
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+#  define OFF_BOARD            ON_BOARD
+#else /* CONFIG_BLK_DEV_OFFBOARD */
+#  define OFF_BOARD            NEVER_BOARD
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
+unsigned long ide_find_free_region (unsigned short size) __init;
+void ide_scan_pcibus (void) __init;
+#endif
+#ifdef CONFIG_BLK_DEV_IDEDMA
+#define BAD_DMA_DRIVE          0
+#define GOOD_DMA_DRIVE         1
+int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
+void ide_dma_intr  (ide_drive_t *drive);
+int check_drive_lists (ide_drive_t *drive, int good_bad);
+int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
+int ide_release_dma (ide_hwif_t *hwif);
+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
+
+/* This is too ugly to live! */
+#ifdef CONFIG_BLK_DEV_PDC4030
+#include "pdc4030.h"
+#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+#else
+#define IS_PDC4030_DRIVE (0)   /* auto-NULLs out pdc4030 code */
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+#endif /* _IDE_H */
index 0b61899c0c924cde2636039136017349dd610fa4..f504bbde8e48b7bebc94feb97f7a10c80e4ad883 100644 (file)
@@ -626,8 +626,7 @@ typedef struct modem_info {
   atemu                 emu;             /* AT-emulator data               */
   struct termios       normal_termios;  /* For saving termios structs     */
   struct termios       callout_termios;
-  struct wait_queue    *open_wait;
-  struct wait_queue    *close_wait;
+  wait_queue_head_t    open_wait, close_wait;
 } modem_info;
 
 #define ISDN_MODEM_WINSIZE 8
@@ -683,8 +682,8 @@ struct ippp_struct {
   struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
   struct ippp_buf_queue *first;  /* pointer to (current) first packet */
   struct ippp_buf_queue *last;   /* pointer to (current) last used packet in queue */
-  struct wait_queue *wq;
-  struct wait_queue *wq1;
+  wait_queue_head_t wq;
+  wait_queue_head_t wql;
   struct task_struct *tk;
   unsigned int mpppcfg;
   unsigned int pppcfg;
@@ -748,7 +747,7 @@ typedef struct {
   ulong               flags;            /* Flags                            */
   int                 channels;         /* Number of channels               */
   int                 reject_bus;       /* Flag: Reject rejected call on bus*/
-  struct wait_queue  *st_waitq;         /* Wait-Queue for status-read's     */
+  wait_queue_head_t   st_waitq;         /* Wait-Queue for status-read's     */
   int                 maxbufsize;       /* Maximum Buffersize supported     */
   unsigned long       pktcount;         /* Until now: unused                */
   int                 running;          /* Flag: Protocolcode running       */
@@ -761,8 +760,8 @@ typedef struct {
   unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
 #endif
   struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
-  struct wait_queue  **rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
-  struct wait_queue  **snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
+  wait_queue_head_t  *rcv_waitq;  /* array of Wait-Queues for B-Channel-Reads  */
+  wait_queue_head_t  *snd_waitq;  /* array of Wait-Queue for B-Channel-Sends  */
   char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
 } driver;
 
@@ -778,7 +777,7 @@ typedef struct isdn_devt {
                                               /*  see ISDN_TIMER_..defines  */
   int               global_flags;
   infostruct        *infochain;                /* List of open info-devs.    */
-  struct wait_queue *info_waitq;               /* Wait-Queue for isdninfo    */
+  wait_queue_head_t info_waitq;               /* Wait-Queue for isdninfo    */
   struct timer_list timer;                    /* Misc.-function Timer       */
   int               chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel  */
   int               drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index    */
index 66e7ee8291f4eecc90c022ecd956c4ac8dae8caf..4b7d75ac80e0d6352b7af2fd65aec5ed60c1e2a2 100644 (file)
@@ -92,6 +92,9 @@
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
+#define IDE6_MAJOR     88
+#define IDE7_MAJOR     89
+
 #define UNIX98_PTY_MASTER_MAJOR        128
 #define UNIX98_PTY_MAJOR_COUNT 8
 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
index 552b9cb1f9baab9c53e19ce1448223b123d19fe3..1617bc6a6077c2ed7655e2c8643914a1ed4391d9 100644 (file)
 
 #define PCI_VENDOR_ID_PROMISE          0x105a
 #define PCI_DEVICE_ID_PROMISE_20246    0x4d33
+#define PCI_DEVICE_ID_PROMISE_20262    0x4d38
 #define PCI_DEVICE_ID_PROMISE_5300     0x5300
 
 #define PCI_VENDOR_ID_N9               0x105d
 #define PCI_DEVICE_ID_AL_M1523         0x1523
 #define PCI_DEVICE_ID_AL_M1531         0x1531
 #define PCI_DEVICE_ID_AL_M1533         0x1533
+#define PCI_DEVICE_ID_AL_M1541         0x1541
+#define PCI_DEVICE_ID_AL_M1543         0x1543
 #define PCI_DEVICE_ID_AL_M3307         0x3307
 #define PCI_DEVICE_ID_AL_M4803         0x5215
 #define PCI_DEVICE_ID_AL_M5219         0x5219
 #define PCI_DEVICE_ID_AL_M5229         0x5229
 #define PCI_DEVICE_ID_AL_M5237         0x5237
+#define PCI_DEVICE_ID_AL_M5243         0x5243
 #define PCI_DEVICE_ID_AL_M7101         0x7101
 
 #define PCI_VENDOR_ID_MITSUBISHI       0x10ba
index 2c4a5bcef2b6752e3f78deb101176876c35953e0..a3e76e1381283d2639fb39e285806de34c49f439 100644 (file)
@@ -170,7 +170,7 @@ struct dquot {
        struct list_head dq_free;       /* free list element */
        struct dquot *dq_hash_next;     /* Pointer to next in dquot_hash */
        struct dquot **dq_hash_pprev;   /* Pointer to previous in dquot_hash */
-       struct wait_queue *dq_wait;     /* Pointer to waitqueue */
+       wait_queue_head_t dq_wait;      /* Pointer to waitqueue */
        int dq_count;                   /* Reference count */
 
        /* fields after this point are cleared when invalidating */
index 2089a9710f3c493febeb426b071226d5f1061c1a..82d5da6e9685a52bdb91cb4595fe843385e3b5ec 100644 (file)
@@ -449,6 +449,14 @@ extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
  *     Add data to an sk_buff
  */
  
+extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
+{
+       unsigned char *tmp=skb->tail;
+       skb->tail+=len;
+       skb->len+=len;
+       return tmp;
+}
+
 extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
        unsigned char *tmp=skb->tail;
@@ -463,6 +471,13 @@ here:              ;
        return tmp;
 }
 
+extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
+{
+       skb->data-=len;
+       skb->len+=len;
+       return skb->data;
+}
+
 extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
 {
        skb->data-=len;
index 119b60eec11c076f71f378140044185526cc8d62..52c1e0f312e5cf3f418c3d035131bf3d05ab38a0 100644 (file)
@@ -278,6 +278,7 @@ struct video_unit
 #define VID_HARDWARE_TYPHOON   19
 #define VID_HARDWARE_VINO      20      /* Reserved for SGI Indy Vino */
 #define VID_HARDWARE_CADET     21      /* Cadet radio */
+#define VID_HARDWARE_CPIA      22
 
 /*
  *     Initialiser list
index 2d91a8d43bf54efdcfe392195ccea44438fa5b90..6d7dc75dc13253c0f028c2c1b6e4bf20b8e2b36b 100644 (file)
@@ -728,7 +728,7 @@ extern __inline__ int tcp_raise_window(struct sock *sk)
  */
 extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
 {
-       __u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache;
+       __u32 snd_wnd_packets = tp->snd_wnd / max(tp->mss_cache, 1);
 
        return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
 }
index d8f92fd09163cf05eae2bf12505b324f9deb67da..09d8af921143906c897830fee5aae054434aaa8e 100644 (file)
@@ -416,6 +416,10 @@ static struct dev_name_struct {
        { "hdj",     0x3840 },
        { "hdk",     0x3900 },
        { "hdl",     0x3940 },
+       { "hdm",     0x5800 },
+       { "hdn",     0x5840 },
+       { "hdo",     0x5900 },
+       { "hdp",     0x5940 },
 #endif
 #ifdef CONFIG_BLK_DEV_SD
        { "sda",     0x0800 },
@@ -929,7 +933,11 @@ static int __init checksetup(char *line)
 
 #ifdef CONFIG_BLK_DEV_IDE
        /* ide driver needs the basic string, rather than pre-processed values */
-       if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) {
+       if (!strncmp(line,"ide",3) ||
+#ifdef CONFIG_BLK_DEV_VIA82C586
+           !strncmp(line,"splitfifo",9) ||
+#endif /* CONFIG_BLK_DEV_VIA82C586 */
+           (!strncmp(line,"hd",2) && line[2] != '=')) {
                ide_setup(line);
                return 1;
        }