]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.99pre9-2 2.3.99pre9-2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:34:52 +0000 (15:34 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:34:52 +0000 (15:34 -0500)
200 files changed:
CREDITS
Documentation/Configure.help
Documentation/DocBook/Makefile
Documentation/DocBook/parportbook.tmpl
Documentation/pci.txt
Documentation/video4linux/bttv/CARDLIST
MAINTAINERS
arch/arm/Makefile
arch/arm/def-configs/ebsa110
arch/arm/def-configs/footbridge
arch/arm/def-configs/rpc
arch/arm/kernel/Makefile
arch/arm/kernel/iic.c [deleted file]
arch/arm/lib/Makefile
arch/i386/defconfig
arch/i386/kernel/acpi.c
arch/i386/kernel/pci-i386.c
arch/mips64/defconfig
arch/mips64/defconfig-ip22
arch/mips64/defconfig-ip27
arch/mips64/kernel/process.c
arch/mips64/kernel/signal32.c
arch/mips64/sgi-ip27/ip27-init.c
arch/mips64/sgi-ip27/ip27-irq.c
arch/mips64/sgi-ip27/ip27-setup.c
arch/mips64/sgi-ip27/ip27-timer.c
arch/ppc/8260_io/enet.c
arch/ppc/8260_io/uart.c
arch/ppc/configs/common_defconfig
arch/ppc/defconfig
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/chrp_time.c
arch/ppc/kernel/entry.S
arch/ppc/kernel/head.S
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/time.c
arch/ppc/kernel/traps.c
arch/ppc/mbxboot/Makefile
arch/ppc/mbxboot/embed_config.c
arch/ppc/mbxboot/gzimage.c [new file with mode: 0644]
arch/ppc/mbxboot/head_8260.S
arch/ppc/mbxboot/misc.c
arch/ppc/mbxboot/rdimage.c [new file with mode: 0644]
arch/ppc/mbxboot/vmlinux.lds [new file with mode: 0644]
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/treeboot/mkevimg
arch/ppc/treeboot/mkirimg
arch/ppc/vmlinux.lds
drivers/acorn/net/Makefile
drivers/acorn/net/ether1.c
drivers/acorn/net/ether3.c
drivers/acorn/net/etherh.c
drivers/block/Config.in
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/xor.c
drivers/char/Makefile
drivers/char/bttv.c
drivers/char/bttv.h
drivers/char/epca.c
drivers/char/mem.c
drivers/char/msp3400.c
drivers/char/tda7432.c [new file with mode: 0644]
drivers/char/tda8425.c
drivers/char/tda985x.c
drivers/char/tda9875.c [new file with mode: 0644]
drivers/char/tea6420.c [new file with mode: 0644]
drivers/ide/Config.in
drivers/ide/aec62xx.c
drivers/ide/alim15x3.c
drivers/ide/amd7409.c
drivers/ide/cmd64x.c
drivers/ide/hpt34x.c
drivers/ide/hpt366.c
drivers/ide/icside.c
drivers/ide/ide-disk.c
drivers/ide/ide-features.c
drivers/ide/ide-pci.c
drivers/ide/ide-pmac.c
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/ide/pdc202xx.c
drivers/ide/piix.c
drivers/ide/qd6580.c
drivers/ide/sis5513.c
drivers/ide/via82cxxx.c
drivers/net/Space.c
drivers/net/acenic.c
drivers/net/am79c961a.c
drivers/net/setup.c
drivers/net/sis900.c
drivers/parport/ChangeLog
drivers/parport/daisy.c
drivers/parport/ieee1284.c
drivers/parport/ieee1284_ops.c
drivers/parport/parport_pc.c
drivers/sound/i810_audio.c
drivers/sound/trident.c
drivers/sound/via82cxxx_audio.c
drivers/usb/audio.c
drivers/usb/input.c
drivers/usb/printer.c
drivers/usb/usb-uhci.c
drivers/usb/usb-uhci.h
drivers/video/cyber2000fb.c
drivers/video/cyber2000fb.h
fs/Makefile
fs/binfmt_aout.c
fs/dcache.c
fs/exec.c
fs/hfs/balloc.c
fs/hfs/catalog.c
fs/hfs/file_hdr.c
fs/hfs/hfs.h
fs/hfs/hfs_btree.h
fs/hfs/mdb.c
fs/hfs/part_tbl.c
fs/inode.c
fs/lockd/clntproc.c
fs/lockd/svclock.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/write.c
fs/partitions/check.c
fs/proc/kcore.c
fs/super.c
include/asm-arm/arch-ebsa285/irq.h
include/asm-arm/arch-l7200/dma.h [new file with mode: 0644]
include/asm-arm/arch-l7200/hardware.h [new file with mode: 0644]
include/asm-arm/arch-l7200/ide.h [new file with mode: 0644]
include/asm-arm/arch-l7200/io.h [new file with mode: 0644]
include/asm-arm/arch-l7200/irq.h [new file with mode: 0644]
include/asm-arm/arch-l7200/irqs.h [new file with mode: 0644]
include/asm-arm/arch-l7200/memory.h [new file with mode: 0644]
include/asm-arm/arch-l7200/param.h [new file with mode: 0644]
include/asm-arm/arch-l7200/processor.h [new file with mode: 0644]
include/asm-arm/arch-l7200/serial_l7200.h [new file with mode: 0644]
include/asm-arm/arch-l7200/system.h [new file with mode: 0644]
include/asm-arm/arch-l7200/time.h [new file with mode: 0644]
include/asm-arm/arch-l7200/timex.h [new file with mode: 0644]
include/asm-arm/arch-l7200/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-l7200/vmalloc.h [new file with mode: 0644]
include/asm-arm/hardirq.h
include/asm-arm/proc-armo/semaphore.h [deleted file]
include/asm-arm/proc-armv/locks.h
include/asm-arm/softirq.h
include/asm-arm/string.h
include/asm-arm/unistd.h
include/asm-mips/delay.h
include/asm-mips/hardirq.h
include/asm-mips/pgalloc.h
include/asm-mips/processor.h
include/asm-mips64/delay.h
include/asm-mips64/dma.h
include/asm-mips64/pgalloc.h
include/asm-mips64/processor.h
include/asm-mips64/sn/addrs.h
include/asm-mips64/sn/agent.h
include/asm-mips64/sn/intr.h
include/asm-mips64/sn/intr_public.h
include/asm-mips64/sn/io.h
include/asm-mips64/sn/klconfig.h
include/asm-mips64/sn/kldir.h
include/asm-mips64/sn/nmi.h
include/asm-ppc/bitops.h
include/asm-ppc/cpm_8260.h
include/asm-ppc/init.h
include/asm-ppc/page.h
include/asm-ppc/string.h
include/linux/hdreg.h
include/linux/hdsmart.h
include/linux/ide.h
include/linux/mmzone.h
include/linux/nfs_fs.h
include/linux/nfs_mount.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/pci_ids.h
include/linux/sunrpc/auth.h
include/linux/vmalloc.h
include/linux/wait.h
init/main.c
ipc/util.c
kernel/exec_domain.c
mm/highmem.c
mm/memory.c
mm/page_alloc.c
mm/swap_state.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
net/sunrpc/auth.c

diff --git a/CREDITS b/CREDITS
index f881963d7cf65b7e6994ee9f13028d7bbbaf65f4..eda1077d77361e52378919b639ac65d1ca55c312 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -942,14 +942,20 @@ D: Selection mechanism
 
 N: Andre Hedrick
 E: andre@linux-ide.org
+E: ahedrick@atipa.com
 E: andre@suse.com
+W: http://www.linux-ide.org/
 D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
 D: Active-ATA-Chipset maddness..........
 D: Ultra DMA 66/33
 D: ATA-Smart Kernel Daemon
-S: 580 Second Street, Suite 2
-S: Oakland, CA
+S: Linux ATA Development (LAD)
+S: Concord, CA
+S: Atipa Linux Solutions
+S: 6000 Connecticut  Kansas City, MO  64120
+S: SuSE Linux, Inc.
+S: 580 Second Street, Suite 210  Oakland, CA  94607
 S: USA
 
 N: Jochen Hein
index f65e265dc87e239b2c5a8b33308c674298349157..c2afcf32675aa3a21ad7bcdb60c9224bd55433c8 100644 (file)
@@ -1496,7 +1496,7 @@ CONFIG_MD_RAID0
 
   If unsure, say Y.
 
-DANGEROUS! RAID-1/RAID-5 code
+RAID-1/RAID-5 code (DANGEROUS)
 CONFIG_RAID15_DANGEROUS
   This new RAID1/RAID5 code has been freshly merged, and has not seen
   enough testing yet. While there are no known bugs in it, it might
@@ -10430,7 +10430,7 @@ CONFIG_NFSD
 Provide NFSv3 server support
 CONFIG_NFSD_V3
   If you would like to include the NFSv3 server as well as the NFSv2
-  server, say Y here.  In unsure, say Y.
+  server, say Y here.  If unsure, say Y.
 
 OS/2 HPFS file system support
 CONFIG_HPFS_FS
index d785534f6178a6d706ddfadc7d2c3c1151635e09..b6cdf0567d9d5d539beec4aa149aad8e14e87030 100644 (file)
@@ -18,6 +18,9 @@ db2ps db2pdf:
         (echo "*** You need to install DocBook stylesheets ***"; \
          exit 1)
 
+%.eps: %.fig
+       -fig2dev -Leps $< $@
+
 $(TOPDIR)/scripts/docproc:
        $(MAKE) -C $(TOPDIR)/scripts docproc
 
@@ -67,12 +70,15 @@ TEX :=      $(patsubst %.sgml, %.tex, $(BOOKS))
 LOG    :=      $(patsubst %.sgml, %.log, $(BOOKS))
 
 clean:
-       $(RM) core *~
-       $(RM) $(BOOKS)
-       $(RM) $(DVI) $(AUX) $(TEX) $(LOG)
+       -$(RM) core *~
+       -$(RM) $(BOOKS)
+       -$(RM) $(DVI) $(AUX) $(TEX) $(LOG)
+       -$(RM) parport-share.eps parport-multi.eps parport-structure.eps
 
 mrproper: clean
-       $(RM) $(PS) $(PDF)
+       -$(RM) $(PS) $(PDF)
+
+parportbook.ps: parport-share.eps parport-multi.eps parport-structure.eps
 
 %.ps : %.sgml db2ps
        db2ps $<
index 1644748adddc93b7298b0363177bb13c8069d417..a6ac266d14195ad4571a22ca3d93c286b14cd8ea 100644 (file)
@@ -1,8 +1,9 @@
+<!-- -*- sgml -*- -->
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
 
 <book id="ParportGuide">
  <bookinfo>
-  <title>The Parallel Port Subsystem</title>
+  <title>The Linux 2.4 Parallel Port Subsystem</title>
 
   <authorgroup>
    <author>
   </legalnotice>
  </bookinfo>
 
-<toc></toc>
+ <toc></toc>
 
-<chapter id="design">
-<title>Design goals</title>
+ <chapter id="design">
+  <title>Design goals</title>
 
-<sect1>
-<title>The problems</title>
+  <sect1>
+   <title>The problems</title>
 
-<!-- Short-comings -->
-<!-- How they are addressed -->
+   <para>
+    The first parallel port support for Linux came with the line
+    printer driver, <filename>lp</filename>.  The printer driver is a
+    character special device, and (in Linux 2.0) had support for
+    writing, via <function>write</function>, and configuration and
+    statistics reporting via <function>ioctl</function>.
+   </para>
 
-<!-- Short-comings
-     - simplistic lp driver
-     - platform differences
-     - no support for Zip drive pass-through
-     - no support for readback? When did Carsten add it?
-     - more parallel port devices. Figures?
-     - IEEE 1284 transfer modes: no advanced modes
-  -->
+   <para>
+    The printer driver could be used on any computer that had an IBM
+    PC-compatible parallel port.  Because some architectures have
+    parallel ports that aren't really the same as PC-style ports,
+    other variants of the printer driver were written in order to
+    support Amiga and Atari parallel ports.
+   </para>
+
+   <para>
+    When the Iomega Zip drive was released, and a driver written for
+    it, a problem became apparent.  The Zip drive is a parallel port
+    device that provides a parallel port of its own---it is designed
+    to sit between a computer and an attached printer, with the
+    printer plugged into the Zip drive, and the Zip drive plugged into
+    the computer.
+   </para>
 
-<para>The first parallel port support for Linux came with the line
-printer driver, <filename>lp</filename>.  The printer driver is a
-character special device, and (in Linux 2.0) had support for writing,
-via <function>write</function>, and configuration and statistics
-reporting via <function>ioctl</function>.</para>
-
-<para>The printer driver could be used on any computer that had an IBM
-PC-compatible parallel port.  Because some architectures have parallel
-ports that aren't really the same as PC-style ports, other variants of
-the printer driver were written in order to support Amiga and Atari
-parallel ports.</para>
-
-<para>When the Iomega Zip drive was released, and a driver written for
-it, a problem became apparent.  The Zip drive is a parallel port
-device that provides a parallel port of its own---it is designed to
-sit between a computer and an attached printer, with the printer
-plugged into the Zip drive, and the Zip drive plugged into the
-computer.</para>
-
-<para>The problem was that, although printers and Zip drives were both
-supported, for any given port only one could be used at a time.  Only
-one of the two drivers could be present in the kernel at once.  This
-was because of the fact that both drivers wanted to drive the same
-hardware---the parallel port.  When the printer driver initialised, it
-would call the <function>check_region</function> function to make sure
-that the IO region associated with the parallel port was free, and
-then it would call <function>request_region</function> to allocate it.
-The Zip drive used the same mechanism.  Whichever driver initialised
-first would gain exclusive control of the parallel port.</para>
-
-<para>The only way around this problem at the time was to make sure
-that both drivers were available as loadable kernel modules.  To use
-the printer, load the printer driver module; then for the Zip drive,
-unload the printer driver module and load the Zip driver
-module.</para>
-
-<para>The net effect was that printing a document that was stored on a Zip
-drive was a bit of an ordeal, at least if the Zip drive and printer
-shared a parallel port.  A better solution was needed.</para>
-
-<para>Zip drives are not the only devices that presented problems for
-Linux.  There are other devices with pass-through ports, for example
-parallel port CD-ROM drives.  There are also printers that report
-their status textually rather than using simple error pins: sending a
-command to the printer can cause it to report the number of pages that
-it has ever printed, or how much free memory it has, or whether it is
-running out of toner, and so on.  The printer driver didn't originally
-offer any facility for reading back this information (although Carsten
-Gross added nibble mode readback support for kernel 2.2).</para>
-
-<!-- IEEE 1284 transfer modes: no advanced modes --> 
-
-<para>The IEEE has issued a standards document called IEEE 1284, which
-documents existing practice for parallel port communications in a
-variety of modes.  Those modes are: <quote>compatibility</quote>,
-reverse nibble, reverse byte, ECP and EPP.  Newer devices often use
-the more advanced modes of transfer (ECP and EPP).  In Linux 2.0, the
-printer driver only supported <quote>compatibility mode</quote>
-(i.e. normal printer protocol) and reverse nibble mode.</para>
-
-</sect1>
-
-<sect1>
-<title>The solutions</title>
+   <para>
+    The problem was that, although printers and Zip drives were both
+    supported, for any given port only one could be used at a time.
+    Only one of the two drivers could be present in the kernel at
+    once.  This was because of the fact that both drivers wanted to
+    drive the same hardware---the parallel port.  When the printer
+    driver initialised, it would call the
+    <function>check_region</function> function to make sure that the
+    IO region associated with the parallel port was free, and then it
+    would call <function>request_region</function> to allocate it.
+    The Zip drive used the same mechanism.  Whichever driver
+    initialised first would gain exclusive control of the parallel
+    port.
+   </para>
+
+   <para>
+    The only way around this problem at the time was to make sure that
+    both drivers were available as loadable kernel modules.  To use
+    the printer, load the printer driver module; then for the Zip
+    drive, unload the printer driver module and load the Zip driver
+    module.
+   </para>
+
+   <para>
+    The net effect was that printing a document that was stored on a
+    Zip drive was a bit of an ordeal, at least if the Zip drive and
+    printer shared a parallel port.  A better solution was
+    needed.
+   </para>
+
+   <para>
+    Zip drives are not the only devices that presented problems for
+    Linux.  There are other devices with pass-through ports, for
+    example parallel port CD-ROM drives.  There are also printers that
+    report their status textually rather than using simple error pins:
+    sending a command to the printer can cause it to report the number
+    of pages that it has ever printed, or how much free memory it has,
+    or whether it is running out of toner, and so on.  The printer
+    driver didn't originally offer any facility for reading back this
+    information (although Carsten Gross added nibble mode readback
+    support for kernel 2.2).
+   </para>
+
+   <para>
+    The IEEE has issued a standards document called IEEE 1284, which
+    documents existing practice for parallel port communications in a
+    variety of modes.  Those modes are: <quote>compatibility</quote>,
+    reverse nibble, reverse byte, ECP and EPP.  Newer devices often
+    use the more advanced modes of transfer (ECP and EPP).  In Linux
+    2.0, the printer driver only supported <quote>compatibility
+    mode</quote> (i.e. normal printer protocol) and reverse nibble
+    mode.
+   </para>
+
+  </sect1>
+
+  <sect1>
+   <title>The solutions</title>
 
 <!-- How they are addressed
      - sharing model
@@ -143,104 +151,131 @@ printer driver only supported <quote>compatibility mode</quote>
      - whether or not 'platform independence' goal was met
   -->
 
-<para>The <filename>parport</filename> code in Linux 2.2 was designed
-to meet these problems of architectural differences in parallel ports,
-of port-sharing between devices with pass-through ports, and of lack
-of support for IEEE 1284 transfer modes.</para>
-
-<!-- platform differences -->
-
-<para>There are two layers to the
-<filename>parport</filename> subsystem, only one of which deals
-directly with the hardware.  The other layer deals with sharing and
-IEEE 1284 transfer modes.  In this way, parallel support for a
-particular architecture comes in the form of a module which registers
-itself with the generic sharing layer.</para>
-
-<!-- sharing model -->
-
-<para>The sharing model provided by the <filename>parport</filename>
-subsystem is one of exclusive access.  A device driver, such as the
-printer driver, must ask the <filename>parport</filename> layer for
-access to the port, and can only use the port once access has been
-granted.  When it has finished a <quote>transaction</quote>, it can
-tell the <filename>parport</filename> layer that it may release the
-port for other device drivers to use.</para>
-
-<!-- talk a bit about how drivers can share devices on the same port -->
-
-<para>Devices with pass-through ports all manage to share a parallel
-port with other devices in generally the same way.  The device has a
-latch for each of the pins on its pass-through port.  The normal state
-of affairs is pass-through mode, with the device copying the signal
-lines between its host port and its pass-through port.  When the
-device sees a special signal from the host port, it latches the
-pass-through port so that devices further downstream don't get
-confused by the pass-through device's conversation with the host
-parallel port: the device connected to the pass-through port (and any
-devices connected in turn to it) are effectively cut off from the
-computer.  When the pass-through device has completed its transaction
-with the computer, it enables the pass-through port again.</para>
-
-<mediaobject>
-<imageobject>
-<imagedata Align=center scalefit=1 fileref="parport-share.eps">
-</imageobject>
-</mediaobject>
-
-<para>This technique relies on certain <quote>special signals</quote>
-being invisible to devices that aren't watching for them.  This tends
-to mean only changing the data signals and leaving the control signals
-alone.  IEEE 1284.3 documents a standard protocol for daisy-chaining
-devices together with parallel ports.</para>
-
-<!-- transfer modes -->
-
-<para>Support for standard transfer modes are provided as operations
-that can be performed on a port, along with operations for setting the
-data lines, or the control lines, or reading the status lines.  These
-operations appear to the device driver as function pointers; more
-later.</para>
-
-</sect1>
-
-</chapter>
-
-<chapter id="transfermodes">
-<title>Standard transfer modes</title>
-
-<!-- Defined by IEEE, but in common use (even though there are widely -->
-<!-- varying implementations). -->
-
-<para>The <quote>standard</quote> transfer modes in use over the
-parallel port are <quote>defined</quote> by a document called IEEE
-1284.  It really just codifies existing practice and documents
-protocols (and variations on protocols) that have been in common use
-for quite some time.</para>
-
-<para>The original definitions of which pin did what were set out by
-Centronics Data Computer Corporation, but only the printer-side
-interface signals were specified.</para>
-
-<para>By the early 1980s, IBM's host-side implementation had become
-the most widely used.  New printers emerged that claimed Centronics
-compatibility, but although compatible with Centronics they differed
-from one another in a number of ways.</para>
-
-<para>As a result of this, when IEEE 1284 was published in 1994, all
-that it could really do was document the various protocols that are
-used for printers (there are about six variations on a theme).</para>
-
-<para>In addition to the protocol used to talk to
-Centronics-compatible printers, IEEE 1284 defined other protocols that
-are used for unidirectional peripheral-to-host transfers (reverse
-nibble and reverse byte) and for fast bidirectional transfers (ECP and
-EPP).</para>
-
-</chapter>
-
-<chapter id="structure">
-<title>Structure</title>
+   <para>
+    The <filename>parport</filename> code in Linux 2.2 was designed to
+    meet these problems of architectural differences in parallel
+    ports, of port-sharing between devices with pass-through ports,
+    and of lack of support for IEEE 1284 transfer modes.
+   </para>
+
+   <!-- platform differences -->
+
+   <para>
+    There are two layers to the <filename>parport</filename>
+    subsystem, only one of which deals directly with the hardware.
+    The other layer deals with sharing and IEEE 1284 transfer modes.
+    In this way, parallel support for a particular architecture comes
+    in the form of a module which registers itself with the generic
+    sharing layer.
+   </para>
+
+   <!-- sharing model -->
+
+   <para>
+    The sharing model provided by the <filename>parport</filename>
+    subsystem is one of exclusive access.  A device driver, such as
+    the printer driver, must ask the <filename>parport</filename>
+    layer for access to the port, and can only use the port once
+    access has been granted.  When it has finished a
+    <quote>transaction</quote>, it can tell the
+    <filename>parport</filename> layer that it may release the port
+    for other device drivers to use.
+   </para>
+
+   <!-- talk a bit about how drivers can share devices on the same port -->
+
+   <para>
+    Devices with pass-through ports all manage to share a parallel
+    port with other devices in generally the same way.  The device has
+    a latch for each of the pins on its pass-through port.  The normal
+    state of affairs is pass-through mode, with the device copying the
+    signal lines between its host port and its pass-through port.
+    When the device sees a special signal from the host port, it
+    latches the pass-through port so that devices further downstream
+    don't get confused by the pass-through device's conversation with
+    the host parallel port: the device connected to the pass-through
+    port (and any devices connected in turn to it) are effectively cut
+    off from the computer.  When the pass-through device has completed
+    its transaction with the computer, it enables the pass-through
+    port again.
+   </para>
+
+   <mediaobject>
+    <imageobject>
+     <imagedata fileref="parport-share.eps" format=ps>
+    </imageobject>
+    <imageobject>
+     <imagedata fileref="parport-share.jpeg" format=jpeg>
+    </imageobject>
+   </mediaobject>
+
+   <para>
+    This technique relies on certain <quote>special signals</quote>
+    being invisible to devices that aren't watching for them.  This
+    tends to mean only changing the data signals and leaving the
+    control signals alone.  IEEE 1284.3 documents a standard protocol
+    for daisy-chaining devices together with parallel ports.
+   </para>
+
+   <!-- transfer modes -->
+
+   <para>
+    Support for standard transfer modes are provided as operations
+    that can be performed on a port, along with operations for setting
+    the data lines, or the control lines, or reading the status lines.
+    These operations appear to the device driver as function pointers;
+    more later.
+   </para>
+
+  </sect1>
+
+ </chapter>
+
+ <chapter id="transfermodes">
+  <title>Standard transfer modes</title>
+
+  <!-- Defined by IEEE, but in common use (even though there are widely -->
+  <!-- varying implementations). -->
+
+  <para>
+   The <quote>standard</quote> transfer modes in use over the parallel
+   port are <quote>defined</quote> by a document called IEEE 1284.  It
+   really just codifies existing practice and documents protocols (and
+   variations on protocols) that have been in common use for quite
+   some time.
+  </para>
+
+  <para>
+   The original definitions of which pin did what were set out by
+   Centronics Data Computer Corporation, but only the printer-side
+   interface signals were specified.
+  </para>
+
+  <para>
+   By the early 1980s, IBM's host-side implementation had become the
+   most widely used.  New printers emerged that claimed Centronics
+   compatibility, but although compatible with Centronics they
+   differed from one another in a number of ways.
+  </para>
+
+  <para>
+   As a result of this, when IEEE 1284 was published in 1994, all that
+   it could really do was document the various protocols that are used
+   for printers (there are about six variations on a theme).
+  </para>
+
+  <para>
+   In addition to the protocol used to talk to Centronics-compatible
+   printers, IEEE 1284 defined other protocols that are used for
+   unidirectional peripheral-to-host transfers (reverse nibble and
+   reverse byte) and for fast bidirectional transfers (ECP and
+   EPP).
+  </para>
+
+ </chapter>
+
+ <chapter id="structure">
+  <title>Structure</title>
 
 <!-- Main structure
      - sharing core
@@ -251,240 +286,274 @@ EPP).</para>
      - IEEE 1284.3 API
   -->
 
-<!-- Diagram -->
-
-<mediaobject>
-<imageobject>
-<imagedata Align=Center ScaleFit=1 fileref="parport-structure.eps">
-</imageobject>
-</mediaobject>
-
-<sect1>
-<title>Sharing core</title>
-
-<!-- sharing core -->
-
-<para>At the core of the <filename>parport</filename> subsystem is the
-sharing mechanism (see <filename>drivers/parport/share.c</filename>).
-This module, <filename>parport</filename>, is responsible for
-keeping track of which ports there are in the system, which device
-drivers might be interested in new ports, and whether or not each port
-is available for use (or if not, which driver is currently using
-it).</para>
-
-</sect1>
-
-<sect1>
-<title>Parports and their overrides</title>
-<!-- parports and their overrides -->
-
-<para>The generic <filename>parport</filename> sharing code doesn't
-directly handle the parallel port hardware.  That is done instead by
-<quote>low-level</quote> <filename>parport</filename> drivers.  The
-function of a low-level <filename>parport</filename> driver is to
-detect parallel ports, register them with the sharing code, and
-provide a list of access functions for each port.</para>
-
-<para>The most basic access functions that must be provided are ones
-for examining the status lines, for setting the control lines, and for
-setting the data lines.  There are also access functions for setting
-the direction of the data lines; normally they are in the
-<quote>forward</quote> direction (that is, the computer drives them),
-but some ports allow switching to <quote>reverse</quote> mode (driven
-by the peripheral).  There is an access function for examining the
-data lines once in reverse mode.</para>
-
-</sect1>
-
-<sect1>
-<title>IEEE 1284 transfer modes</title>
-<!-- IEEE 1284 transfer modes -->
-
-<para>Stacked on top of the sharing mechanism, but still in the
-<filename>parport</filename> module, are functions for transferring
-data.  They are provided for the device drivers to use, and are very
-much like library routines.  Since these transfer functions are
-provided by the generic <filename>parport</filename> core they must
-use the <quote>lowest common denominator</quote> set of access
-functions: they can set the control lines, examine the status lines,
-and use the data lines.  With some parallel ports the data lines can
-only be set and not examined, and with other ports accessing the data
-register causes control line activity; with these types of situations,
-the IEEE 1284 transfer functions make a best effort attempt to do the
-right thing.  In some cases, it is not physically possible to use
-particular IEEE 1284 transfer modes.</para>
-
-<para>The low-level <filename>parport</filename> drivers also provide
-IEEE 1284 transfer functions, as names in the access function list.
-The low-level driver can just name the generic IEEE 1284 transfer
-functions for this.  Some parallel ports can do IEEE 1284 transfers in
-hardware; for those ports, the low-level driver can provide functions
-to utilise that feature.</para>
-
-</sect1>
-
-<!-- muxes? -->
-
-<!-- pardevices and pardrivers -->
-
-<sect1>
-<title>Pardevices and parport_drivers</title>
-
-<para>When a parallel port device driver (such as
-<filename>lp</filename>) initialises it tells the sharing layer about
-itself using <function>parport_register_driver</function>.  The
-information is put into a <structname>struct
-parport_driver</structname>, which is put into a linked list.  The
-information in a <structname>struct parport_driver</structname> really
-just amounts to some function pointers to callbacks in the parallel
-port device driver.</para>
-
-<para>During its initialisation, a low-level port driver tells the
-sharing layer about all the ports that it has found (using
-<function>parport_register_port</function>), and the sharing layer
-creates a <structname>struct parport</structname> for each of them.
-Each <structname>struct parport</structname> contains (among other
-things) a pointer to a <structname>struct
-parport_operations</structname>, which is a list of function pointers
-for the various operations that can be performed on a port.  You can
-think of a <structname>struct parport</structname> as a parallel port
-<quote>object</quote>, if <quote>object-orientated</quote> programming
-is your thing.  The <structname>parport</structname> structures are
-chained in a linked list, whose head is <varname>portlist</varname>
-(in <filename>drivers/parport/share.c</filename>).</para>
-
-<para>Once the port has been registered, the low-level port driver
-announces it.  The <function>parport_announce_port</function> function
-walks down the list of parallel port device drivers
-(<structname>struct parport_driver</structname>s) calling the
-<function>attach</function> function of each.</para>
-
-<para>Similarly, a low-level port driver can undo the effect of
-registering a port with the
-<function>parport_unregister_port</function> function, and device
-drivers are notified using the <function>detach</function>
-callback.</para>
-
-<para>Device drivers can undo the effect of registering themselves
-with the <function>parport_unregister_driver</function>
-function.</para>
-
-</sect1>
-
-<!-- IEEE 1284.3 API -->
-
-<sect1>
-<title>The IEEE 1284.3 API</title>
-
-<para>The ability to daisy-chain devices is very useful, but if every
-device does it in a different way it could lead to lots of
-complications for device driver writers.  Fortunately, the IEEE are
-standardising it in IEEE 1284.3, which covers daisy-chain devices and
-port multiplexors.</para>
-
-<para>At the time of writing, IEEE 1284.3 has not been published, but
-the draft specifies the on-the-wire protocol for daisy-chaining and
-multiplexing, and also suggests a programming interface for using it.
-That interface (or most of it) has been implemented in the
-<filename>parport</filename> code in Linux.</para>
-
-<para>At initialisation of the parallel port <quote>bus</quote>, daisy-chained
-devices are assigned addresses starting from zero.  There can only be
-four devices with daisy-chain addresses, plus one device on the end
-that doesn't know about daisy-chaining and thinks it's connected
-directly to a computer.</para>
-
-<para>Another way of connecting more parallel port devices is to use a
-multiplexor.  The idea is to have a device that is connected directly
-to a parallel port on a computer, but has a number of parallel ports
-on the other side for other peripherals to connect to (two or four
-ports are allowed).  The multiplexor switches control to different
-ports under software control---it is, in effect, a programmable
-printer switch.</para>
-
-<para>Combining the ability of daisy-chaining five devices together
-with the ability to multiplex one parallel port between four gives the
-potential to have twenty peripherals connected to the same parallel
-port!</para>
-
-<para>In addition, of course, a single computer can have multiple
-parallel ports.  So, each parallel port peripheral in the system can
-be identified with three numbers, or co-ordinates: the parallel port,
-the multiplexed port, and the daisy-chain address.</para>
-
-<mediaobject>
-<imageobject>
-<imagedata align=center scalefit=1 fileref="parport-multi.eps">
-</imageobject>
-</mediaobject>
-
-<!-- x parport_open -->
-<!-- x parport_close -->
-<!-- x parport_device_id -->
-<!-- x parport_device_num -->
-<!-- x parport_device_coords -->
-<!-- x parport_find_device -->
-<!-- x parport_find_class -->
-
-<para>Each device in the system is numbered at initialisation (by
-<function>parport_daisy_init</function>).  You can convert between
-this device number and its co-ordinates with
-<function>parport_device_num</function> and
-<function>parport_device_coords</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_device_num</function></funcdef>
-  <paramdef>int <parameter>parport</parameter></paramdef>
-  <paramdef>int <parameter>mux</parameter></paramdef>
-  <paramdef>int <parameter>daisy</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_device_coords</function></funcdef>
-  <paramdef>int <parameter>devnum</parameter></paramdef>
-  <paramdef>int *<parameter>parport</parameter></paramdef>
-  <paramdef>int *<parameter>mux</parameter></paramdef>
-  <paramdef>int *<parameter>daisy</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>Any parallel port peripheral will be connected directly or
-indirectly to a parallel port on the system, but it won't have a
-daisy-chain address if it does not know about daisy-chaining, and it
-won't be connected through a multiplexor port if there is no
-multiplexor.  The special co-ordinate value <constant>-1</constant> is
-used to indicate these cases.</para>
-
-<para>Two functions are provided for finding devices based on their
-IEEE 1284 Device ID: <function>parport_find_device</function> and
-<function>parport_find_class</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_find_device</function></funcdef>
-  <paramdef>const char *<parameter>mfg</parameter></paramdef>
-  <paramdef>const char *<parameter>mdl</parameter></paramdef>
-  <paramdef>int <parameter>from</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_find_class</function></funcdef>
-  <paramdef>parport_device_class <parameter>cls</parameter></paramdef>
-  <paramdef>int <parameter>from</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>These functions take a device number (in addition to some other
-things), and return another device number.  They walk through the list
-of detected devices until they find one that matches the requirements,
-and then return that device number (or <constant>-1</constant> if
-there are no more such devices).  They start their search at the
-device after the one in the list with the number given (at
-<parameter>from</parameter>+1, in other words).</para>
-
-</sect1>
-
-</chapter>
-
-<chapter id="drivers">
-<title>Device driver's view</title>
+  <mediaobject>
+   <imageobject>
+    <imagedata format=eps fileref="parport-structure.eps">
+   </imageobject>
+   <imageobject>
+    <imagedata format=jpeg fileref="parport-structure.jpeg">
+   </imageobject>
+  </mediaobject>
+
+  <sect1>
+   <title>Sharing core</title>
+
+   <para>
+    At the core of the <filename>parport</filename> subsystem is the
+    sharing mechanism (see
+    <filename>drivers/parport/share.c</filename>).  This module,
+    <filename>parport</filename>, is responsible for keeping track of
+    which ports there are in the system, which device drivers might be
+    interested in new ports, and whether or not each port is available
+    for use (or if not, which driver is currently using it).
+   </para>
+
+  </sect1>
+
+  <sect1>
+   <title>Parports and their overrides</title>
+
+   <para>
+    The generic <filename>parport</filename> sharing code doesn't
+    directly handle the parallel port hardware.  That is done instead
+    by <quote>low-level</quote> <filename>parport</filename> drivers.
+    The function of a low-level <filename>parport</filename> driver is
+    to detect parallel ports, register them with the sharing code, and
+    provide a list of access functions for each port.
+   </para>
+
+   <para>
+    The most basic access functions that must be provided are ones for
+    examining the status lines, for setting the control lines, and for
+    setting the data lines.  There are also access functions for
+    setting the direction of the data lines; normally they are in the
+    <quote>forward</quote> direction (that is, the computer drives
+    them), but some ports allow switching to <quote>reverse</quote>
+    mode (driven by the peripheral).  There is an access function for
+    examining the data lines once in reverse mode.
+   </para>
+
+  </sect1>
+
+  <sect1>
+   <title>IEEE 1284 transfer modes</title>
+
+   <para>
+    Stacked on top of the sharing mechanism, but still in the
+    <filename>parport</filename> module, are functions for
+    transferring data.  They are provided for the device drivers to
+    use, and are very much like library routines.  Since these
+    transfer functions are provided by the generic
+    <filename>parport</filename> core they must use the <quote>lowest
+    common denominator</quote> set of access functions: they can set
+    the control lines, examine the status lines, and use the data
+    lines.  With some parallel ports the data lines can only be set
+    and not examined, and with other ports accessing the data register
+    causes control line activity; with these types of situations, the
+    IEEE 1284 transfer functions make a best effort attempt to do the
+    right thing.  In some cases, it is not physically possible to use
+    particular IEEE 1284 transfer modes.
+   </para>
+
+   <para>
+    The low-level <filename>parport</filename> drivers also provide
+    IEEE 1284 transfer functions, as names in the access function
+    list.  The low-level driver can just name the generic IEEE 1284
+    transfer functions for this.  Some parallel ports can do IEEE 1284
+    transfers in hardware; for those ports, the low-level driver can
+    provide functions to utilise that feature.
+   </para>
+
+  </sect1>
+
+  <!-- muxes? -->
+
+  <sect1>
+   <title>Pardevices and parport_drivers</title>
+
+   <para>
+    When a parallel port device driver (such as
+    <filename>lp</filename>) initialises it tells the sharing layer
+    about itself using <function>parport_register_driver</function>.
+    The information is put into a <structname>struct
+    parport_driver</structname>, which is put into a linked list.  The
+    information in a <structname>struct parport_driver</structname>
+    really just amounts to some function pointers to callbacks in the
+    parallel port device driver.
+   </para>
+
+   <para>
+    During its initialisation, a low-level port driver tells the
+    sharing layer about all the ports that it has found (using
+    <function>parport_register_port</function>), and the sharing layer
+    creates a <structname>struct parport</structname> for each of
+    them.  Each <structname>struct parport</structname> contains
+    (among other things) a pointer to a <structname>struct
+    parport_operations</structname>, which is a list of function
+    pointers for the various operations that can be performed on a
+    port.  You can think of a <structname>struct parport</structname>
+    as a parallel port <quote>object</quote>, if
+    <quote>object-orientated</quote> programming is your thing.  The
+    <structname>parport</structname> structures are chained in a
+    linked list, whose head is <varname>portlist</varname> (in
+    <filename>drivers/parport/share.c</filename>).
+   </para>
+
+   <para>
+    Once the port has been registered, the low-level port driver
+    announces it.  The <function>parport_announce_port</function>
+    function walks down the list of parallel port device drivers
+    (<structname>struct parport_driver</structname>s) calling the
+    <function>attach</function> function of each.
+   </para>
+
+   <para>
+    Similarly, a low-level port driver can undo the effect of
+    registering a port with the
+    <function>parport_unregister_port</function> function, and device
+    drivers are notified using the <function>detach</function>
+    callback.
+   </para>
+
+   <para>
+    Device drivers can undo the effect of registering themselves with
+    the <function>parport_unregister_driver</function>
+    function.
+   </para>
+
+  </sect1>
+
+  <!-- IEEE 1284.3 API -->
+
+  <sect1>
+   <title>The IEEE 1284.3 API</title>
+
+   <para>
+    The ability to daisy-chain devices is very useful, but if every
+    device does it in a different way it could lead to lots of
+    complications for device driver writers.  Fortunately, the IEEE
+    are standardising it in IEEE 1284.3, which covers daisy-chain
+    devices and port multiplexors.
+   </para>
+
+   <para>
+    At the time of writing, IEEE 1284.3 has not been published, but
+    the draft specifies the on-the-wire protocol for daisy-chaining
+    and multiplexing, and also suggests a programming interface for
+    using it.  That interface (or most of it) has been implemented in
+    the <filename>parport</filename> code in Linux.
+   </para>
+
+   <para>
+    At initialisation of the parallel port <quote>bus</quote>,
+    daisy-chained devices are assigned addresses starting from zero.
+    There can only be four devices with daisy-chain addresses, plus
+    one device on the end that doesn't know about daisy-chaining and
+    thinks it's connected directly to a computer.
+   </para>
+
+   <para>
+    Another way of connecting more parallel port devices is to use a
+    multiplexor.  The idea is to have a device that is connected
+    directly to a parallel port on a computer, but has a number of
+    parallel ports on the other side for other peripherals to connect
+    to (two or four ports are allowed).  The multiplexor switches
+    control to different ports under software control---it is, in
+    effect, a programmable printer switch.
+   </para>
+
+   <para>
+    Combining the ability of daisy-chaining five devices together with
+    the ability to multiplex one parallel port between four gives the
+    potential to have twenty peripherals connected to the same
+    parallel port!
+   </para>
+
+   <para>
+    In addition, of course, a single computer can have multiple
+    parallel ports.  So, each parallel port peripheral in the system
+    can be identified with three numbers, or co-ordinates: the
+    parallel port, the multiplexed port, and the daisy-chain
+    address.
+   </para>
+
+   <mediaobject>
+    <imageobject>
+     <imagedata format=eps fileref="parport-multi.eps">
+    </imageobject>
+    <imageobject>
+     <imagedata format=jpeg fileref="parport-multi.jpeg">
+    </imageobject>
+   </mediaobject>
+
+   <para>
+    Each device in the system is numbered at initialisation (by
+    <function>parport_daisy_init</function>).  You can convert between
+    this device number and its co-ordinates with
+    <function>parport_device_num</function> and
+    <function>parport_device_coords</function>.
+   </para>
+
+   <funcsynopsis><funcprototype>
+     <funcdef>int <function>parport_device_num</function></funcdef>
+     <paramdef>int <parameter>parport</parameter></paramdef>
+     <paramdef>int <parameter>mux</parameter></paramdef>
+     <paramdef>int <parameter>daisy</parameter></paramdef>
+    </funcprototype></funcsynopsis>
+
+   <funcsynopsis><funcprototype>
+     <funcdef>int <function>parport_device_coords</function></funcdef>
+     <paramdef>int <parameter>devnum</parameter></paramdef>
+     <paramdef>int *<parameter>parport</parameter></paramdef>
+     <paramdef>int *<parameter>mux</parameter></paramdef>
+     <paramdef>int *<parameter>daisy</parameter></paramdef>
+    </funcprototype></funcsynopsis>
+
+   <para>
+    Any parallel port peripheral will be connected directly or
+    indirectly to a parallel port on the system, but it won't have a
+    daisy-chain address if it does not know about daisy-chaining, and
+    it won't be connected through a multiplexor port if there is no
+    multiplexor.  The special co-ordinate value
+    <constant>-1</constant> is used to indicate these cases.
+   </para>
+
+   <para>
+    Two functions are provided for finding devices based on their IEEE
+    1284 Device ID: <function>parport_find_device</function> and
+    <function>parport_find_class</function>.
+   </para>
+
+   <funcsynopsis><funcprototype>
+     <funcdef>int <function>parport_find_device</function></funcdef>
+     <paramdef>const char *<parameter>mfg</parameter></paramdef>
+     <paramdef>const char *<parameter>mdl</parameter></paramdef>
+     <paramdef>int <parameter>from</parameter></paramdef>
+    </funcprototype></funcsynopsis>
+
+   <funcsynopsis><funcprototype>
+     <funcdef>int <function>parport_find_class</function></funcdef>
+     <paramdef>parport_device_class <parameter>cls</parameter></paramdef>
+     <paramdef>int <parameter>from</parameter></paramdef>
+    </funcprototype></funcsynopsis>
+
+   <para>
+    These functions take a device number (in addition to some other
+    things), and return another device number.  They walk through the
+    list of detected devices until they find one that matches the
+    requirements, and then return that device number (or
+    <constant>-1</constant> if there are no more such devices).  They
+    start their search at the device after the one in the list with
+    the number given (at <parameter>from</parameter>+1, in other
+    words).
+   </para>
+
+  </sect1>
+
+ </chapter>
+
+ <chapter id="drivers">
+  <title>Device driver's view</title>
 
 <!-- Cover:
      - sharing interface, preemption, interrupts, wakeups...
@@ -499,525 +568,620 @@ device after the one in the list with the number given (at
 <!-- driver' should deal with that later; might be worth mentioning -->
 <!-- in the text. -->
 
-<para>This section is written from the point of view of the device
-driver programmer, who might be writing a driver for a printer or a
-scanner or else anything that plugs into the parallel port.  It
-explains how to use the <filename>parport</filename> interface to find
-parallel ports, use them, and share them with other device
-drivers.</para>
-
-<para>We'll start out with a description of the various functions that
-can be called, and then look at a reasonably simple example of their
-use: the printer driver.</para>
-
-<para>The interactions between the device driver and the
-<filename>parport</filename> layer are as follows.  First, the device
-driver registers its existence with <filename>parport</filename>, in
-order to get told about any parallel ports that have been (or will be)
-detected.  When it gets told about a parallel port, it then tells
-<filename>parport</filename> that it wants to drive a device on that
-port.  Thereafter it can claim exclusive access to the port in order
-to talk to its device.</para>
-
-<para>So, the first thing for the device driver to do is tell
-<filename>parport</filename> that it wants to know what parallel ports
-are on the system.  To do this, it uses the
-<function>parport_register_device</function> function:</para>
-
-<programlisting>
-<![CDATA[
+  <para>
+   This section is written from the point of view of the device driver
+   programmer, who might be writing a driver for a printer or a
+   scanner or else anything that plugs into the parallel port.  It
+   explains how to use the <filename>parport</filename> interface to
+   find parallel ports, use them, and share them with other device
+   drivers.
+  </para>
+
+  <para>
+   We'll start out with a description of the various functions that
+   can be called, and then look at a reasonably simple example of
+   their use: the printer driver.
+  </para>
+
+  <para>
+   The interactions between the device driver and the
+   <filename>parport</filename> layer are as follows.  First, the
+   device driver registers its existence with
+   <filename>parport</filename>, in order to get told about any
+   parallel ports that have been (or will be) detected.  When it gets
+   told about a parallel port, it then tells
+   <filename>parport</filename> that it wants to drive a device on
+   that port.  Thereafter it can claim exclusive access to the port in
+   order to talk to its device.
+  </para>
+
+  <para>
+   So, the first thing for the device driver to do is tell
+   <filename>parport</filename> that it wants to know what parallel
+   ports are on the system.  To do this, it uses the
+   <function>parport_register_device</function> function:
+  </para>
+
+  <programlisting>
+   <![CDATA[
 struct parport_driver {
         const char *name;
         void (*attach) (struct parport *);
         void (*detach) (struct parport *);
         struct parport_driver *next;
 };
-]]></programlisting>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_register_driver</function></funcdef>
-  <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>In other words, the device driver passes pointers to a couple of
-functions to <filename>parport</filename>, and
-<filename>parport</filename> calls <function>attach</function> for
-each port that's detected (and <function>detach</function> for each
-port that disappears -- yes, this can happen).</para>
-
-<para>The next thing that happens is that the device driver tells
-<filename>parport</filename> that it thinks there's a device on the
-port that it can drive.  This typically will happen in the driver's
-<function>attach</function> function, and is done with
-<function>parport_register_device</function>:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const char *<parameter>name</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>void <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>void <parameter>(*irq_func)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The <parameter>port</parameter> comes from the parameter supplied
-to the <function>attach</function> function when it is called, or
-alternatively can be found from the list of detected parallel ports
-directly with the (now deprecated)
-<function>parport_enumerate</function> function.</para>
-
-<para>The next three parameters, <parameter>pf</parameter>,
-<parameter>kf</parameter>, and <parameter>irq_func</parameter>, are
-more function pointers.  These callback functions get called under
-various circumstances, and are always given the
-<parameter>handle</parameter> as one of their parameters.</para>
-
-<para>The preemption callback, <parameter>pf</parameter>, is called
-when the driver has claimed access to the port but another device
-driver wants access.  If the driver is willing to let the port go, it
-should return zero and the port will be released on its behalf.  There
-is no need to call <function>parport_release</function>.  If
-<parameter>pf</parameter> gets called at a bad time for letting the
-port go, it should return non-zero and no action will be taken.  It is
-good manners for the driver to try to release the port at the earliest
-opportunity after its preemption callback is called.</para>
-
-<para>The <quote>kick</quote> callback, <parameter>kf</parameter>, is
-called when the port can be claimed for exclusive access; that is,
-<function>parport_claim</function> is guaranteed to succeed inside the
-<quote>kick</quote> callback.  If the driver wants to claim the port
-it should do so; otherwise, it need not take any action.</para>
-
-<para>The <parameter>irq_func</parameter> callback is called,
-predictably, when a parallel port interrupt is generated.  But it is
-not the only code that hooks on the interrupt.  The sequence is this:
-the lowlevel driver is the one that has done
-<function>request_irq</function>; it then does whatever
-hardware-specific things it needs to do to the parallel port hardware
-(for PC-style ports, there is nothing special to do); it then tells
-the IEEE 1284 code about the interrupt, which may involve reacting to
-an IEEE 1284 event, depending on the current IEEE 1284 phase; and
-finally the <parameter>irq_func</parameter> function is called.</para>
-
-<para>None of the callback functions are allowed to block.</para>
-
-<para>The <parameter>flags</parameter> are for telling
-<filename>parport</filename> any requirements or hints that are
-useful.  The only useful value here (other than
-<constant>0</constant>, which is the usual value) is
-<constant>PARPORT_DEV_EXCL</constant>.  The point of that flag is to
-request exclusive access at all times---once a driver has successfully
-called <function>parport_register_device</function> with that flag, no
-other device drivers will be able to register devices on that port
-(until the successful driver deregisters its device, of
-course).</para>
-
-<para>The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing
-port sharing, and so should only be used when sharing the port with
-other device drivers is impossible and would lead to incorrect
-behaviour.  Use it sparingly!</para>
-
-<para>Devices can also be registered by device drivers based on their
-device numbers (the same device numbers as in the previous
-section).</para>
-
-<para>The <function>parport_open</function> function is similar to
-<function>parport_register_device</function>, and
-<function>parport_close</function> is the equivalent of
-<function>parport_unregister_device</function>.  The difference is
-that <function>parport_open</function> takes a device number rather
-than a pointer to a <structname>struct parport</structname>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_open</function></funcdef>
-  <paramdef>int <parameter>devnum</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*irqf)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_close</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const char *<parameter>name</parameter></paramdef>
-  <paramdef>int <parameter>(*pf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*kf)</parameter>
-    <funcparams>void *</funcparams></paramdef>
-  <paramdef>int <parameter>(*irqf)</parameter>
-    <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
-  <paramdef>int <parameter>flags</parameter></paramdef>
-  <paramdef>void *<parameter>handle</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_unregister_device</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The intended use of these functions is during driver
-initialisation while the driver looks for devices that it supports, as
-demonstrated by the following code fragment:</para>
-
-<programlisting>
-<![CDATA[
+   ]]></programlisting>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_register_driver</function></funcdef>
+    <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   In other words, the device driver passes pointers to a couple of
+   functions to <filename>parport</filename>, and
+   <filename>parport</filename> calls <function>attach</function> for
+   each port that's detected (and <function>detach</function> for each
+   port that disappears---yes, this can happen).
+  </para>
+
+  <para>
+   The next thing that happens is that the device driver tells
+   <filename>parport</filename> that it thinks there's a device on the
+   port that it can drive.  This typically will happen in the driver's
+   <function>attach</function> function, and is done with
+   <function>parport_register_device</function>:
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
+    <paramdef>struct parport *<parameter>port</parameter></paramdef>
+    <paramdef>const char *<parameter>name</parameter></paramdef>
+    <paramdef>int <parameter>(*pf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>void <parameter>(*kf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>void <parameter>(*irq_func)</parameter>
+     <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+    <paramdef>int <parameter>flags</parameter></paramdef>
+    <paramdef>void *<parameter>handle</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   The <parameter>port</parameter> comes from the parameter supplied
+   to the <function>attach</function> function when it is called, or
+   alternatively can be found from the list of detected parallel ports
+   directly with the (now deprecated)
+   <function>parport_enumerate</function> function.
+  </para>
+
+  <para>
+   The next three parameters, <parameter>pf</parameter>,
+   <parameter>kf</parameter>, and <parameter>irq_func</parameter>, are
+   more function pointers.  These callback functions get called under
+   various circumstances, and are always given the
+   <parameter>handle</parameter> as one of their parameters.
+  </para>
+
+  <para>
+   The preemption callback, <parameter>pf</parameter>, is called when
+   the driver has claimed access to the port but another device driver
+   wants access.  If the driver is willing to let the port go, it
+   should return zero and the port will be released on its behalf.
+   There is no need to call <function>parport_release</function>.  If
+   <parameter>pf</parameter> gets called at a bad time for letting the
+   port go, it should return non-zero and no action will be taken.  It
+   is good manners for the driver to try to release the port at the
+   earliest opportunity after its preemption callback is
+   called.
+  </para>
+
+  <para>
+   The <quote>kick</quote> callback, <parameter>kf</parameter>, is
+   called when the port can be claimed for exclusive access; that is,
+   <function>parport_claim</function> is guaranteed to succeed inside
+   the <quote>kick</quote> callback.  If the driver wants to claim the
+   port it should do so; otherwise, it need not take any
+   action.
+  </para>
+
+  <para>
+   The <parameter>irq_func</parameter> callback is called,
+   predictably, when a parallel port interrupt is generated.  But it
+   is not the only code that hooks on the interrupt.  The sequence is
+   this: the lowlevel driver is the one that has done
+   <function>request_irq</function>; it then does whatever
+   hardware-specific things it needs to do to the parallel port
+   hardware (for PC-style ports, there is nothing special to do); it
+   then tells the IEEE 1284 code about the interrupt, which may
+   involve reacting to an IEEE 1284 event, depending on the current
+   IEEE 1284 phase; and finally the <parameter>irq_func</parameter>
+   function is called.
+  </para>
+
+  <para>
+   None of the callback functions are allowed to block.
+  </para>
+
+  <para>
+   The <parameter>flags</parameter> are for telling
+   <filename>parport</filename> any requirements or hints that are
+   useful.  The only useful value here (other than
+   <constant>0</constant>, which is the usual value) is
+   <constant>PARPORT_DEV_EXCL</constant>.  The point of that flag is
+   to request exclusive access at all times---once a driver has
+   successfully called <function>parport_register_device</function>
+   with that flag, no other device drivers will be able to register
+   devices on that port (until the successful driver deregisters its
+   device, of course).
+  </para>
+
+  <para>
+   The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing
+   port sharing, and so should only be used when sharing the port with
+   other device drivers is impossible and would lead to incorrect
+   behaviour.  Use it sparingly!
+  </para>
+
+  <para>
+   Devices can also be registered by device drivers based on their
+   device numbers (the same device numbers as in the previous
+   section).
+  </para>
+
+  <para>
+   The <function>parport_open</function> function is similar to
+   <function>parport_register_device</function>, and
+   <function>parport_close</function> is the equivalent of
+   <function>parport_unregister_device</function>.  The difference is
+   that <function>parport_open</function> takes a device number rather
+   than a pointer to a <structname>struct parport</structname>.
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>struct pardevice *<function>parport_open</function></funcdef>
+    <paramdef>int <parameter>devnum</parameter></paramdef>
+    <paramdef>int <parameter>(*pf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>int <parameter>(*kf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>int <parameter>(*irqf)</parameter>
+     <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+    <paramdef>int <parameter>flags</parameter></paramdef>
+    <paramdef>void *<parameter>handle</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>void <function>parport_close</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
+    <paramdef>struct parport *<parameter>port</parameter></paramdef>
+    <paramdef>const char *<parameter>name</parameter></paramdef>
+    <paramdef>int <parameter>(*pf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>int <parameter>(*kf)</parameter>
+     <funcparams>void *</funcparams></paramdef>
+    <paramdef>int <parameter>(*irqf)</parameter>
+     <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
+    <paramdef>int <parameter>flags</parameter></paramdef>
+    <paramdef>void *<parameter>handle</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>void <function>parport_unregister_device</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   The intended use of these functions is during driver initialisation
+   while the driver looks for devices that it supports, as
+   demonstrated by the following code fragment:
+  </para>
+
+  <programlisting>
+   <![CDATA[
 int devnum = -1;
 while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
                                      devnum)) != -1) {
     struct pardevice *dev = parport_open (devnum, ...);
     ...
 }
-]]></programlisting>
-
-<para>Once your device driver has registered its device and been
-handed a pointer to a <structname>struct pardevice</structname>, the
-next thing you are likely to want to do is communicate with the device
-you think is there.  To do that you'll need to claim access to the
-port.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_claim</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_claim_or_block</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>void <function>parport_release</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>To claim access to the port, use
-<function>parport_claim</function> or
-<function>parport_claim_or_block</function>.  The first of these will
-not block, and so can be used from interrupt context.  If
-<function>parport_claim</function> succeeds it will return zero and
-the port is available to use.  It may fail (returning non-zero) if the
-port is in use by another driver and that driver is not willing to
-relinquish control of the port.</para>
-
-<para>The other function, <function>parport_claim_or_block</function>,
-will block if necessary to wait for the port to be free.  If it slept,
-it returns <constant>1</constant>; if it succeeded without needing to
-sleep it returns <constant>0</constant>.  If it fails it will return a
-negative error code.</para>
-
-<para>When you have finished communicating with the device, you can
-give up access to the port so that other drivers can communicate with
-their devices.  The <function>parport_release</function> function
-cannot fail, but it should not be called without the port claimed.
-Similarly, you should not try to claim the port if you already have it
-claimed.</para>
-
-<para>You may find that although there are convenient points for your
-driver to relinquish the parallel port and allow other drivers to talk
-to their devices, it would be preferable to keep hold of the port.
-The printer driver only needs the port when there is data to print,
-for example, but a network driver (such as PLIP) could be sent a
-remote packet at any time.  With PLIP, it is no huge catastrophe if a
-network packet is dropped, since it will likely be sent again, so it
-is possible for that kind of driver to share the port with other
-(pass-through) devices.</para>
-
-<para>The <function>parport_yield</function> and
-<function>parport_yield_blocking</function> functions are for marking
-points in the driver at which other drivers may claim the port and use
-their devices.  Yielding the port is similar to releasing it and
-reclaiming it, but it more efficient because nothing is done if there
-are no other devices needing the port.  In fact, nothing is done even
-if there are other devices waiting but the current device is still
-within its <quote>timeslice</quote>.  The default timeslice is half a
-second, but it can be adjusted via a <filename>/proc</filename>
-entry.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_yield</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_yield_blocking</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The first of these, <function>parport_yield</function>, will not
-block but as a result may fail.  The return value for
-<function>parport_yield</function> is the same as for
-<function>parport_claim</function>.  The blocking version,
-<function>parport_yield_blocking</function>, has the same return code
-as <function>parport_claim_or_block</function>.</para>
-
-<para>Once the port has been claimed, the device driver can use the
-functions in the <structname>struct parport_operations</structname>
-pointer in the <structname>struct parport</structname> it has a
-pointer to.  For example:</para>
-
-<programlisting>
-<![CDATA[
+   ]]></programlisting>
+
+  <para>
+   Once your device driver has registered its device and been handed a
+   pointer to a <structname>struct pardevice</structname>, the next
+   thing you are likely to want to do is communicate with the device
+   you think is there.  To do that you'll need to claim access to the
+   port.
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_claim</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_claim_or_block</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>void <function>parport_release</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   To claim access to the port, use <function>parport_claim</function>
+   or <function>parport_claim_or_block</function>.  The first of these
+   will not block, and so can be used from interrupt context.  If
+   <function>parport_claim</function> succeeds it will return zero and
+   the port is available to use.  It may fail (returning non-zero) if
+   the port is in use by another driver and that driver is not willing
+   to relinquish control of the port.
+  </para>
+
+  <para>
+   The other function, <function>parport_claim_or_block</function>,
+   will block if necessary to wait for the port to be free.  If it
+   slept, it returns <constant>1</constant>; if it succeeded without
+   needing to sleep it returns <constant>0</constant>.  If it fails it
+   will return a negative error code.
+  </para>
+
+  <para>
+   When you have finished communicating with the device, you can give
+   up access to the port so that other drivers can communicate with
+   their devices.  The <function>parport_release</function> function
+   cannot fail, but it should not be called without the port claimed.
+   Similarly, you should not try to claim the port if you already have
+   it claimed.
+  </para>
+
+  <para>
+   You may find that although there are convenient points for your
+   driver to relinquish the parallel port and allow other drivers to
+   talk to their devices, it would be preferable to keep hold of the
+   port.  The printer driver only needs the port when there is data to
+   print, for example, but a network driver (such as PLIP) could be
+   sent a remote packet at any time.  With PLIP, it is no huge
+   catastrophe if a network packet is dropped, since it will likely be
+   sent again, so it is possible for that kind of driver to share the
+   port with other (pass-through) devices.
+  </para>
+
+  <para>
+   The <function>parport_yield</function> and
+   <function>parport_yield_blocking</function> functions are for
+   marking points in the driver at which other drivers may claim the
+   port and use their devices.  Yielding the port is similar to
+   releasing it and reclaiming it, but is more efficient because
+   nothing is done if there are no other devices needing the port.  In
+   fact, nothing is done even if there are other devices waiting but
+   the current device is still within its <quote>timeslice</quote>.
+   The default timeslice is half a second, but it can be adjusted via
+   a <filename>/proc</filename> entry.
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_yield</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_yield_blocking</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   The first of these, <function>parport_yield</function>, will not
+   block but as a result may fail.  The return value for
+   <function>parport_yield</function> is the same as for
+   <function>parport_claim</function>.  The blocking version,
+   <function>parport_yield_blocking</function>, has the same return
+   code as <function>parport_claim_or_block</function>.
+  </para>
+
+  <para>
+   Once the port has been claimed, the device driver can use the
+   functions in the <structname>struct parport_operations</structname>
+   pointer in the <structname>struct parport</structname> it has a
+   pointer to.  For example:
+  </para>
+
+  <programlisting>
+   <![CDATA[
 port->ops->write_data (port, d);
-]]></programlisting>
-
-<para>Some of these operations have <quote>shortcuts</quote>.  For
-instance, <function>parport_write_data</function> is equivalent to the
-above, but may be a little bit faster (it's a macro that in some cases
-can avoid needing to indirect through <varname>port</varname> and
-<varname>ops</varname>).</para>
-
-</chapter>
-
-<chapter id="portdrivers">
-<title>Port drivers</title>
-
-<!-- What port drivers are for (i.e. implementing parport objects). -->
-
-<para>To recap, then:</para>
-
-<itemizedlist spacing=compact>
-
-<listitem>
-<para>
-The device driver registers itself with <filename>parport</filename>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-A low-level driver finds a parallel port and registers it with
-<filename>parport</filename> (these first two things can happen in
-either order).  This registration creates a <structname>struct
-parport</structname> which is linked onto a list of known ports.
-</para>
-</listitem>
-
-<listitem>
-<para>
-<filename>parport</filename> calls the <function>attach</function>
-function of each registered device driver, passing it the pointer to
-the new <structname>struct parport</structname>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-The device driver gets a handle from <filename>parport</filename>, for
-use with
-<function>parport_claim</function>/<function>release</function>.  This
-handle takes the form of a pointer to a <structname>struct
-pardevice</structname>, representing a particular device on the
-parallel port, and is acquired using
-<function>parport_register_device</function>.
-</para>
-</listitem>
-
-<listitem>
-<para>
-The device driver claims the port using
-<function>parport_claim</function> (or
-<function>function_claim_or_block</function>).
-</para>
-</listitem>
-
-<listitem>
-<para>
-Then it goes ahead and uses the port.  When finished it releases the
-port.
-</para>
-</listitem>
-
-</itemizedlist>
-
-<para>The purpose of the low-level drivers, then, is to detect
-parallel ports and provide methods of accessing them
-(i.e. implementing the operations in <structname>struct
-parport_operations</structname>).</para>
-
-<!-- Interaction with sharing engine; port state -->
-<!-- What did I mean by that? -->
-
-<!-- Talk about parport_pc implementation, and contrast with e.g. amiga -->
-
-<para>A more complete description of which operation is supposed to do
-what is available in
-<filename>Documentation/parport-lowlevel.txt</filename>.</para>
-
-</chapter>
-
-<chapter id="lp">
-<title>The printer driver</title>
-
-<!-- Talk the reader through the printer driver. -->
-<!-- Could even talk about parallel port console here. -->
-
-<para>The printer driver, <filename>lp</filename> is a character
-special device driver and a <filename>parport</filename> client.  As a
-character special device driver it registers a <structname>struct
-file_operations</structname> using
-<function>register_chrdev</function>, with pointers filled in for
-<structfield>write</structfield>, <structfield>ioctl</structfield>,
-<structfield>open</structfield> and
-<structfield>release</structfield>.  As a client of
-<filename>parport</filename>, it registers a <structname>struct
-parport_driver</structname> using
-<function>parport_register_driver</function>, so that
-<filename>parport</filename> knows to call
-<function>lp_attach</function> when a new parallel port is discovered
-(and <function>lp_detach</function> when it goes away).</para>
-
-<para>The parallel port console functionality is also implemented in
-<filename>lp.c</filename>, but that won't be covered here (it's quite
-simple though).</para>
-
-<para>The initialisation of the driver is quite easy to understand
-(see <function>lp_init</function>).  The <varname>lp_table</varname>
-is an array of structures that contain information about a specific
-device (the <structname>struct pardevice</structname> associated with
-it, for example).  That array is initialised to sensible values first
-of all.</para>
-
-<para>Next, the printer driver calls
-<function>register_chrdev</function> passing it a pointer to
-<varname>lp_fops</varname>, which contains function pointers for the
-printer driver's implementation of <function>open</function>,
-<function>write</function>, and so on.  This part is the same as for
-any character special device driver.</para>
-
-<para>After successfully registering itself as a character special
-device driver, the printer driver registers itself as a
-<filename>parport</filename> client using
-<function>parport_register_driver</function>.  It passes a pointer to
-this structure:</para>
-
-<programlisting>
-<![CDATA[
+   ]]></programlisting>
+
+  <para>
+   Some of these operations have <quote>shortcuts</quote>.  For
+   instance, <function>parport_write_data</function> is equivalent to
+   the above, but may be a little bit faster (it's a macro that in
+   some cases can avoid needing to indirect through
+   <varname>port</varname> and <varname>ops</varname>).
+  </para>
+
+ </chapter>
+
+ <chapter id="portdrivers">
+  <title>Port drivers</title>
+
+  <!-- What port drivers are for (i.e. implementing parport objects). -->
+
+  <para>
+   To recap, then:</para>
+
+  <itemizedlist spacing=compact>
+
+   <listitem>
+    <para>
+     The device driver registers itself with <filename>parport</filename>.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+     A low-level driver finds a parallel port and registers it with
+     <filename>parport</filename> (these first two things can happen
+     in either order).  This registration creates a <structname>struct
+     parport</structname> which is linked onto a list of known ports.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+     <filename>parport</filename> calls the
+     <function>attach</function> function of each registered device
+     driver, passing it the pointer to the new <structname>struct
+     parport</structname>.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+     The device driver gets a handle from
+     <filename>parport</filename>, for use with
+     <function>parport_claim</function>/<function>release</function>.
+     This handle takes the form of a pointer to a <structname>struct
+     pardevice</structname>, representing a particular device on the
+     parallel port, and is acquired using
+     <function>parport_register_device</function>.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+     The device driver claims the port using
+     <function>parport_claim</function> (or
+     <function>function_claim_or_block</function>).
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+     Then it goes ahead and uses the port.  When finished it releases
+     the port.
+    </para>
+   </listitem>
+
+  </itemizedlist>
+
+  <para>
+   The purpose of the low-level drivers, then, is to detect parallel
+   ports and provide methods of accessing them (i.e. implementing the
+   operations in <structname>struct
+   parport_operations</structname>).
+  </para>
+
+  <!-- Should DocBookise this -->
+  <para>
+   A more complete description of which operation is supposed to do
+   what is available in
+   <filename>Documentation/parport-lowlevel.txt</filename>.
+  </para>
+
+ </chapter>
+
+ <chapter id="lp">
+  <title>The printer driver</title>
+
+  <!-- Talk the reader through the printer driver. -->
+  <!-- Could even talk about parallel port console here. -->
+
+  <para>
+   The printer driver, <filename>lp</filename> is a character special
+   device driver and a <filename>parport</filename> client.  As a
+   character special device driver it registers a <structname>struct
+   file_operations</structname> using
+   <function>register_chrdev</function>, with pointers filled in for
+   <structfield>write</structfield>, <structfield>ioctl</structfield>,
+   <structfield>open</structfield> and
+   <structfield>release</structfield>.  As a client of
+   <filename>parport</filename>, it registers a <structname>struct
+   parport_driver</structname> using
+   <function>parport_register_driver</function>, so that
+   <filename>parport</filename> knows to call
+   <function>lp_attach</function> when a new parallel port is
+   discovered (and <function>lp_detach</function> when it goes
+   away).
+  </para>
+
+  <para>
+   The parallel port console functionality is also implemented in
+   <filename>lp.c</filename>, but that won't be covered here (it's
+   quite simple though).
+  </para>
+
+  <para>
+   The initialisation of the driver is quite easy to understand (see
+   <function>lp_init</function>).  The <varname>lp_table</varname> is
+   an array of structures that contain information about a specific
+   device (the <structname>struct pardevice</structname> associated
+   with it, for example).  That array is initialised to sensible
+   values first of all.
+  </para>
+
+  <para>
+   Next, the printer driver calls <function>register_chrdev</function>
+   passing it a pointer to <varname>lp_fops</varname>, which contains
+   function pointers for the printer driver's implementation of
+   <function>open</function>, <function>write</function>, and so on.
+   This part is the same as for any character special device
+   driver.
+  </para>
+
+  <para>
+   After successfully registering itself as a character special device
+   driver, the printer driver registers itself as a
+   <filename>parport</filename> client using
+   <function>parport_register_driver</function>.  It passes a pointer
+   to this structure:
+  </para>
+
+  <programlisting>
+   <![CDATA[
 static struct parport_driver lp_driver = {
         "lp",
         lp_attach,
         lp_detach,
         NULL
 };
-]]></programlisting>
-
-<para>The <function>lp_detach</function> function is not very
-interesting (it does nothing); the interesting bit is
-<function>lp_attach</function>.  What goes on here depends on whether
-the user supplied any parameters.  The possibilities are: no
-parameters supplied, in which case the printer driver uses every port
-that is detected; the user supplied the parameter <quote>auto</quote>,
-in which case only ports on which the device ID string indicates a
-printer is present are used; or the user supplied a list of parallel
-port numbers to try, in which case only those are used.</para>
-
-<para>For each port that the printer driver wants to use (see
-<function>lp_register</function>), it calls
-<function>parport_register_device</function> and stores the resulting
-<structname>struct pardevice</structname> pointer in the
-<varname>lp_table</varname>.  If the user told it to do so, it then
-resets the printer.</para>
-
-<para>The other interesting piece of the printer driver, from the
-point of view of <filename>parport</filename>, is
-<function>lp_write</function>.  In this function, the user space
-process has data that it wants printed, and the printer driver hands
-it off to the <filename>parport</filename> code to deal with.</para>
-
-<para>The <filename>parport</filename> functions it uses that we have
-not seen yet are <function>parport_negotiate</function>,
-<function>parport_set_timeout</function>, and
-<function>parport_write</function>.  These functions are part of the
-IEEE 1284 implementation.</para>
-
-<para>The way the IEEE 1284 protocol works is that the host tells the
-peripheral what transfer mode it would like to use, and the peripheral
-either accepts that mode or rejects it; if the mode is rejected, the
-host can try again with a different mode.  This is the negotation
-phase.  Once the peripheral has accepted a particular transfer mode,
-data transfer can begin that mode.</para>
-
-<para>The particular transfer mode that the printer driver wants to
-use is named in IEEE 1284 as <quote>compatibility</quote> mode, and
-the function to request a particular mode is called
-<function>parport_negotiate</function>.</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>int <function>parport_negotiate</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>int <parameter>mode</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>The <parameter>modes</parameter> parameter is a symbolic
-constant representing an IEEE 1284 mode; in this instance, it is
-<constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is
-slightly different to the other modes---rather than being specifically
-requested, it is the default until another mode is selected.)</para>
-
-<para>Back to <function>lp_write</function> then.  First, access to
-the parallel port is secured with
-<function>parport_claim_or_block</function>.  At this point the driver
-might sleep, waiting for another driver (perhaps a Zip drive driver,
-for instance) to let the port go.  Next, it goes to compatibility mode
-using <function>parport_negotiate</function>.</para>
-
-<para>The main work is done in the write-loop.  In particular, the
-line that hands the data over to <filename>parport</filename>
-reads:</para>
+   ]]></programlisting>
+
+  <para>
+   The <function>lp_detach</function> function is not very interesting
+   (it does nothing); the interesting bit is
+   <function>lp_attach</function>.  What goes on here depends on
+   whether the user supplied any parameters.  The possibilities are:
+   no parameters supplied, in which case the printer driver uses every
+   port that is detected; the user supplied the parameter
+   <quote>auto</quote>, in which case only ports on which the device
+   ID string indicates a printer is present are used; or the user
+   supplied a list of parallel port numbers to try, in which case only
+   those are used.
+  </para>
+
+  <para>
+   For each port that the printer driver wants to use (see
+   <function>lp_register</function>), it calls
+   <function>parport_register_device</function> and stores the
+   resulting <structname>struct pardevice</structname> pointer in the
+   <varname>lp_table</varname>.  If the user told it to do so, it then
+   resets the printer.
+  </para>
+
+  <para>
+   The other interesting piece of the printer driver, from the point
+   of view of <filename>parport</filename>, is
+   <function>lp_write</function>.  In this function, the user space
+   process has data that it wants printed, and the printer driver
+   hands it off to the <filename>parport</filename> code to deal with.
+  </para>
+
+  <para>
+   The <filename>parport</filename> functions it uses that we have not
+   seen yet are <function>parport_negotiate</function>,
+   <function>parport_set_timeout</function>, and
+   <function>parport_write</function>.  These functions are part of
+   the IEEE 1284 implementation.
+  </para>
+
+  <para>
+   The way the IEEE 1284 protocol works is that the host tells the
+   peripheral what transfer mode it would like to use, and the
+   peripheral either accepts that mode or rejects it; if the mode is
+   rejected, the host can try again with a different mode.  This is
+   the negotation phase.  Once the peripheral has accepted a
+   particular transfer mode, data transfer can begin that mode.
+  </para>
+
+  <para>
+   The particular transfer mode that the printer driver wants to use
+   is named in IEEE 1284 as <quote>compatibility</quote> mode, and the
+   function to request a particular mode is called
+   <function>parport_negotiate</function>.
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>int <function>parport_negotiate</function></funcdef>
+    <paramdef>struct parport *<parameter>port</parameter></paramdef>
+    <paramdef>int <parameter>mode</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   The <parameter>modes</parameter> parameter is a symbolic constant
+   representing an IEEE 1284 mode; in this instance, it is
+   <constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is
+   slightly different to the other modes---rather than being
+   specifically requested, it is the default until another mode is
+   selected.)
+  </para>
+
+  <para>
+   Back to <function>lp_write</function> then.  First, access to the
+   parallel port is secured with
+   <function>parport_claim_or_block</function>.  At this point the
+   driver might sleep, waiting for another driver (perhaps a Zip drive
+   driver, for instance) to let the port go.  Next, it goes to
+   compatibility mode using <function>parport_negotiate</function>.
+  </para>
+
+  <para>
+   The main work is done in the write-loop.  In particular, the line
+   that hands the data over to <filename>parport</filename> reads:
+  </para>
 
 <programlisting>
 <![CDATA[
         written = parport_write (port, kbuf, copy_size);
 ]]></programlisting>
 
-<para>The <function>parport_write</function> function writes data to
-the peripheral using the currently selected transfer mode
-(compatibility mode, in this case).  It returns the number of bytes
-successfully written:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>ssize_t <function>parport_write</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>const void *<parameter>buf</parameter></paramdef>
-  <paramdef>size_t <parameter>len</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<funcsynopsis><funcprototype>
-  <funcdef>ssize_t <function>parport_read</function></funcdef>
-  <paramdef>struct parport *<parameter>port</parameter></paramdef>
-  <paramdef>void *<parameter>buf</parameter></paramdef>
-  <paramdef>size_t <parameter>len</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>(<function>parport_read</function> does what it sounds like, but
-only works for modes in which reverse transfer is possible.  Of
-course, <function>parport_write</function> only works in modes in
-which forward transfer is possible, too.)</para>
-
-<para>The <parameter>buf</parameter> pointer should be to kernel space
-memory, and obviously the <parameter>len</parameter> parameter
-specifies the amount of data to transfer.</para>
-
-<para>In fact what <function>parport_write</function> does is call the
-appropriate block transfer function from the <structname>struct
-parport_operations</structname>:</para>
-
-<programlisting>
-<![CDATA[
+  <para>
+   The <function>parport_write</function> function writes data to the
+   peripheral using the currently selected transfer mode
+   (compatibility mode, in this case).  It returns the number of bytes
+   successfully written:
+  </para>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>ssize_t <function>parport_write</function></funcdef>
+    <paramdef>struct parport *<parameter>port</parameter></paramdef>
+    <paramdef>const void *<parameter>buf</parameter></paramdef>
+    <paramdef>size_t <parameter>len</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <funcsynopsis><funcprototype>
+    <funcdef>ssize_t <function>parport_read</function></funcdef>
+    <paramdef>struct parport *<parameter>port</parameter></paramdef>
+    <paramdef>void *<parameter>buf</parameter></paramdef>
+    <paramdef>size_t <parameter>len</parameter></paramdef>
+   </funcprototype></funcsynopsis>
+
+  <para>
+   (<function>parport_read</function> does what it sounds like, but
+   only works for modes in which reverse transfer is possible.  Of
+   course, <function>parport_write</function> only works in modes in
+   which forward transfer is possible, too.)
+  </para>
+
+  <para>
+   The <parameter>buf</parameter> pointer should be to kernel space
+   memory, and obviously the <parameter>len</parameter> parameter
+   specifies the amount of data to transfer.
+  </para>
+
+  <para>
+   In fact what <function>parport_write</function> does is call the
+   appropriate block transfer function from the <structname>struct
+   parport_operations</structname>:
+  </para>
+
+  <programlisting>
+   <![CDATA[
 struct parport_operations {
         [...]
 
@@ -1045,494 +1209,620 @@ struct parport_operations {
         size_t (*byte_read_data) (struct parport *port, void *buf,
                                   size_t len, int flags);
 };
-]]></programlisting>
-
-<para>The transfer code in <filename>parport</filename> will tolerate
-a data transfer stall only for so long, and this timeout can be
-specified with <function>parport_set_timeout</function>, which returns
-the previous timeout:</para>
-
-<funcsynopsis><funcprototype>
-  <funcdef>long <function>parport_set_timeout</function></funcdef>
-  <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
-  <paramdef>long <parameter>inactivity</parameter></paramdef>
-</funcprototype></funcsynopsis>
-
-<para>This timeout is specific to the device, and is restored on
-<function>parport_claim</function>.</para>
-
-</chapter>
-
-<chapter id="ppdev">
-<title>User-level device drivers</title>
-
-<!-- ppdev -->
-<sect1>
-<title>Introduction to ppdev</title>
-
-<para>The printer is accessible through <filename>/dev/lp0</filename>;
-in the same way, the parallel port itself is accessible through
-<filename>/dev/parport0</filename>.  The difference is in the level of
-control that you have over the wires in the parallel port
-cable.</para>
-
-<para>With the printer driver, a user-space program (such as the
-printer spooler) can send bytes in <quote>printer protocol</quote>.
-Briefly, this means that for each byte, the eight data lines are set
-up, then a <quote>strobe</quote> line tells the printer to look at the
-data lines, and the printer sets an <quote>acknowledgement</quote>
-line to say that it got the byte.  The printer driver also allows the
-user-space program to read bytes in <quote>nibble mode</quote>, which
-is a way of transferring data from the peripheral to the computer half
-a byte at a time (and so it's quite slow).</para>
-
-<para>In contrast, the <filename>ppdev</filename> driver (accessed via
-<filename>/dev/parport0</filename>) allows you to:</para>
-
-<itemizedlist spacing=compact>
-
-<listitem>
-<para>
-examine status lines,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set control lines,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set/examine data lines (and control the direction of the data lines),
-</para>
-</listitem>
-
-<listitem>
-<para>
-wait for an interrupt (triggered by one of the status lines),
-</para>
-</listitem>
-
-<listitem>
-<para>
-find out how many new interrupts have occurred,
-</para>
-</listitem>
-
-<listitem>
-<para>
-set up a response to an interrupt,
-</para>
-</listitem>
-
-<listitem>
-<para>
-use IEEE 1284 negotiation (for telling peripheral which transfer mode,
-to use)
-</para>
-</listitem>
-
-<listitem>
-<para>
-transfer data using a specified IEEE 1284 mode.
-</para>
-</listitem>
-
-</itemizedlist>
-
-</sect1>
-
-<sect1>
-<title>User-level or kernel-level driver?</title>
-
-<para>The decision of whether to choose to write a kernel-level device
-driver or a user-level device driver depends on several factors.  One
-of the main ones from a practical point of view is speed: kernel-level
-device drivers get to run faster because they are not preemptable,
-unlike user-level applications.</para>
-
-<para>Another factor is ease of development.  It is in general easier
-to write a user-level driver because (a) one wrong move does not
-result in a crashed machine, (b) you have access to user libraries
-(such as the C library), and (c) debugging is easier.</para>
-
-</sect1>
-
-<sect1>
-<title>Programming interface</title>
-
-<para>The <filename>ppdev</filename> interface is largely the same as
-that of other character special devices, in that it supports
-<function>open</function>, <function>close</function>,
-<function>read</function>, <function>write</function>, and
-<function>ioctl</function>.</para>
-
-<sect2>
-<title>Starting and stopping: <function>open</function> and
-<function>close</function></title>
-
-<para>The device node <filename>/dev/parport0</filename> represents
-any device that is connected to <filename>parport0</filename>, the
-first parallel port in the system.  Each time the device node is
-opened, it represents (to the process doing the opening) a different
-device.  It can be opened more than once, but only one instance can
-actually be in control of the parallel port at any time.  A process
-that has opened <filename>/dev/parport0</filename> shares the parallel
-port in the same way as any other device driver.  A user-land driver
-may be sharing the parallel port with in-kernel device drivers as well
-as other user-land drivers.</para>
-</sect2>
-
-<sect2>
-<title>Control: <function>ioctl</function></title>
-
-<para>Most of the control is done, naturally enough, via the
-<function>ioctl</function> call.  Using <function>ioctl</function>,
-the user-land driver can control both the <filename>ppdev</filename>
-driver in the kernel and the physical parallel port itself.  The
-<function>ioctl</function> call takes as parameters a file descriptor
-(the one returned from opening the device node), a command, and
-optionally (a pointer to) some data.</para>
-
-<variablelist>
-<varlistentry><term><constant>PPCLAIM</constant></term>
-<listitem>
-
-<para>Claims access to the port.  As a user-land device driver writer,
-you will need to do this before you are able to actually change the
-state of the parallel port in any way.  Note that some operations only
-affect the <filename>ppdev</filename> driver and not the port, such as
-<constant>PPSETMODE</constant>; they can be performed while access to
-the port is not claimed.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPEXCL</constant></term>
-<listitem>
-
-<para>Instructs the kernel driver to forbid any sharing of the port
-with other drivers, i.e. it requests exclusivity.  The
-<constant>PPEXCL</constant> command is only valid when the port is not
-already claimed for use, and it may mean that the next
-<constant>PPCLAIM</constant> <function>ioctl</function> will fail:
-some other driver may already have registered itself on that
-port.</para>
-
-<para>Most device drivers don't need exclusive access to the port.
-It's only provided in case it is really needed, for example for
-devices where access to the port is required for extensive periods of
-time (many seconds).</para>
-
-<para>Note that the <constant>PPEXCL</constant>
-<function>ioctl</function> doesn't actually claim the port there and
-then---action is deferred until the <constant>PPCLAIM</constant>
-<function>ioctl</function> is performed.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRELEASE</constant></term>
-<listitem>
-
-<para>Releases the port.  Releasing the port undoes the effect of
-claiming the port.  It allows other device drivers to talk to their
-devices (assuming that there are any).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPYIELD</constant></term>
-<listitem>
-
-<para>Yields the port to another driver.  This
-<function>ioctl</function> is a kind of short-hand for releasing the
-port and immediately reclaiming it.  It gives other drivers a chance
-to talk to their devices, but afterwards claims the port back.  An
-example of using this would be in a user-land printer driver: once a
-few characters have been written we could give the port to another
-device driver for a while, but if we still have characters to send to
-the printer we would want the port back as soon as possible.</para>
-
-<para>It is important not to claim the parallel port for too long, as
-other device drivers will have no time to service their devices.  If
-your device does not allow for parallel port sharing at all, it is
-better to claim the parallel port exclusively (see
-<constant>PPEXCL</constant>).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPNEGOT</constant></term>
-<listitem>
-
-<para>Performs IEEE 1284 negotiation into a particular mode.  Briefly,
-negotiation is the method by which the host and the peripheral decide
-on a protocol to use when transferring data.</para>
-
-<para>An IEEE 1284 compliant device will start out in compatibility
-mode, and then the host can negotiate to another mode (such as
-ECP).</para>
-
-<para>The <function>ioctl</function> parameter should be a pointer to
-an <type>int</type>; values for this are in
-<filename>parport.h</filename> and include:</para>
-
-<itemizedlist spacing=compact>
-<listitem><para><constant>IEEE1284_MODE_COMPAT</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_NIBBLE</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_BYTE</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_EPP</constant></para></listitem>
-<listitem><para><constant>IEEE1284_MODE_ECP</constant></para></listitem>
-</itemizedlist>
-
-<para>The <constant>PPNEGOT</constant> <function>ioctl</function>
-actually does two things: it performs the on-the-wire negotiation, and
-it sets the behaviour of subsequent
-<function>read</function>/<function>write</function> calls so that
-they use that mode (but see <constant>PPSETMODE</constant>).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPSETMODE</constant></term>
-<listitem>
-
-<para>Sets which IEEE 1284 protocol to use for the
-<function>read</function> and <function>write</function> calls.</para>
+   ]]></programlisting>
 
-<para>The <function>ioctl</function> parameter should be a pointer to
-an <type>int</type>.</para>
-
-</listitem></varlistentry>
+  <para>
+   The transfer code in <filename>parport</filename> will tolerate a
+   data transfer stall only for so long, and this timeout can be
+   specified with <function>parport_set_timeout</function>, which
+   returns the previous timeout:
+  </para>
 
-<varlistentry><term><constant>PPGETTIME</constant></term>
-<listitem>
+  <funcsynopsis><funcprototype>
+    <funcdef>long <function>parport_set_timeout</function></funcdef>
+    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
+    <paramdef>long <parameter>inactivity</parameter></paramdef>
+   </funcprototype></funcsynopsis>
 
-<para>Retrieves the time-out value.  The <function>read</function> and
-<function>write</function> calls will time out if the peripheral
-doesn't respond quickly enough.  The <constant>PPGETTIME</constant>
-<function>ioctl</function> retrieves the length of time that the
-peripheral is allowed to have before giving up.</para>
+  <para>
+   This timeout is specific to the device, and is restored on
+   <function>parport_claim</function>.
+  </para>
 
-<para>The <function>ioctl</function> parameter should be a pointer to
-a <structname>struct timeval</structname>.</para>
+ </chapter>
 
-</listitem></varlistentry>
+ <chapter id="ppdev">
+  <title>User-level device drivers</title>
 
-<varlistentry><term><constant>PPSETTIME</constant></term>
-<listitem>
+  <!-- ppdev -->
+  <sect1>
+   <title>Introduction to ppdev</title>
 
-<para>Sets the time-out.  The <function>ioctl</function> parameter
-should be a pointer to a <structname>struct
-timeval</structname>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWCONTROL</constant></term>
-<listitem>
-
-<para>Sets the control lines.  The <function>ioctl</function>
-parameter is a pointer to an <type>unsigned char</type>, the bitwise
-OR of the control line values in
-<filename>parport.h</filename>.</para>
-
-</listitem></varlistentry>
+   <para>
+    The printer is accessible through <filename>/dev/lp0</filename>;
+    in the same way, the parallel port itself is accessible through
+    <filename>/dev/parport0</filename>.  The difference is in the
+    level of control that you have over the wires in the parallel port
+    cable.
+   </para>
 
-<varlistentry><term><constant>PPRCONTROL</constant></term>
-<listitem>
+   <para>
+    With the printer driver, a user-space program (such as the printer
+    spooler) can send bytes in <quote>printer protocol</quote>.
+    Briefly, this means that for each byte, the eight data lines are
+    set up, then a <quote>strobe</quote> line tells the printer to
+    look at the data lines, and the printer sets an
+    <quote>acknowledgement</quote> line to say that it got the byte.
+    The printer driver also allows the user-space program to read
+    bytes in <quote>nibble mode</quote>, which is a way of
+    transferring data from the peripheral to the computer half a byte
+    at a time (and so it's quite slow).
+   </para>
 
-<para>Returns the last value written to the control register, in the
-form of an <type>unsigned char</type>: each bit corresponds to a
-control line (although some are unused).  The
-<function>ioctl</function> parameter should be a pointer to an
-<type>unsigned char</type>.</para>
-
-<para>This doesn't actually touch the hardware; the last value written
-is remembered in software.  This is because some parallel port
-hardware does not offer read access to the control register.</para>
+   <para>
+    In contrast, the <filename>ppdev</filename> driver (accessed via
+    <filename>/dev/parport0</filename>) allows you to:
+   </para>
 
-<para>The control lines bits are defined in
-<filename>parport.h</filename>:</para>
+   <itemizedlist spacing=compact>
+
+    <listitem>
+     <para>
+      examine status lines,
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      set control lines,
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      set/examine data lines (and control the direction of the data
+      lines),
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      wait for an interrupt (triggered by one of the status lines),
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      find out how many new interrupts have occurred,
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      set up a response to an interrupt,
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      use IEEE 1284 negotiation (for telling peripheral which transfer
+      mode, to use)
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      transfer data using a specified IEEE 1284 mode.
+     </para>
+    </listitem>
+
+   </itemizedlist>
+
+  </sect1>
+
+  <sect1>
+   <title>User-level or kernel-level driver?</title>
 
-<itemizedlist spacing=compact>
-<listitem><para><constant>PARPORT_CONTROL_STROBE</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_AUTOFD</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_SELECT</constant></para></listitem>
-<listitem><para><constant>PARPORT_CONTROL_INIT</constant></para></listitem>
-</itemizedlist>
+   <para>
+    The decision of whether to choose to write a kernel-level device
+    driver or a user-level device driver depends on several factors.
+    One of the main ones from a practical point of view is speed:
+    kernel-level device drivers get to run faster because they are not
+    preemptable, unlike user-level applications.
+   </para>
 
-</listitem></varlistentry>
+   <para>
+    Another factor is ease of development.  It is in general easier to
+    write a user-level driver because (a) one wrong move does not
+    result in a crashed machine, (b) you have access to user libraries
+    (such as the C library), and (c) debugging is easier.
+   </para>
 
-<varlistentry><term><constant>PPFCONTROL</constant></term>
-<listitem>
+  </sect1>
 
-<para>Frobs the control lines.  Since a common operation is to change
-one of the control signals while leaving the others alone, it would be
-quite inefficient for the user-land driver to have to use
-<constant>PPRCONTROL</constant>, make the change, and then use
-<constant>PPWCONTROL</constant>.  Of course, each driver could
-remember what state the control lines are supposed to be in (they are
-never changed by anything else), but in order to provide
-<constant>PPRCONTROL</constant>, <filename>ppdev</filename> must
-remember the state of the control lines anyway.</para>
+  <sect1>
+   <title>Programming interface</title>
 
-<para>The <constant>PPFCONTROL</constant> <function>ioctl</function>
-is for <quote>frobbing</quote> control lines, and is like
-<constant>PPWCONTROL</constant> but acts on a restricted set of
-control lines.  The <function>ioctl</function> parameter is a pointer
-to a <structname>struct ppdev_frob_struct</structname>:</para>
+   <para>
+    The <filename>ppdev</filename> interface is largely the same as
+    that of other character special devices, in that it supports
+    <function>open</function>, <function>close</function>,
+    <function>read</function>, <function>write</function>, and
+    <function>ioctl</function>.
+   </para>
 
-<programlisting>
-<![CDATA[
+   <sect2>
+    <title>
+     Starting and stopping: <function>open</function> and
+     <function>close</function>
+    </title>
+
+    <para>
+     The device node <filename>/dev/parport0</filename> represents any
+     device that is connected to <filename>parport0</filename>, the
+     first parallel port in the system.  Each time the device node is
+     opened, it represents (to the process doing the opening) a
+     different device.  It can be opened more than once, but only one
+     instance can actually be in control of the parallel port at any
+     time.  A process that has opened
+     <filename>/dev/parport0</filename> shares the parallel port in
+     the same way as any other device driver.  A user-land driver may
+     be sharing the parallel port with in-kernel device drivers as
+     well as other user-land drivers.
+    </para>
+   </sect2>
+
+   <sect2>
+    <title>Control: <function>ioctl</function></title>
+
+    <para>
+     Most of the control is done, naturally enough, via the
+     <function>ioctl</function> call.  Using
+     <function>ioctl</function>, the user-land driver can control both
+     the <filename>ppdev</filename> driver in the kernel and the
+     physical parallel port itself.  The <function>ioctl</function>
+     call takes as parameters a file descriptor (the one returned from
+     opening the device node), a command, and optionally (a pointer
+     to) some data.
+    </para>
+
+    <variablelist>
+     <varlistentry><term><constant>PPCLAIM</constant></term>
+      <listitem>
+
+       <para>
+       Claims access to the port.  As a user-land device driver
+       writer, you will need to do this before you are able to
+       actually change the state of the parallel port in any way.
+       Note that some operations only affect the
+       <filename>ppdev</filename> driver and not the port, such as
+       <constant>PPSETMODE</constant>; they can be performed while
+       access to the port is not claimed.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPEXCL</constant></term>
+      <listitem>
+
+       <para>
+       Instructs the kernel driver to forbid any sharing of the port
+       with other drivers, i.e. it requests exclusivity.  The
+       <constant>PPEXCL</constant> command is only valid when the
+       port is not already claimed for use, and it may mean that the
+       next <constant>PPCLAIM</constant> <function>ioctl</function>
+       will fail: some other driver may already have registered
+       itself on that port.
+       </para>
+
+       <para>
+       Most device drivers don't need exclusive access to the port.
+       It's only provided in case it is really needed, for example
+       for devices where access to the port is required for extensive
+       periods of time (many seconds).
+       </para>
+
+       <para>
+       Note that the <constant>PPEXCL</constant>
+       <function>ioctl</function> doesn't actually claim the port
+       there and then---action is deferred until the
+       <constant>PPCLAIM</constant> <function>ioctl</function> is
+       performed.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPRELEASE</constant></term>
+      <listitem>
+
+       <para>
+       Releases the port.  Releasing the port undoes the effect of
+       claiming the port.  It allows other device drivers to talk to
+       their devices (assuming that there are any).
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPYIELD</constant></term>
+      <listitem>
+
+       <para>
+       Yields the port to another driver.  This
+       <function>ioctl</function> is a kind of short-hand for
+       releasing the port and immediately reclaiming it.  It gives
+       other drivers a chance to talk to their devices, but
+       afterwards claims the port back.  An example of using this
+       would be in a user-land printer driver: once a few characters
+       have been written we could give the port to another device
+       driver for a while, but if we still have characters to send to
+       the printer we would want the port back as soon as possible.
+       </para>
+
+       <para>
+       It is important not to claim the parallel port for too long,
+       as other device drivers will have no time to service their
+       devices.  If your device does not allow for parallel port
+       sharing at all, it is better to claim the parallel port
+       exclusively (see <constant>PPEXCL</constant>).
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPNEGOT</constant></term>
+      <listitem>
+
+       <para>
+       Performs IEEE 1284 negotiation into a particular mode.
+       Briefly, negotiation is the method by which the host and the
+       peripheral decide on a protocol to use when transferring data.
+       </para>
+
+       <para>
+       An IEEE 1284 compliant device will start out in compatibility
+       mode, and then the host can negotiate to another mode (such as
+       ECP).
+       </para>
+
+       <para>
+       The <function>ioctl</function> parameter should be a pointer
+       to an <type>int</type>; values for this are in
+       <filename>parport.h</filename> and include:
+       </para>
+
+       <itemizedlist spacing=compact>
+       <listitem><para>
+         <constant>IEEE1284_MODE_COMPAT</constant></para></listitem>
+       <listitem><para>
+         <constant>IEEE1284_MODE_NIBBLE</constant></para></listitem>
+       <listitem><para>
+         <constant>IEEE1284_MODE_BYTE</constant></para></listitem>
+       <listitem><para>
+         <constant>IEEE1284_MODE_EPP</constant></para></listitem>
+       <listitem><para>
+         <constant>IEEE1284_MODE_ECP</constant></para></listitem>
+       </itemizedlist>
+
+       <para>
+       The <constant>PPNEGOT</constant> <function>ioctl</function>
+       actually does two things: it performs the on-the-wire
+       negotiation, and it sets the behaviour of subsequent
+       <function>read</function>/<function>write</function> calls so
+       that they use that mode (but see
+       <constant>PPSETMODE</constant>).
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPSETMODE</constant></term>
+      <listitem>
+
+       <para>
+       Sets which IEEE 1284 protocol to use for the
+       <function>read</function> and <function>write</function>
+       calls.
+       </para>
+
+       <para>
+       The <function>ioctl</function> parameter should be a pointer
+       to an <type>int</type>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPGETTIME</constant></term>
+      <listitem>
+
+       <para>
+       Retrieves the time-out value.  The <function>read</function>
+       and <function>write</function> calls will time out if the
+       peripheral doesn't respond quickly enough.  The
+       <constant>PPGETTIME</constant> <function>ioctl</function>
+       retrieves the length of time that the peripheral is allowed to
+       have before giving up.
+       </para>
+
+       <para>
+       The <function>ioctl</function> parameter should be a pointer
+       to a <structname>struct timeval</structname>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPSETTIME</constant></term>
+      <listitem>
+
+       <para>
+       Sets the time-out.  The <function>ioctl</function> parameter
+       should be a pointer to a <structname>struct
+       timeval</structname>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPWCONTROL</constant></term>
+      <listitem>
+
+       <para>
+       Sets the control lines.  The <function>ioctl</function>
+       parameter is a pointer to an <type>unsigned char</type>, the
+       bitwise OR of the control line values in
+       <filename>parport.h</filename>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPRCONTROL</constant></term>
+      <listitem>
+
+       <para>
+       Returns the last value written to the control register, in the
+       form of an <type>unsigned char</type>: each bit corresponds to
+       a control line (although some are unused).  The
+       <function>ioctl</function> parameter should be a pointer to an
+       <type>unsigned char</type>.
+       </para>
+
+       <para>
+       This doesn't actually touch the hardware; the last value
+       written is remembered in software.  This is because some
+       parallel port hardware does not offer read access to the
+       control register.
+       </para>
+
+       <para>
+       The control lines bits are defined in
+       <filename>parport.h</filename>:
+       </para>
+
+       <itemizedlist spacing=compact>
+       <listitem><para>
+         <constant>PARPORT_CONTROL_STROBE</constant></para></listitem>
+         <listitem><para>
+         <constant>PARPORT_CONTROL_AUTOFD</constant></para></listitem>
+         <listitem><para>
+         <constant>PARPORT_CONTROL_SELECT</constant></para></listitem>
+         <listitem><para>
+         <constant>PARPORT_CONTROL_INIT</constant></para></listitem>
+       </itemizedlist>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPFCONTROL</constant></term>
+      <listitem>
+
+       <para>
+       Frobs the control lines.  Since a common operation is to
+       change one of the control signals while leaving the others
+       alone, it would be quite inefficient for the user-land driver
+       to have to use <constant>PPRCONTROL</constant>, make the
+       change, and then use <constant>PPWCONTROL</constant>.  Of
+       course, each driver could remember what state the control
+       lines are supposed to be in (they are never changed by
+       anything else), but in order to provide
+       <constant>PPRCONTROL</constant>, <filename>ppdev</filename>
+       must remember the state of the control lines anyway.
+       </para>
+
+       <para>
+       The <constant>PPFCONTROL</constant> <function>ioctl</function>
+       is for <quote>frobbing</quote> control lines, and is like
+       <constant>PPWCONTROL</constant> but acts on a restricted set
+       of control lines.  The <function>ioctl</function> parameter is
+       a pointer to a <structname>struct
+       ppdev_frob_struct</structname>:
+       </para>
+
+       <programlisting>
+       <![CDATA[
 struct ppdev_frob_struct {
         unsigned char mask;
         unsigned char val;
 };
-]]>
-</programlisting>
-
-<para>The <structfield>mask</structfield> and
-<structfield>val</structfield> fields are bitwise ORs of control line
-names (such as in <constant>PPWCONTROL</constant>).  The operation
-performed by <constant>PPFCONTROL</constant> is:</para>
-
-<programlisting>
-<![CDATA[new_ctr = (old_ctr & ~mask) | val;]]>
-</programlisting>
-
-<para>In other words, the signals named in
-<structfield>mask</structfield> are set to the values in
-<structfield>val</structfield>.</para>
+       ]]>
+       </programlisting>
+
+       <para>
+       The <structfield>mask</structfield> and
+       <structfield>val</structfield> fields are bitwise ORs of
+       control line names (such as in
+       <constant>PPWCONTROL</constant>).  The operation performed by
+       <constant>PPFCONTROL</constant> is:
+       </para>
+
+       <programlisting>
+       <![CDATA[
+       new_ctr = (old_ctr & ~mask) | val;]]>
+       </programlisting>
+
+       <para>
+       In other words, the signals named in
+       <structfield>mask</structfield> are set to the values in
+       <structfield>val</structfield>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPRSTATUS</constant></term>
+      <listitem>
+
+       <para>
+       Returns an <type>unsigned char</type> containing bits set for
+       each status line that is set (for instance,
+       <constant>PARPORT_STATUS_BUSY</constant>).  The
+       <function>ioctl</function> parameter should be a pointer to an
+       <type>unsigned char</type>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPDATADIR</constant></term>
+      <listitem>
+
+       <para>
+       Controls the data line drivers.  Normally the computer's
+       parallel port will drive the data lines, but for byte-wide
+       transfers from the peripheral to the host it is useful to turn
+       off those drivers and let the peripheral drive the
+       signals. (If the drivers on the computer's parallel port are
+       left on when this happens, the port might be damaged.)
+       </para>
+
+       <para>
+       This is only needed in conjunction with
+       <constant>PPWDATA</constant> or
+       <constant>PPRDATA</constant>.
+       </para>
+
+       <para>
+       The <function>ioctl</function> parameter is a pointer to an
+       <type>int</type>.  If the <type>int</type> is zero, the
+       drivers are turned on (forward direction); if non-zero, the
+       drivers are turned off (reverse direction).
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPWDATA</constant></term>
+      <listitem>
+
+       <para>
+       Sets the data lines (if in forward mode).  The
+       <function>ioctl</function> parameter is a pointer to an
+       <type>unsigned char</type>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPRDATA</constant></term>
+      <listitem>
+
+       <para>
+       Reads the data lines (if in reverse mode).  The
+       <function>ioctl</function> parameter is a pointer to an
+       <type>unsigned char</type>.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPCLRIRQ</constant></term>
+      <listitem>
+
+       <para>
+       Clears the interrupt count.  The <filename>ppdev</filename>
+       driver keeps a count of interrupts as they are triggered.
+       <constant>PPCLRIRQ</constant> stores this count in an
+       <type>int</type>, a pointer to which is passed in as the
+       <function>ioctl</function> parameter.
+       </para>
+
+       <para>
+       In addition, the interrupt count is reset to zero.
+       </para>
+
+      </listitem></varlistentry>
+
+     <varlistentry><term><constant>PPWCTLONIRQ</constant></term>
+      <listitem>
+
+       <para>
+       Set a trigger response.  Afterwards when an interrupt is
+       triggered, the interrupt handler will set the control lines as
+       requested.  The <function>ioctl</function> parameter is a
+       pointer to an <type>unsigned char</type>, which is interpreted
+       in the same way as for <constant>PPWCONTROL</constant>.
+       </para>
+
+       <para>
+       The reason for this <function>ioctl</function> is simply
+       speed.  Without this <function>ioctl</function>, responding to
+       an interrupt would start in the interrupt handler, switch
+       context to the user-land driver via <function>poll</function>
+       or <function>select</function>, and then switch context back
+       to the kernel in order to handle
+       <constant>PPWCONTROL</constant>.  Doing the whole lot in the
+       interrupt handler is a lot faster.
+       </para>
+
+      </listitem></varlistentry>
+
+     <!-- PPSETPHASE? -->
+
+    </variablelist>
+
+   </sect2>
+
+   <sect2>
+    <title>Transferring data: <function>read</function> and
+     <function>write</function></title>
+
+    <para>
+     Transferring data using <function>read</function> and
+     <function>write</function> is straightforward.  The data is
+     transferring using the current IEEE 1284 mode (see the
+     <constant>PPSETMODE</constant> <function>ioctl</function>).  For
+     modes which can only transfer data in one direction, only the
+     appropriate function will work, of course.
+    </para>
+   </sect2>
+
+   <sect2>
+    <title>Waiting for events: <function>poll</function> and
+     <function>select</function></title>
+
+    <para>
+     The <filename>ppdev</filename> driver provides user-land device
+     drivers with the ability to wait for interrupts, and this is done
+     using <function>poll</function> (and <function>select</function>,
+     which is implemented in terms of <function>poll</function>).
+    </para>
+
+    <para>
+     When a user-land device driver wants to wait for an interrupt, it
+     sleeps with <function>poll</function>.  When the interrupt
+     arrives, <filename>ppdev</filename> wakes it up (with a
+     <quote>read</quote> event, although strictly speaking there is
+     nothing to actually <function>read</function>).
+    </para>
+
+   </sect2>
+
+  </sect1>
+
+  <sect1>
+   <title>Examples</title>
 
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRSTATUS</constant></term>
-<listitem>
-
-<para>Returns an <type>unsigned char</type> containing bits set for
-each status line that is set (for instance,
-<constant>PARPORT_STATUS_BUSY</constant>).  The
-<function>ioctl</function> parameter should be a pointer to an
-<type>unsigned char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPDATADIR</constant></term>
-<listitem>
-
-<para>Controls the data line drivers.  Normally the computer's
-parallel port will drive the data lines, but for byte-wide transfers
-from the peripheral to the host it is useful to turn off those drivers
-and let the peripheral drive the signals. (If the drivers on the
-computer's parallel port are left on when this happens, the port might
-be damaged.)</para>
-
-<para>This is only needed in conjunction with
-<constant>PPWDATA</constant> or <constant>PPRDATA</constant>.</para>
-
-<para>The <function>ioctl</function> parameter is a pointer to an
-<type>int</type>.  If the <type>int</type> is zero, the drivers are
-turned on (forward direction); if non-zero, the drivers are turned off
-(reverse direction).</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWDATA</constant></term>
-<listitem>
-
-<para>Sets the data lines (if in forward mode).  The
-<function>ioctl</function> parameter is a pointer to an <type>unsigned
-char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPRDATA</constant></term>
-<listitem>
-
-<para>Reads the data lines (if in reverse mode).  The
-<function>ioctl</function> parameter is a pointer to an <type>unsigned
-char</type>.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPCLRIRQ</constant></term>
-<listitem>
-
-<para>Clears the interrupt count.  The <filename>ppdev</filename>
-driver keeps a count of interrupts as they are triggered.
-<constant>PPCLRIRQ</constant> stores this count in an
-<type>int</type>, a pointer to which is passed in as the
-<function>ioctl</function> parameter.</para>
-
-<para>In addition, the interrupt count is reset to zero.</para>
-
-</listitem></varlistentry>
-
-<varlistentry><term><constant>PPWCTLONIRQ</constant></term>
-<listitem>
-
-<para>Set a trigger response.  Afterwards when an interrupt is
-triggered, the interrupt handler will set the control lines as
-requested.  The <function>ioctl</function> parameter is a pointer to
-an <type>unsigned char</type>, which is interpreted in the same way as
-for <constant>PPWCONTROL</constant>.</para>
-
-<para>The reason for this <function>ioctl</function> is simply speed.
-Without this <function>ioctl</function>, responding to an interrupt
-would start in the interrupt handler, switch context to the user-land
-driver via <function>poll</function> or <function>select</function>,
-and then switch context back to the kernel in order to handle
-<constant>PPWCONTROL</constant>.  Doing the whole lot in the interrupt
-handler is a lot faster.</para>
-
-</listitem></varlistentry>
-
-<!-- PPSETPHASE? -->
-
-</variablelist>
-
-</sect2>
-
-<sect2>
-<title>Transferring data: <function>read</function> and
-<function>write</function></title>
-
-<para>Transferring data using <function>read</function> and
-<function>write</function> is straightforward.  The data is
-transferring using the current IEEE 1284 mode (see the
-<constant>PPSETMODE</constant> <function>ioctl</function>).  For modes
-which can only transfer data in one direction, only the appropriate
-function will work, of course.</para>
-</sect2>
-
-<sect2>
-<title>Waiting for events: <function>poll</function> and
-<function>select</function></title>
-
-<para>The <filename>ppdev</filename> driver provides user-land device
-drivers with the ability to wait for interrupts, and this is done
-using <function>poll</function> (and <function>select</function>,
-which is implemented in terms of <function>poll</function>).</para>
-
-<para>When a user-land device driver wants to wait for an interrupt,
-it sleeps with <function>poll</function>.  When the interrupt arrives,
-<filename>ppdev</filename> wakes it up (with a <quote>read</quote>
-event, although strictly speaking there is nothing to actually
-<function>read</function>).</para>
-
-</sect2>
-
-</sect1>
-
-<sect1>
-<title>Examples</title>
-
-<para>Presented here are two demonstrations of how to write a simple
-printer driver for <filename>ppdev</filename>.  Firstly we will use
-the <function>write</function> function, and after that we will drive
-the control and data lines directly.</para>
+   <para>
+    Presented here are two demonstrations of how to write a simple
+    printer driver for <filename>ppdev</filename>.  Firstly we will
+    use the <function>write</function> function, and after that we
+    will drive the control and data lines directly.
+   </para>
 
-<para>The first thing to do is to actually open the device.</para>
+   <para>
+    The first thing to do is to actually open the device.
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
 int drive_printer (const char *name)
 {
     int fd;
@@ -1543,32 +1833,39 @@ int drive_printer (const char *name)
         perror ("open");
         return 1;
     }
-]]></programlisting>
+    ]]></programlisting>
 
-<para>Here <varname>name</varname> should be something along the lines
-of <filename>"/dev/parport0"</filename>. (If you don't have any
-<filename>/dev/parport</filename> files, you can make them with
-<command>mknod</command>; they are character special device nodes with
-major 99.)</para>
+   <para>
+    Here <varname>name</varname> should be something along the lines
+    of <filename>"/dev/parport0"</filename>. (If you don't have any
+    <filename>/dev/parport</filename> files, you can make them with
+    <command>mknod</command>; they are character special device nodes
+    with major 99.)
+   </para>
 
-<para>In order to do anything with the port we need to claim access to
-it.</para>
+   <para>
+    In order to do anything with the port we need to claim access to
+    it.
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
     if (ioctl (fd, PPCLAIM)) {
         perror ("PPCLAIM");
         close (fd);
         return 1;
     }
-]]></programlisting>
+    ]]></programlisting>
 
-<para>Our printer driver will copy its input (from
-<varname>stdin</varname>) to the printer, and it can do that it one of
-two ways.  The first way is to hand it all off to the kernel driver,
-with the knowledge that the protocol that the printer speaks is IEEE
-1284's <quote>compatibility</quote> mode.</para>
+   <para>
+    Our printer driver will copy its input (from
+    <varname>stdin</varname>) to the printer, and it can do that it
+    one of two ways.  The first way is to hand it all off to the
+    kernel driver, with the knowledge that the protocol that the
+    printer speaks is IEEE 1284's <quote>compatibility</quote>
+    mode.
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
     /* Switch to compatibility mode.  (In fact we don't need
      * to do this, since we start off in compatibility mode
      * anyway, but this demonstrates PPNEGOT.)
@@ -1608,38 +1905,46 @@ with the knowledge that the protocol that the printer speaks is IEEE
             got -= written;
         }
     }
-]]></programlisting>
+    ]]></programlisting>
 
-<para>The <function>write_printer</function> function is not pictured
-above.  This is because the main loop that is shown can be used for
-both methods of driving the printer.  Here is one implementation of
-<function>write_printer</function>:</para>
+   <para>
+    The <function>write_printer</function> function is not pictured
+    above.  This is because the main loop that is shown can be used
+    for both methods of driving the printer.  Here is one
+    implementation of <function>write_printer</function>:
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
 ssize_t write_printer (int fd, const void *ptr, size_t count)
 {
     return write (fd, ptr, count);
 }
-]]></programlisting>
+    ]]></programlisting>
 
-<para>We hand the data to the kernel-level driver (using
-<function>write</function>) and it handles the printer
-protocol.</para>
+   <para>
+    We hand the data to the kernel-level driver (using
+    <function>write</function>) and it handles the printer
+    protocol.
+   </para>
 
-<para>Now let's do it the hard way!  In this particular example there
-is no practical reason to do anything other than just call
-<function>write</function>, because we know that the printer talks an
-IEEE 1284 protocol.  On the other hand, this particular example does
-not even need a user-land driver since there is already a kernel-level
-one; for the purpose of this discussion, try to imagine that the
-printer speaks a protocol that is not already implemented under
-Linux.</para>
+   <para>
+    Now let's do it the hard way!  In this particular example there is
+    no practical reason to do anything other than just call
+    <function>write</function>, because we know that the printer talks
+    an IEEE 1284 protocol.  On the other hand, this particular example
+    does not even need a user-land driver since there is already a
+    kernel-level one; for the purpose of this discussion, try to
+    imagine that the printer speaks a protocol that is not already
+    implemented under Linux.
+   </para>
 
-<para>So, here is the alternative implementation of
-<function>write_printer</function> (for brevity, error checking has
-been omitted):</para>
+   <para>
+    So, here is the alternative implementation of
+    <function>write_printer</function> (for brevity, error checking
+    has been omitted):
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
 ssize_t write_printer (int fd, const void *ptr, size_t count)
 {
     ssize_t wrote = 0;
@@ -1690,13 +1995,15 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
 
     return wrote;
 }
-]]></programlisting>
+    ]]></programlisting>
 
-<para>To show a bit more of the <filename>ppdev</filename> interface,
-here is a small piece of code that is intended to mimic the printer's
-side of printer protocol.</para>
+   <para>
+    To show a bit more of the <filename>ppdev</filename> interface,
+    here is a small piece of code that is intended to mimic the
+    printer's side of printer protocol.
+   </para>
 
-<programlisting><![CDATA[
+   <programlisting><![CDATA[
   for (;;)
     {
       int irqc;
@@ -1739,9 +2046,42 @@ side of printer protocol.</para>
 
       putchar (ch);
     }
-]]></programlisting>
-
-</sect1>
+    ]]></programlisting>
+
+  </sect1>
+
+ </chapter>
+
+ <DEFANGED_appendix>
+  <title>
+   API reference
+  </title>
+
+!Fdrivers/parport/daisy.c parport_device_num
+!Fdrivers/parport/daisy.c parport_device_coords
+!Fdrivers/parport/daisy.c parport_find_device
+!Fdrivers/parport/daisy.c parport_find_class
+!Fdrivers/parport/share.c parport_register_driver
+!Fdrivers/parport/share.c parport_unregister_driver
+!Fdrivers/parport/share.c parport_register_device
+!Fdrivers/parport/share.c parport_unregister_device
+!Fdrivers/parport/daisy.c parport_open
+!Fdrivers/parport/daisy.c parport_close
+!Fdrivers/parport/share.c parport_claim
+!Fdrivers/parport/share.c parport_claim_or_block
+!Fdrivers/parport/share.c parport_release
+!Finclude/linux/parport.h parport_yield
+!Finclude/linux/parport.h parport_yield_blocking
+!Fdrivers/parport/ieee1284.c parport_negotiate
+!Fdrivers/parport/ieee1284.c parport_write
+!Fdrivers/parport/ieee1284.c parport_read
+!Fdrivers/parport/ieee1284.c parport_set_timeout
+
+ </appendix>
+</book>
+
+<!-- Local Variables: -->
+<!-- sgml-indent-step: 1 -->
+<!-- sgml-indent-data: 1 -->
+<!-- End: -->
 
-</chapter>
-</book>
\ No newline at end of file
index b676d2b32c9645b842ec29fef5b60841a611dbab..b96f6c48fec540b7fa7be09b0920932d2a2c3765 100644 (file)
@@ -96,6 +96,9 @@ Tips:
        The ID table array should be marked __devinitdata.
        The probe() and remove() functions (and all initialization
        functions called only from these) should be marked __devinit/exit.
+       If you are sure the driver is not a hotplug driver then use only 
+       __init/exit __initdata/exitdata.
+
 
 2. How to find PCI devices manually (the old style)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index e41e60edfb7c91eb53da96e06d95ec998439b4ec..02ec58baac5616516201c93dc501202365871fcd 100644 (file)
@@ -38,6 +38,10 @@ bttv.o
   card=36 - Typhoon TView TV/FM Tuner
   card=37 - PixelView PlayTV pro
   card=38 - TView99 CPH063
+  card=39 - Pinnacle PCTV Rave
+  card=40 - STB2
+  card=41 - AVerMedia TVPhone 98
+  card=42 - ProVideo PV951
 
 tuner.o
   type=0 - Temic PAL
index 56f7268549de63ee969a1c4f849dc3d8cecfe52a..1776ea8a77c58825a05aff0c3c76497225e73970 100644 (file)
@@ -482,6 +482,7 @@ S:      Supported
 IDE DRIVER [GENERAL]
 P:     Andre Hedrick
 M:     andre@linux-ide.org
+M:     ahedrick@atipa.com
 M:     andre@suse.com
 L:     linux-kernel@vger.rutgers.edu
 W:     http://www.kernel.org/pub/linux/kernel/people/hedrick/
index 3988131acb041aeb4b563608c27f59f9fe28f9ae..b49cebfded6b96084e4c65f8242b9f60795e87a6 100644 (file)
@@ -182,7 +182,7 @@ ifeq ($(CONFIG_ARCH_ACORN),y)
 SUBDIRS                += drivers/acorn
 DRIVERS                += drivers/acorn/block/acorn-block.a
 DRIVERS                += drivers/acorn/char/acorn-char.o
-DRIVERS                += drivers/acorn/net/acorn-net.a
+DRIVERS                += drivers/acorn/net/acorn-net.o
 DRIVERS                += drivers/acorn/scsi/acorn-scsi.a
 endif
 
index 417ad00ffff30ac6784fe34717905130d0536b88..42529e789a41f8307e4d606190744899b65c7480 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_UID16=y
 CONFIG_EXPERIMENTAL=y
 
 #
-# System and processor type
+# System and Processor Type
 #
 # CONFIG_ARCH_ARC is not set
 # CONFIG_ARCH_A5K is not set
@@ -25,6 +25,8 @@ CONFIG_CPU_SA110=y
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
 # CONFIG_ISA_DMA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCMCIA is not set
 
 #
 # Loadable module support
@@ -69,7 +71,6 @@ CONFIG_LEDS=y
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
 # CONFIG_I2O_BLOCK is not set
 # CONFIG_I2O_LAN is not set
 # CONFIG_I2O_SCSI is not set
@@ -87,13 +88,19 @@ CONFIG_LEDS=y
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 
 #
 # Additional Block Devices
 #
 # CONFIG_BLK_DEV_LOOP is not set
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_LVM is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_RAID15_DANGEROUS is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
 
@@ -124,7 +131,7 @@ CONFIG_PRINTER=m
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
+# CONFIG_MOUSE is not set
 # CONFIG_PSMOUSE is not set
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
@@ -141,6 +148,7 @@ CONFIG_MOUSE=y
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 # CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
 CONFIG_SOFT_WATCHDOG=y
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
@@ -173,6 +181,7 @@ CONFIG_NETLINK=y
 CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
 CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -222,6 +231,7 @@ CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
 # CONFIG_IP_NF_TARGET_MIRROR is not set
 CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=y
 CONFIG_IP_NF_TARGET_REDIRECT=y
 CONFIG_IP_NF_MANGLE=y
@@ -302,10 +312,12 @@ CONFIG_ARM_AM79C961A=y
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
 CONFIG_PPP_ASYNC=y
 # CONFIG_PPP_SYNC_TTY is not set
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 
 #
@@ -342,9 +354,10 @@ CONFIG_PPP_BSDCOMP=m
 # File systems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
@@ -354,10 +367,12 @@ CONFIG_AUTOFS4_FS=y
 # CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
-CONFIG_MINIX_FS=y
+# CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
@@ -365,23 +380,39 @@ CONFIG_PROC_FS=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_EXT2_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
index acfd9de1758aad5b9b9707805c91c1ecd6a3b7d0..ffe655f5db290d72e24d7907b4d8e992b51f5860 100644 (file)
@@ -10,7 +10,7 @@ CONFIG_UID16=y
 CONFIG_EXPERIMENTAL=y
 
 #
-# System and processor type
+# System and Processor Type
 #
 # CONFIG_ARCH_ARC is not set
 # CONFIG_ARCH_A5K is not set
@@ -19,6 +19,10 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_FOOTBRIDGE=y
 CONFIG_HOST_FOOTBRIDGE=y
 # CONFIG_ADDIN_FOOTBRIDGE is not set
+
+#
+# Footbridge Implementations
+#
 CONFIG_ARCH_EBSA285=y
 # CONFIG_ARCH_CATS is not set
 CONFIG_ARCH_NETWINDER=y
@@ -30,7 +34,10 @@ CONFIG_CPU_32v4=y
 CONFIG_CPU_SA110=y
 CONFIG_PCI=y
 CONFIG_PCI_NAMES=y
+CONFIG_ISA=y
 CONFIG_ISA_DMA=y
+# CONFIG_SBUS is not set
+# CONFIG_PCMCIA is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -137,7 +144,11 @@ CONFIG_PARIDE_ON26=m
 #
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_LVM is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_RAID15_DANGEROUS is not set
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_BLK_DEV_INITRD is not set
 
@@ -202,6 +213,7 @@ CONFIG_PSMOUSE=y
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
 # CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
 CONFIG_SOFT_WATCHDOG=y
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
@@ -242,6 +254,7 @@ CONFIG_VIDEO_DEV=y
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_VIDEO_BWQCAM is not set
 # CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CPIA is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_TUNER_3036 is not set
 # CONFIG_VIDEO_STRADIS is not set
@@ -261,56 +274,6 @@ CONFIG_VIDEO_CYBERPRO=m
 # CONFIG_DRM_TDFX is not set
 # CONFIG_AGP is not set
 
-#
-# USB support
-#
-CONFIG_USB=m
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=m
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
-CONFIG_USB_PRINTER=m
-CONFIG_USB_SCANNER=m
-CONFIG_USB_AUDIO=m
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_CPIA is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_DSBR is not set
-
-#
-# USB HID
-#
-# CONFIG_USB_HID is not set
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_WMFORCE is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
 #
 # Console drivers
 #
@@ -522,10 +485,12 @@ CONFIG_NE2K_PCI=y
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
 CONFIG_PPP_ASYNC=m
 # CONFIG_PPP_SYNC_TTY is not set
 CONFIG_PPP_DEFLATE=m
 CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -588,9 +553,10 @@ CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC6210 is not set
-# CONFIG_AEC6210_TUNING is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD7409 is not set
 # CONFIG_AMD7409_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
@@ -610,6 +576,7 @@ CONFIG_BLK_DEV_PDC202XX=y
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_VIA82CXXX_TUNING is not set
 CONFIG_BLK_DEV_SL82C105=y
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
@@ -625,6 +592,7 @@ CONFIG_BLK_DEV_IDE_MODES=y
 #
 CONFIG_SOUND=m
 # CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
@@ -633,6 +601,7 @@ CONFIG_SOUND=m
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
 CONFIG_SOUND_OSS=m
 # CONFIG_SOUND_TRACEINIT is not set
 # CONFIG_SOUND_DMAP is not set
@@ -643,6 +612,7 @@ CONFIG_SOUND_ADLIB=m
 # CONFIG_SOUND_CS4232 is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_VMIDI is not set
 # CONFIG_SOUND_TRIX is not set
 # CONFIG_SOUND_MSS is not set
@@ -657,7 +627,6 @@ CONFIG_SOUND_SB=m
 # CONFIG_SOUND_AWE32_SYNTH is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 # CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_YM3812 is not set
 # CONFIG_SOUND_OPL3SA1 is not set
 # CONFIG_SOUND_OPL3SA2 is not set
@@ -670,8 +639,8 @@ CONFIG_SOUND_WAVEARTIST=m
 # File systems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
 CONFIG_ADFS_FS=m
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
@@ -683,10 +652,12 @@ CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
@@ -694,17 +665,22 @@ CONFIG_PROC_FS=y
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
@@ -712,6 +688,16 @@ CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
@@ -766,6 +752,57 @@ CONFIG_NLS_ISO8859_2=m
 CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 
+#
+# USB support
+#
+CONFIG_USB=m
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=m
+
+#
+# USB Devices
+#
+CONFIG_USB_PRINTER=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_DSBR is not set
+
+#
+# USB HID
+#
+# CONFIG_USB_HID is not set
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_WMFORCE is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
 #
 # Kernel hacking
 #
@@ -774,4 +811,5 @@ CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
index a22e1d99258583bfab1decd1070bffbe3065b7cf..d55bdf89f2b385b1f81a552e176eeccb049f1c42 100644 (file)
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
+CONFIG_UID16=y
 
 #
 # Code maturity level options
@@ -9,7 +10,7 @@ CONFIG_ARM=y
 CONFIG_EXPERIMENTAL=y
 
 #
-# System and processor type
+# System and Processor Type
 #
 # CONFIG_ARCH_ARC is not set
 # CONFIG_ARCH_A5K is not set
@@ -23,7 +24,11 @@ CONFIG_CPU_32v3=y
 CONFIG_CPU_ARM6=y
 CONFIG_CPU_ARM7=y
 CONFIG_CPU_SA110=y
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
 # CONFIG_ISA_DMA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCMCIA is not set
 # CONFIG_ALIGNMENT_TRAP is not set
 
 #
@@ -47,10 +52,14 @@ CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
 # CONFIG_PARPORT_PC_FIFO is not set
-# CONFIG_PARPORT_PC_PCMCIA is not set
+CONFIG_PARPORT_PC_SUPERIO=y
 # CONFIG_PARPORT_ARC is not set
 # CONFIG_PARPORT_AMIGA is not set
 # CONFIG_PARPORT_MFC3 is not set
@@ -63,7 +72,6 @@ CONFIG_PARPORT_PC=y
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
 # CONFIG_I2O_BLOCK is not set
 # CONFIG_I2O_LAN is not set
 # CONFIG_I2O_SCSI is not set
@@ -79,44 +87,23 @@ CONFIG_PARPORT_PC=y
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-CONFIG_BLK_DEV_IDE_ICSIDE=y
-CONFIG_BLK_DEV_IDEDMA_ICS=y
-CONFIG_IDEDMA_ICS_AUTO=y
-CONFIG_BLK_DEV_IDE_RAPIDE=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 
 #
 # Additional Block Devices
 #
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
 # CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_RAID15_DANGEROUS is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
 # Acorn-specific block devices
@@ -138,6 +125,17 @@ CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_PHILIPSPAR is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=y
+
 #
 # Mice
 #
@@ -177,19 +175,9 @@ CONFIG_MOUSE=y
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
 # CONFIG_DRM_TDFX is not set
-
-#
-# PCMCIA character device support
-#
-# CONFIG_PCMCIA_SERIAL_CS is not set
 # CONFIG_AGP is not set
 CONFIG_RPCMOUSE=y
 
-#
-# Support for USB
-#
-# CONFIG_USB is not set
-
 #
 # Console drivers
 #
@@ -201,10 +189,6 @@ CONFIG_FB=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FB_ACORN=y
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_3DFX is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
 CONFIG_FBCON_MFB=y
@@ -222,6 +206,7 @@ CONFIG_FBCON_CFB32=y
 # CONFIG_FBCON_MAC is not set
 # CONFIG_FBCON_VGA_PLANES is not set
 # CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -298,6 +283,7 @@ CONFIG_NETDEVICES=y
 #
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_NET_SB1000 is not set
 
@@ -312,12 +298,10 @@ CONFIG_ARM_ETHERH=y
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_DM9102 is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+# CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
 
 #
@@ -330,10 +314,12 @@ CONFIG_ARM_ETHERH=y
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
 # CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 
 #
@@ -342,7 +328,7 @@ CONFIG_PPP=m
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring driver support
+# Token Ring devices
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
@@ -355,9 +341,42 @@ CONFIG_PPP=m
 # CONFIG_WAN is not set
 
 #
-# PCMCIA network device support
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
 #
-# CONFIG_NET_PCMCIA is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDE_ICSIDE=y
+CONFIG_BLK_DEV_IDEDMA_ICS=y
+CONFIG_IDEDMA_ICS_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_BLK_DEV_IDE_RAPIDE=y
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
@@ -368,9 +387,11 @@ CONFIG_SCSI=y
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
+CONFIG_SD_EXTRA_DEVS=8
+CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
 
 #
@@ -390,12 +411,12 @@ CONFIG_SCSI_LOGGING=y
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
@@ -403,6 +424,8 @@ CONFIG_SCSI_LOGGING=y
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_IMM=m
 # CONFIG_SCSI_IZIP_EPP16 is not set
@@ -410,15 +433,14 @@ CONFIG_SCSI_IMM=m
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_ACORNSCSI_3=m
 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
@@ -439,6 +461,7 @@ CONFIG_SCSI_OAK1=m
 #
 CONFIG_SOUND=m
 # CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
@@ -447,12 +470,18 @@ CONFIG_SOUND=m
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
 CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
 # CONFIG_SOUND_CS4232 is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_VMIDI is not set
 # CONFIG_SOUND_TRIX is not set
 # CONFIG_SOUND_MSS is not set
@@ -460,30 +489,29 @@ CONFIG_SOUND_OSS=m
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_SOFTOSS is not set
+CONFIG_SOUND_SOFTOSS=m
 # CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 # CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_YM3812 is not set
 # CONFIG_SOUND_OPL3SA1 is not set
 # CONFIG_SOUND_OPL3SA2 is not set
 # CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
 CONFIG_SOUND_VIDC=m
 # CONFIG_SOUND_WAVEARTIST is not set
 
 #
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
-
-#
-# Filesystems
+# File systems
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
 CONFIG_ADFS_FS=y
+# CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
@@ -492,35 +520,66 @@ CONFIG_ADFS_FS=y
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
 
 #
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_ACORN_PARTITION_RISCIX=y
 CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
 CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
 CONFIG_BSD_DISKLABEL=y
@@ -528,13 +587,6 @@ CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_SGI_PARTITION=y
 CONFIG_SUN_PARTITION=y
-CONFIG_AMIGA_PARTITION=y
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_ACORN_PARTITION=y
-CONFIG_ACORN_PARTITION_ADFS=y
-CONFIG_ACORN_PARTITION_ICS=y
-CONFIG_ACORN_PARTITION_POWERTEC=y
-CONFIG_ACORN_PARTITION_RISCIX=y
 CONFIG_NLS=y
 
 #
@@ -569,6 +621,11 @@ CONFIG_NLS_ISO8859_9=m
 # CONFIG_NLS_ISO8859_15 is not set
 CONFIG_NLS_KOI8_R=m
 
+#
+# USB support
+#
+# CONFIG_USB is not set
+
 #
 # Kernel hacking
 #
index d8f14a756d302e6faf96f62be020a036f5f713c7..a129ca2f63a32a899c917f3f09a53bcd47389fc6 100644 (file)
@@ -34,7 +34,7 @@ obj-                  :=
 
 export-objs            := armksyms.o dma.o ecard.o hw-footbridge.o leds-$(MACHINE).o
 
-obj-$(CONFIG_ARCH_ACORN) += dma.o ecard.o iic.o fiq.o time-acorn.o
+obj-$(CONFIG_ARCH_ACORN) += dma.o ecard.o fiq.o time-acorn.o
 obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o
 obj-$(CONFIG_MODULES)  += armksyms.o
 obj-$(CONFIG_LEDS)     += leds-$(MACHINE).o
diff --git a/arch/arm/kernel/iic.c b/arch/arm/kernel/iic.c
deleted file mode 100644 (file)
index c9a672a..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * linux/arch/arm/kernel/iic.c
- *
- * Copyright (C) 1995, 1996 Russell King
- *
- * IIC is used to get the current time from the CMOS rtc.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-
-#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/ioc.h>
-
-#define FORCE_ONES     0xdc
-
-/*
- * if delay loop has been calibrated then us that,
- * else use IOC timer 1.
- */
-static void iic_delay(void)
-{
-       extern unsigned long loops_per_sec;
-       if (loops_per_sec != (1 << 12)) {
-               udelay(100); /* was 10 */
-               return;
-       } else {
-               unsigned long flags;
-               save_flags_cli(flags);
-
-               outb(254,  IOC_T1LTCHL);
-               outb(255,  IOC_T1LTCHH);
-               outb(0,    IOC_T1GO);
-               outb(1<<6, IOC_IRQCLRA);                        /* clear T1 irq */
-               outb(10,   IOC_T1LTCHL); /* was 4 */
-               outb(0,    IOC_T1LTCHH);
-               outb(0,    IOC_T1GO);
-               while ((inb(IOC_IRQSTATA) & (1<<6)) == 0);
-               restore_flags(flags);
-       }
-}
-
-#define IIC_INIT()             dat = (inb(IOC_CONTROL) | FORCE_ONES) & ~3
-#define IIC_SET_DAT            outb(dat|=1, IOC_CONTROL);
-#define IIC_CLR_DAT            outb(dat&=~1, IOC_CONTROL);
-#define IIC_SET_CLK            outb(dat|=2, IOC_CONTROL);
-#define IIC_CLR_CLK            outb(dat&=~2, IOC_CONTROL);
-#define IIC_DELAY              iic_delay();
-#define IIC_READ_DATA()                (inb(IOC_CONTROL) & 1)
-
-static inline void iic_set_lines(int clk, int dat)
-{
-       int old;
-
-       old = inb(IOC_CONTROL) | FORCE_ONES;
-
-       old &= ~3;
-
-       if (clk)
-               old |= 2;
-       if (dat)
-               old |= 1;
-
-       outb(old, IOC_CONTROL);
-
-       iic_delay();
-}
-
-static inline unsigned int iic_read_data(void)
-{
-       return inb(IOC_CONTROL) & 1;
-}
-
-/*
- * C: ==~~_
- * D: =~~__
- */
-static inline void iic_start(void)
-{
-       unsigned int dat;
-
-       IIC_INIT();
-
-       IIC_SET_DAT
-       IIC_DELAY
-       IIC_SET_CLK
-       IIC_DELAY
-
-       IIC_CLR_DAT
-       IIC_DELAY
-       IIC_CLR_CLK
-       IIC_DELAY
-}
-
-/*
- * C: __~~
- * D: =__~
- */
-static inline void iic_stop(void)
-{
-       unsigned int dat;
-
-       IIC_INIT();
-
-       IIC_CLR_DAT
-       IIC_DELAY
-       IIC_SET_CLK
-       IIC_DELAY
-       IIC_SET_DAT
-       IIC_DELAY
-}
-
-/*
- * C: __~_
- * D: =___
- */
-static inline void iic_acknowledge(void)
-{
-       unsigned int dat;
-
-       IIC_INIT();
-
-       IIC_CLR_DAT
-       IIC_DELAY
-       IIC_SET_CLK
-       IIC_DELAY
-       IIC_CLR_CLK
-       IIC_DELAY
-}
-
-/*
- * C: __~_
- * D: =~H~
- */
-static inline int iic_is_acknowledged(void)
-{
-       unsigned int dat, ack_bit;
-
-       IIC_INIT();
-
-       IIC_SET_DAT
-       IIC_DELAY
-       IIC_SET_CLK
-       IIC_DELAY
-
-       ack_bit = IIC_READ_DATA();
-
-       IIC_CLR_CLK
-       IIC_DELAY
-
-       return ack_bit == 0;
-}
-
-/*
- * C: _~__~__~__~__~__~__~__~_
- * D: =DDXDDXDDXDDXDDXDDXDDXDD
- */
-static void iic_sendbyte(unsigned int b)
-{
-       unsigned int dat, i;
-
-       IIC_INIT();
-
-       for (i = 0; i < 8; i++) {
-               if (b & 128)
-                       IIC_SET_DAT
-               else
-                       IIC_CLR_DAT
-               IIC_DELAY
-
-               IIC_SET_CLK
-               IIC_DELAY
-               IIC_CLR_CLK
-               IIC_DELAY
-
-               b <<= 1;
-       }
-}
-
-/*
- * C: __~_~_~_~_~_~_~_~_
- * D: =~HHHHHHHHHHHHHHHH
- */
-static unsigned char iic_recvbyte(void)
-{
-       unsigned int dat, i, in;
-
-       IIC_INIT();
-
-       IIC_SET_DAT
-       IIC_DELAY
-
-       in = 0;
-       for (i = 0; i < 8; i++) {
-               IIC_SET_CLK
-               IIC_DELAY
-
-               in = (in << 1) | IIC_READ_DATA();
-
-               IIC_CLR_CLK
-               IIC_DELAY
-       }
-
-       return in;
-}
-
-int iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len)
-{
-       int i, err = -EIO;
-
-       iic_start();
-       iic_sendbyte(addr & 0xfe);
-       if (!iic_is_acknowledged())
-               goto error;
-
-       iic_sendbyte(loc);
-       if (!iic_is_acknowledged())
-               goto error;
-
-       if (addr & 1) {
-               iic_stop();
-               iic_start();
-               iic_sendbyte(addr|1);
-               if (!iic_is_acknowledged())
-                       goto error;
-
-               for (i = 0; i < len - 1; i++) {
-                       buf[i] = iic_recvbyte();
-                       iic_acknowledge();
-               }
-               buf[i] = iic_recvbyte();
-       } else {
-               for (i = 0; i < len; i++) {
-                       iic_sendbyte(buf[i]);
-
-                       if (!iic_is_acknowledged())
-                               goto error;
-               }
-       }
-
-       err = 0;
-error:
-       iic_stop();
-
-       return err;
-}
index 5f48f951abf3e186f74fb718068a49fa369140d5..e932164bf8b5de2721881dcefbfe20aae2d59d0a 100644 (file)
@@ -20,6 +20,7 @@ L_OBJS_rpc            := io-acorn.o floppydma.o
 L_OBJS_clps7500                := io-acorn.o
 L_OBJS_ebsa110         := io-ebsa110.o
 L_OBJS_footbridge      := io-footbridge.o
+L_OBJS_l7200           := io-acorn.o
 L_OBJS_nexuspci                := io-footbridge.o
 L_OBJS_sa1100          := io-footbridge.o
 L_OBJS_shark           := io-shark.o
index f618cac4bb7ed9e7c5b0b20aedb81087c6cc2417..e00ac753a26cf7faf36c7e6ef3ffe67455bfe852 100644 (file)
@@ -111,7 +111,6 @@ CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
@@ -169,6 +168,13 @@ CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
index 9d21c617e17e9f5852b4f7c4564e5ff51d4493b1..2e220bc06ec702c36949e3f1eaa263481d589ec0 100644 (file)
@@ -824,7 +824,7 @@ const static struct
        {acpi_init_via},
 };
        
-const static struct pci_device_id acpi_pci_tbl[] __devinitdata =
+const static struct pci_device_id acpi_pci_tbl[] =
 {
        {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4},
        {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586},
index afb90ab125acac4b52cbda1beb9b7bbfda613955..53349bd0a665c002f8707e0e7d7b2ffaca047c80 100644 (file)
@@ -121,6 +121,19 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
        }
 }
 
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
 void
 pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
@@ -129,17 +142,16 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size)
        if (res->flags & IORESOURCE_IO) {
                unsigned long start = res->start;
 
-               /* We need to avoid collisions with `mirrored' VGA ports
-                  and other strange ISA hardware, so we always want the
-                  addresses kilobyte aligned.  */
                if (size > 0x100) {
                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
                               " (%ld bytes)\n", dev->slot_name,
                               dev->resource - res, size);
                }
 
-               start = (start + 1024 - 1) & ~(1024 - 1);
-               res->start = start;
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
        }
 }
 
index fc6376f142be84dccf58396e70d1c213432b86cc..cef645c3b11aaa4fa8d89905e6abcfb75d504525 100644 (file)
@@ -76,7 +76,6 @@ CONFIG_PCI_NAMES=y
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
index e9a442e43a1c35ea199ed5a3cf5d18ea42680903..85e7ace0e6566156d5ace9133040222a4de70438 100644 (file)
@@ -67,7 +67,6 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
index fc6376f142be84dccf58396e70d1c213432b86cc..cef645c3b11aaa4fa8d89905e6abcfb75d504525 100644 (file)
@@ -76,7 +76,6 @@ CONFIG_PCI_NAMES=y
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_MD_LINEAR is not set
 # CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
index 22ce0ed6d07d28e5e8029e859affb381d5083a07..b8a0b32784f2b94211cbd2693a9b1090df4df5d2 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 1994 - 1999 by Ralf Baechle and others.
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index e33a69d5ef6a546bde646ff5c5d31b24717546a7..2a8e95eb19d4094e59c50fd40a8caf72fba8f5d3 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright (C) 1994 - 1999  Ralf Baechle
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
index 9e2df36625ce28797809a81d4caf8ec3eb5504ba..7e412cb1e483b398f68727adc523bd06fe9abe34 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
index 2c0ddcc69924df87a5629ee3f078e8afc4a3066f..4ffd7f90a0d678d37b9689fec6b6a117d5ce07a6 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
+#include <linux/config.h>
 #include <linux/init.h>
 
 #include <linux/errno.h>
index 89f58c13de6e4f1516952a1a30d5f6b1c0d9e02b..74381a5e8e60aac8ff07c2a7bba3e4ec12e98818 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/pci/bridge.h>
 #include <asm/paccess.h>
 #include <asm/sn/sn0/ip27.h>
-#include <asm/sn/sn0/hubio.h>
 
 /* Check against user dumbness.  */
 #ifdef CONFIG_VT
index d5a1ed0581a54e76306a1ac6d678f7bed18c6964..7f19f5e96fd438583f4dda7131faff010a9b348c 100644 (file)
@@ -3,6 +3,7 @@
  * Copytight (C) 1999 Ralf Baechle (ralf@gnu.org)
  * Copytight (C) 1999 Silicon Graphics, Inc.
  */
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 82ed8f9ec01e4a83b230733fcf02de32287f5192..4a7c20df35af911c234be95fffffc76b69095d7d 100644 (file)
@@ -689,8 +689,8 @@ int __init scc_enet_init(void)
        cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
        cep->cur_rx = cep->rx_bd_base;
 
-       ep->sen_genscc.scc_rfcr = SCC_EB;
-       ep->sen_genscc.scc_tfcr = SCC_EB;
+       ep->sen_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+       ep->sen_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
 
        /* Set maximum bytes per receive buffer.
         * This appears to be an Ethernet frame size, not the buffer
index 9e93bcdd5428c22f67dd09e512618cdf697c34e6..c039a452c0d7c3113c88e0a0b378986faadf86e6 100644 (file)
@@ -2536,8 +2536,8 @@ int __init rs_8xx_init(void)
                                /* Set up the uart parameters in the
                                 * parameter ram.
                                 */
-                               up->smc_rfcr = SMC_EB;
-                               up->smc_tfcr = SMC_EB;
+                               up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+                               up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
 
                                /* Set this to 1 for now, so we get single
                                 * character interrupts.  Using idle charater
@@ -2579,8 +2579,8 @@ int __init rs_8xx_init(void)
                                /* Set up the uart parameters in the
                                 * parameter ram.
                                 */
-                               sup->scc_genscc.scc_rfcr = SMC_EB;
-                               sup->scc_genscc.scc_tfcr = SMC_EB;
+                               sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+                               sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
 
                                /* Set this to 1 for now, so we get single
                                 * character interrupts.  Using idle charater
@@ -2741,8 +2741,8 @@ static int __init serial_console_setup(struct console *co, char *options)
        */
        up->smc_rbase = dp_addr;        /* Base of receive buffer desc. */
        up->smc_tbase = dp_addr+sizeof(cbd_t);  /* Base of xmt buffer desc. */
-       up->smc_rfcr = SMC_EB;
-       up->smc_tfcr = SMC_EB;
+       up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
+       up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
 
        /* Set this to 1 for now, so we get single character interrupts.
        */
index caf15d27d93d8f4da7ccb0ee41addf25da81c3b5..051e964023c2df42cdae80c1cac4b239c8c307b6 100644 (file)
@@ -15,10 +15,11 @@ CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_PPC64 is not set
-# CONFIG_82xx is not set
+# CONFIG_8260 is not set
 # CONFIG_8xx is not set
 CONFIG_ALL_PPC=y
 # CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
 # CONFIG_APUS is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
@@ -159,10 +160,10 @@ CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
@@ -376,6 +377,11 @@ CONFIG_PPP=y
 #
 # CONFIG_HAMRADIO is not set
 
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
 #
 # ISDN subsystem
 #
@@ -607,6 +613,7 @@ CONFIG_SOUND=y
 CONFIG_DMASOUND_AWACS=y
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
@@ -688,3 +695,4 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
 CONFIG_XMON=y
+
index c93118bae96652f44657273fcc17c21473e299d3..a14aa41ab7456a2944bfe4ad9283f864e3ef0e0a 100644 (file)
@@ -15,10 +15,11 @@ CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_PPC64 is not set
-# CONFIG_82xx is not set
+# CONFIG_8260 is not set
 # CONFIG_8xx is not set
 CONFIG_ALL_PPC=y
 # CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
 # CONFIG_APUS is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
@@ -159,10 +160,10 @@ CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDEDMA_PCI_EXPERIMENTAL=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
@@ -376,6 +377,11 @@ CONFIG_PPP=y
 #
 # CONFIG_HAMRADIO is not set
 
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
 #
 # ISDN subsystem
 #
@@ -608,6 +614,7 @@ CONFIG_SOUND=y
 CONFIG_DMASOUND_AWACS=y
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
index a2fbe5f14f7b969c7e5b4bdfc57f128912b6fa91..e609906cb7b11220da26d1f18e1443fb65af3728 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/prom.h>
 #include <asm/gg2.h>
 #include <asm/machdep.h>
+#include <asm/init.h>
 
 #include "pci.h"
 
@@ -31,7 +32,7 @@ volatile struct Hydra *Hydra = NULL;
  * limit the bus number to 3 bits
  */
 
-int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                 unsigned char offset, unsigned char *val)
 {
        if (bus > 7) {
@@ -42,7 +43,7 @@ int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
                                 unsigned char offset, unsigned short *val)
 {
        if (bus > 7) {
@@ -54,7 +55,7 @@ int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 
-int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
                                  unsigned char offset, unsigned int *val)
 {
        if (bus > 7) {
@@ -65,7 +66,7 @@ int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
                                  unsigned char offset, unsigned char val)
 {
        if (bus > 7)
@@ -74,7 +75,7 @@ int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
                                  unsigned char offset, unsigned short val)
 {
        if (bus > 7)
@@ -83,7 +84,7 @@ int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
                                   unsigned char offset, unsigned int val)
 {
        if (bus > 7)
@@ -98,7 +99,7 @@ int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
                                 | (((o) & ~3) << 24))
 unsigned int python_busnr = 0;
 
-int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned char *val)
 {
        if (bus > python_busnr) {
@@ -110,7 +111,7 @@ int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned short *val)
 {
        if (bus > python_busnr) {
@@ -123,7 +124,7 @@ int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 
-int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned int *val)
 {
        if (bus > python_busnr) {
@@ -135,7 +136,7 @@ int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned char val)
 {
        if (bus > python_busnr)
@@ -145,7 +146,7 @@ int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned short val)
 {
        if (bus > python_busnr)
@@ -156,7 +157,7 @@ int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
                                      unsigned char offset, unsigned int val)
 {
        if (bus > python_busnr)
@@ -167,7 +168,7 @@ int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 }
 
 
-int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned char *val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
@@ -176,7 +177,7 @@ int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
                                    unsigned char offset, unsigned short *val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
@@ -186,7 +187,7 @@ int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 
-int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned int *val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
@@ -195,7 +196,7 @@ int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned char val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
@@ -204,7 +205,7 @@ int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
                                     unsigned char offset, unsigned short val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
@@ -213,7 +214,7 @@ int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_SUCCESSFUL;
 }
 
-int rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+int __chrp rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
                                      unsigned char offset, unsigned int val)
 {
        unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16);
index 3b541c26f3d208da2735eb3065c5205d969dfb08..d8c22e1a61305d7a7e4de30747698b7359decb4e 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/irq.h>
 #include <asm/hydra.h>
 #include <asm/keyboard.h>
+#include <asm/init.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -112,7 +113,7 @@ static const char *gg2_cachemodes[4] = {
        "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
 };
 
-int
+int __chrp
 chrp_get_cpuinfo(char *buffer)
 {
        int i, len, sdramen;
@@ -306,7 +307,7 @@ chrp_setup_arch(void)
        }
 }
 
-void
+void __chrp
 chrp_event_scan(void)
 {
        unsigned char log[1024];
@@ -317,7 +318,7 @@ chrp_event_scan(void)
        ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
 }
        
-void
+void __chrp
 chrp_restart(char *cmd)
 {
        printk("RTAS system-reboot returned %d\n",
@@ -325,7 +326,7 @@ chrp_restart(char *cmd)
        for (;;);
 }
 
-void
+void __chrp
 chrp_power_off(void)
 {
        /* allow power on only with power button press */
@@ -334,13 +335,13 @@ chrp_power_off(void)
        for (;;);
 }
 
-void
+void __chrp
 chrp_halt(void)
 {
        chrp_power_off();
 }
 
-u_int
+u_int __chrp
 chrp_irq_cannonicalize(u_int irq)
 {
        if (irq == 2)
@@ -353,7 +354,7 @@ chrp_irq_cannonicalize(u_int irq)
        }
 }
 
-int chrp_get_irq( struct pt_regs *regs )
+int __chrp chrp_get_irq( struct pt_regs *regs )
 {
         int irq;
 
@@ -383,7 +384,7 @@ int chrp_get_irq( struct pt_regs *regs )
        return irq;
 }
 
-void chrp_post_irq(struct pt_regs* regs, int irq)
+void __chrp chrp_post_irq(struct pt_regs* regs, int irq)
 {
        /*
         * If it's an i8259 irq then we've already done the
@@ -445,7 +446,7 @@ int chrp_ide_ports_known = 0;
 ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
 ide_ioreg_t chrp_idedma_regbase;
 
-void
+void __chrp
 chrp_ide_probe(void)
 {
         struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
@@ -460,19 +461,19 @@ chrp_ide_probe(void)
         }
 }
 
-void
+void __chrp
 chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
        ide_insw(port+_IO_BASE, buf, ns);
 }
 
-void
+void __chrp
 chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
        ide_outsw(port+_IO_BASE, buf, ns);
 }
 
-int
+int __chrp
 chrp_ide_default_irq(ide_ioreg_t base)
 {
         if (chrp_ide_ports_known == 0)
@@ -480,7 +481,7 @@ chrp_ide_default_irq(ide_ioreg_t base)
        return chrp_ide_irq;
 }
 
-ide_ioreg_t
+ide_ioreg_t __chrp
 chrp_ide_default_io_base(int index)
 {
         if (chrp_ide_ports_known == 0)
@@ -488,13 +489,13 @@ chrp_ide_default_io_base(int index)
        return chrp_ide_regbase[index];
 }
 
-int
+int __chrp
 chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
 {
         return check_region(from, extent);
 }
 
-void
+void __chrp
 chrp_ide_request_region(ide_ioreg_t from,
                        unsigned int extent,
                        const char *name)
@@ -502,20 +503,20 @@ chrp_ide_request_region(ide_ioreg_t from,
         request_region(from, extent, name);
 }
 
-void
+void __chrp
 chrp_ide_release_region(ide_ioreg_t from,
                        unsigned int extent)
 {
         release_region(from, extent);
 }
 
-void
+void __chrp
 chrp_ide_fix_driveid(struct hd_driveid *id)
 {
         ppc_generic_ide_fix_driveid(id);
 }
 
-void
+void __chrp
 chrp_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;
@@ -629,7 +630,7 @@ void __init
        if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
 }
 
-void
+void __chrp
 chrp_progress(char *s, unsigned short hex)
 {
        extern unsigned int rtas_data;
index c692b54d08b5b3cdeda2d4050e35bfcdd4bf6b66..6d275e517b34bf72a984c84abfe8aad8019d9f49 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/processor.h>
 #include <asm/nvram.h>
 #include <asm/prom.h>
+#include <asm/init.h>
 #include "time.h"
 
 static int nvram_as1 = NVRAM_AS1;
@@ -45,7 +46,7 @@ void __init chrp_time_init(void)
        nvram_data = base + 1;
 }
 
-int chrp_cmos_clock_read(int addr)
+int __chrp chrp_cmos_clock_read(int addr)
 {
        if (nvram_as1 != 0)
                outb(addr>>8, nvram_as1);
@@ -53,7 +54,7 @@ int chrp_cmos_clock_read(int addr)
        return (inb(nvram_data));
 }
 
-void chrp_cmos_clock_write(unsigned long val, int addr)
+void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
 {
        if (nvram_as1 != 0)
                outb(addr>>8, nvram_as1);
@@ -65,7 +66,7 @@ void chrp_cmos_clock_write(unsigned long val, int addr)
 /*
  * Set the hardware clock. -- Cort
  */
-int chrp_set_rtc_time(unsigned long nowtime)
+int __chrp chrp_set_rtc_time(unsigned long nowtime)
 {
        unsigned char save_control, save_freq_select;
        struct rtc_time tm;
@@ -111,7 +112,7 @@ int chrp_set_rtc_time(unsigned long nowtime)
        return 0;
 }
 
-unsigned long chrp_get_rtc_time(void)
+unsigned long __chrp chrp_get_rtc_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        int i;
index cc647a58b6187f3d7291b1b811ea526865433bed..ad467894f7aa8d8e85eb53ea7a91bd40902a32e6 100644 (file)
@@ -291,25 +291,9 @@ ret_from_intercept:
         * -- Cort
         */
        cmpi    0,r3,0
-       bne     ret_from_except
-       /*
-        * If we're returning from user mode we do things differently
-        * -- Cort
-        */
-       lwz     r3,_MSR(r1)
-       andi.   r3,r3,MSR_PR
-       beq+    10f
-       b       8f
-
+       beq     restore
        .globl  ret_from_except
 ret_from_except:
-0:     /* disable interrupts */
-       lis     r30,int_control@h
-       ori     r30,r30,int_control@l
-       lwz     r30,0(r30)
-       mtlr    r30
-       blrl
-       
        lwz     r5,_MSR(r1)
        andi.   r5,r5,MSR_EE
        beq     2f
@@ -341,65 +325,58 @@ lost_irq_ret:
        bl      do_softirq
        .globl  do_bottom_half_ret
 do_bottom_half_ret:
-2:     /* disable interrupts */        
-       lis     r30,int_control@h
-       ori     r30,r30,int_control@l
-       lwz     r30,0(r30)
-       mtlr    r30
-       blrl
-       lwz     r3,_MSR(r1)     /* Returning to user mode? */
+2:     lwz     r3,_MSR(r1)     /* Returning to user mode? */
        andi.   r3,r3,MSR_PR
-       beq+    10f             /* if so, check need_resched and signals */
+       beq+    restore         /* if so, check need_resched and signals */
+       .globl ret_to_user_hook 
+ret_to_user_hook:
+       nop
        lwz     r3,NEED_RESCHED(r2)
        cmpi    0,r3,0          /* check need_resched flag */
        beq+    7f
        bl      schedule
-       b       0b
 7:     lwz     r5,SIGPENDING(r2) /* Check for pending unblocked signals */
        cmpwi   0,r5,0
-       beq+    8f
+       beq+    restore
        li      r3,0
        addi    r4,r1,STACK_FRAME_OVERHEAD
        bl      do_signal
        .globl  do_signal_ret
 do_signal_ret:
-       b       0b
-8:     /* 
-        * We need to hard disable here even if RTL is active since
-        * being interrupted after here trashes the SPRG2
-        *  -- Cort
-        */ 
-       mfmsr   r0              /* Get current interrupt state */
-       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
-       mtmsr   r0              /* Update machine state */
-       
-       addi    r4,r1,INT_FRAME_SIZE    /* size of frame */
-       stw     r4,THREAD+KSP(r2)       /* save kernel stack pointer */
-       tophys(r3,r1)
-       mtspr   SPRG2,r3        /* phys exception stack pointer */
-       b       11f
-10:    /* make sure we hard disable here, even if rtl is active -- Cort */
-       mfmsr   r0              /* Get current interrupt state */
-       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
-       sync                    /* Some chip revs have problems here... */
-       mtmsr   r0              /* Update machine state */
-11: 
-       lwz     r2,_CTR(r1)
+restore:       
+       lwz     r3,_CTR(r1)
        lwz     r0,_LINK(r1)
-       mtctr   r2
+       mtctr   r3
        mtlr    r0
-       lwz     r2,_XER(r1)
-       lwz     r0,_CCR(r1)
-       mtspr   XER,r2
-       mtcrf   0xFF,r0
+       lwz     r3,_XER(r1)
+       mtspr   XER,r3
        REST_10GPRS(3, r1)
        REST_10GPRS(13, r1)
        REST_8GPRS(23, r1)
        REST_GPR(31, r1)
-       lwz     r2,_NIP(r1)     /* Restore environment */
+       
+       /* make sure we hard disable here, even if rtl is active, to protect
+        * SRR[01] and SPRG2 -- Cort 
+        */
+       mfmsr   r0              /* Get current interrupt state */
+       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
+       sync                    /* Some chip revs have problems here... */
+       mtmsr   r0              /* Update machine state */
+       
+       /* if returning to user mode, set new sprg2 and save kernel SP */
        lwz     r0,_MSR(r1)
-       mtspr   SRR0,r2
        mtspr   SRR1,r0
+       andi.   r0,r0,MSR_PR
+       beq+    1f
+       addi    r0,r1,INT_FRAME_SIZE    /* size of frame */
+       stw     r0,THREAD+KSP(r2)       /* save kernel stack pointer */
+       tophys(r2,r1)
+       mtspr   SPRG2,r2        /* phys exception stack pointer */
+1:     
+       lwz     r2,_CCR(r1)
+       mtcrf   0xFF,r2
+       lwz     r2,_NIP(r1)
+       mtspr   SRR0,r2
        lwz     r0,GPR0(r1)
        lwz     r2,GPR2(r1)
        lwz     r1,GPR1(r1)
index 6700806bd15950e70535ba68bfd96775525e52f1..f88c5383d2699b0fd32620e4ce8b345ba75f90aa 100644 (file)
@@ -1459,7 +1459,8 @@ start_here:
 /*
  * Set up the segment registers for a new context.
  */
-_GLOBAL(set_context)
+       .globl set_context
+set_context:   
        rlwinm  r3,r3,4,8,27    /* VSID = context << 4 */
        addis   r3,r3,0x6000    /* Set Ks, Ku bits */
        li      r0,12           /* TASK_SIZE / SEGMENT_SIZE */
index 9b7d2be314834a97591731699167b252efd8a0d4..6d7f2aff7891f2d9f91b6ca193f3a20230569ab4 100644 (file)
@@ -58,6 +58,7 @@ long long __ashrdi3(long long, int);
 long long __ashldi3(long long, int);
 long long __lshrdi3(long long, int);
 int abs(int);
+extern unsigned long ret_to_user_hook;
 
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
@@ -284,3 +285,5 @@ EXPORT_SYMBOL(debugger_sstep);
 EXPORT_SYMBOL(debugger_iabr_match);
 EXPORT_SYMBOL(debugger_dabr_match);
 EXPORT_SYMBOL(debugger_fault_handler);
+
+EXPORT_SYMBOL(ret_to_user_hook);
index fe0bfcea2a0020b2bb5016aa9eb4a7eb5ef8b141..3ccc8f51869e72db21e791b01b1bf05395a7ac6c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/ppc/kernel/ptrace.c
  *
- *  PowerPC version 
+ *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
  *  Derived from "arch/m68k/kernel/ptrace.c"
@@ -9,14 +9,14 @@
  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  *
- * Modified by Cort Dougan (cort@cs.nmt.edu) 
+ * Modified by Cort Dougan (cort@hq.fsmlabs.com)
+ * and Paul Mackerras (paulus@linuxcare.com.au).
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file README.legal in the main directory of
  * this archive for more details.
  */
 
-#include <stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -26,7 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -44,7 +44,7 @@
 /*
  * Get contents of register REGNO in task TASK.
  */
-static inline long get_reg(struct task_struct *task, int regno)
+static inline unsigned long get_reg(struct task_struct *task, int regno)
 {
        if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
                return ((unsigned long *)task->thread.regs)[regno];
@@ -64,7 +64,7 @@ static inline int put_reg(struct task_struct *task, int regno,
                ((unsigned long *)task->thread.regs)[regno] = data;
                return 0;
        }
-       return -1;
+       return -EIO;
 }
 
 static inline void
@@ -81,216 +81,10 @@ clear_single_step(struct task_struct *task)
        regs->msr &= ~MSR_SE;
 }
 
-#if 0
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- */
-static unsigned long get_long(struct task_struct * tsk, 
-       struct vm_area_struct * vma, unsigned long addr)
-{
-       pgd_t * pgdir;
-       pmd_t * pgmiddle;
-       pte_t * pgtable;
-       unsigned long page;
-
-repeat:
-       pgdir = pgd_offset(vma->vm_mm, addr);
-       if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk->mm, vma, addr, 0);
-               goto repeat;
-       }
-       if (pgd_bad(*pgdir)) {
-               printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
-               pgd_clear(pgdir);
-               return 0;
-       }
-       pgmiddle = pmd_offset(pgdir,addr);
-       if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk->mm, vma, addr, 0);
-               goto repeat;
-       }
-       if (pmd_bad(*pgmiddle)) {
-               printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
-               pmd_clear(pgmiddle);
-               return 0;
-       }
-       pgtable = pte_offset(pgmiddle, addr);
-       if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk->mm, vma, addr, 0);
-               goto repeat;
-       }
-       page = pte_page(*pgtable);
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) >= max_mapnr)
-               return 0;
-       page += addr & ~PAGE_MASK;
-       return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
-                    unsigned long addr, unsigned long data)
-{
-       pgd_t *pgdir;
-       pmd_t *pgmiddle;
-       pte_t *pgtable;
-       unsigned long page;
-               
-repeat:
-       pgdir = pgd_offset(vma->vm_mm, addr);
-       if (!pgd_present(*pgdir)) {
-               handle_mm_fault(tsk->mm, vma, addr, 1);
-               goto repeat;
-       }
-       if (pgd_bad(*pgdir)) {
-               printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
-               pgd_clear(pgdir);
-               return;
-       }
-       pgmiddle = pmd_offset(pgdir,addr);
-       if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk->mm, vma, addr, 1);
-               goto repeat;
-       }
-       if (pmd_bad(*pgmiddle)) {
-               printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
-               pmd_clear(pgmiddle);
-               return;
-       }
-       pgtable = pte_offset(pgmiddle, addr);
-       if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk->mm, vma, addr, 1);
-               goto repeat;
-       }
-       page = pte_page(*pgtable);
-       if (!pte_write(*pgtable)) {
-               handle_mm_fault(tsk->mm, vma, addr, 1);
-               goto repeat;
-       }
-/* this is a hack for non-kernel-mapped video buffers and similar */
-       if (MAP_NR(page) < max_mapnr) {
-               unsigned long phys_addr = page + (addr & ~PAGE_MASK);
-               *(unsigned long *) phys_addr = data;
-               flush_icache_range(phys_addr, phys_addr+4);
-       }
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-/* this should also re-instate whatever read-only mode there was before */
-       set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-       flush_tlb_all();
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-       unsigned long * result)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr);
-
-       if (!vma)
-               return -EIO;
-       if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               unsigned long low,high;
-               struct vm_area_struct * vma_low = vma;
-
-               if (addr + sizeof(long) >= vma->vm_end) {
-                       vma_low = vma->vm_next;
-                       if (!vma_low || vma_low->vm_start != vma->vm_end)
-                               return -EIO;
-               }
-               high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
-               low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
-               switch (addr & (sizeof(long)-1)) {
-                       case 3:
-                               low >>= 8;
-                               low |= high << 24;
-                               break;
-                       case 2:
-                               low >>= 16;
-                               low |= high << 16;
-                               break;
-                       case 1:
-                               low >>= 24;
-                               low |= high << 8;
-                               break;
-               }
-               *result = low;
-       } else
-               *result = get_long(tsk, vma,addr);
-       return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-       unsigned long data)
-{
-       struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr);
-
-       if (!vma)
-               return -EIO;
-       if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               unsigned long low,high;
-               struct vm_area_struct * vma_low = vma;
-
-               if (addr + sizeof(long) >= vma->vm_end) {
-                       vma_low = vma->vm_next;
-                       if (!vma_low || vma_low->vm_start != vma->vm_end)
-                               return -EIO;
-               }
-               high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
-               low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
-               switch (addr & (sizeof(long)-1)) {
-                       case 0: /* shouldn't happen, but safety first */
-                               high = data;
-                               break;
-                       case 3:
-                               low &= 0x000000ff;
-                               low |= data << 8;
-                               high &= ~0xff;
-                               high |= data >> 24;
-                               break;
-                       case 2:
-                               low &= 0x0000ffff;
-                               low |= data << 16;
-                               high &= ~0xffff;
-                               high |= data >> 16;
-                               break;
-                       case 1:
-                               low &= 0x00ffffff;
-                               low |= data << 24;
-                               high &= ~0xffffff;
-                               high |= data >> 8;
-                               break;
-               }
-               put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
-               put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
-       } else
-               put_long(tsk, vma,addr,data);
-       return 0;
-}
-#endif
-
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
        int ret = -EPERM;
-       unsigned long flags;
 
        lock_kernel();
        if (request == PTRACE_TRACEME) {
@@ -302,209 +96,209 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                ret = 0;
                goto out;
        }
-       if (pid == 1)           /* you may not mess with init */
-               goto out;
        ret = -ESRCH;
        read_lock(&tasklist_lock);
        child = find_task_by_pid(pid);
-       read_unlock(&tasklist_lock);    /* FIXME!!! */
-       if ( !child )
+       if (child)
+               get_task_struct(child);
+       read_unlock(&tasklist_lock);
+       if (!child)
                goto out;
+
        ret = -EPERM;
+       if (pid == 1)           /* you may not mess with init */
+               goto out_tsk;
+
        if (request == PTRACE_ATTACH) {
                if (child == current)
-                       goto out;
+                       goto out_tsk;
                if ((!child->dumpable ||
                    (current->uid != child->euid) ||
-                   (current->uid != child->uid) ||
                    (current->uid != child->suid) ||
+                   (current->uid != child->uid) ||
                    (current->gid != child->egid) ||
-                   (current->gid != child->gid) ||
                    (current->gid != child->sgid) ||
-                   (!cap_issubset(child->cap_permitted, current->cap_permitted)))
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+                   (current->gid != child->gid))
                    && !capable(CAP_SYS_PTRACE))
-                       goto out;
+                       goto out_tsk;
                /* the same process cannot be attached many times */
                if (child->flags & PF_PTRACED)
-                       goto out;
+                       goto out_tsk;
                child->flags |= PF_PTRACED;
-               
-               write_lock_irqsave(&tasklist_lock, flags);
+
+               write_lock_irq(&tasklist_lock);
                if (child->p_pptr != current) {
                        REMOVE_LINKS(child);
                        child->p_pptr = current;
                        SET_LINKS(child);
                }
-               write_unlock_irqrestore(&tasklist_lock, flags);
+               write_unlock_irq(&tasklist_lock);
 
                send_sig(SIGSTOP, child, 1);
                ret = 0;
-               goto out;
+               goto out_tsk;
        }
        ret = -ESRCH;
        if (!(child->flags & PF_PTRACED))
-               goto out;
+               goto out_tsk;
        if (child->state != TASK_STOPPED) {
                if (request != PTRACE_KILL)
-                       goto out;
+                       goto out_tsk;
        }
        if (child->p_pptr != current)
-               goto out;
+               goto out_tsk;
 
        switch (request) {
        /* when I and D space are separate, these will need to be fixed. */
-               case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-               case PTRACE_PEEKDATA: {
-                       unsigned long tmp;
-                       int copied;
+       case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+       case PTRACE_PEEKDATA: {
+               unsigned long tmp;
+               int copied;
+
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               ret = -EIO;
+               if (copied != sizeof(tmp))
+                       break;
+               ret = put_user(tmp,(unsigned long *) data);
+               break;
+       }
 
-                       copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-                       ret = -EIO;
-                       if (copied != sizeof(tmp))
-                               goto out;
-                       ret = put_user(tmp,(unsigned long *) data);
-                       goto out;
-               }
        /* read the word at location addr in the USER area. */
-               case PTRACE_PEEKUSR: {
-                       unsigned long tmp;
-                       
-                       if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
-                               ret = -EIO;
-                               goto out;
-                       }
-                       
-                       ret = verify_area(VERIFY_WRITE, (void *) data,
-                                         sizeof(long));
-                       if (ret)
-                               goto out;
-                       tmp = 0;  /* Default return condition */
-                       addr = addr >> 2; /* temporary hack. */
-                       if (addr < PT_FPR0) {
-                               tmp = get_reg(child, addr);
-                       }
-                       else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
-                               if (child->thread.regs->msr & MSR_FP)
-                                       giveup_fpu(child);
-                               tmp = ((long *)child->thread.fpr)[addr - PT_FPR0];
-                       }
-                       else
-                               ret = -EIO;
-                       if (!ret)
-                               put_user(tmp,(unsigned long *) data);
-                       goto out;
+       /* XXX this will need fixing for 64-bit */
+       case PTRACE_PEEKUSR: {
+               unsigned long index, tmp;
+
+               ret = -EIO;
+               /* convert to index and check */
+               index = (unsigned long) addr >> 2;
+               if ((addr & 3) || index > PT_FPSCR)
+                       break;
+
+               if (addr < PT_FPR0) {
+                       tmp = get_reg(child, (int) index);
+               } else {
+                       if (child->thread.regs->msr & MSR_FP)
+                               giveup_fpu(child);
+                       tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
                }
+               ret = put_user(tmp,(unsigned long *) data);
+               break;
+       }
 
-      /* If I and D space are separate, this will have to be fixed. */
-               case PTRACE_POKETEXT: /* write the word at location addr. */
-               case PTRACE_POKEDATA:
-                       ret = 0;
-                       if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-                               goto out;
-                       ret = -EIO;
-                       goto out;
-               case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-                       ret = -EIO;
-                       if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
-                               goto out;
+       /* If I and D space are separate, this will have to be fixed. */
+       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKEDATA:
+               ret = 0;
+               if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+                       break;
+               ret = -EIO;
+               break;
 
-                       addr = addr >> 2; /* temporary hack. */
-                           
-                       if (addr == PT_ORIG_R3)
-                               goto out;
-                       if (addr < PT_FPR0) {
-                               if (put_reg(child, addr, data))
-                                       goto out;
-                               ret = 0;
-                               goto out;
-                       }
-                       if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
-                               if (child->thread.regs->msr & MSR_FP)
-                                       giveup_fpu(child);
-                               ((long *)child->thread.fpr)[addr - PT_FPR0] = data;
-                               ret = 0;
-                               goto out;
-                       }
-                       goto out;
+       /* write the word at location addr in the USER area */
+       /* XXX this will need fixing for 64-bit */
+       case PTRACE_POKEUSR: {
+               unsigned long index;
 
-               case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-               case PTRACE_CONT: { /* restart after signal. */
-                       ret = -EIO;
-                       if ((unsigned long) data >= _NSIG)
-                               goto out;
-                       if (request == PTRACE_SYSCALL)
-                               child->flags |= PF_TRACESYS;
-                       else
-                               child->flags &= ~PF_TRACESYS;
-                       child->exit_code = data;
-                       wake_up_process(child);
-                       /* make sure the single step bit is not set. */
-                       clear_single_step(child);
+               ret = -EIO;
+               /* convert to index and check */
+               index = (unsigned long) addr >> 2;
+               if ((addr & 3) || index > PT_FPSCR)
+                       break;
+
+               if (addr == PT_ORIG_R3)
+                       break;
+               if (addr < PT_FPR0) {
+                       ret = put_reg(child, addr, data);
+               } else {
+                       if (child->thread.regs->msr & MSR_FP)
+                               giveup_fpu(child);
+                       ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
                        ret = 0;
-                       goto out;
                }
+               break;
+       }
+
+       case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+       case PTRACE_CONT: { /* restart after signal. */
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       break;
+               if (request == PTRACE_SYSCALL)
+                       child->flags |= PF_TRACESYS;
+               else
+                       child->flags &= ~PF_TRACESYS;
+               child->exit_code = data;
+               /* make sure the single step bit is not set. */
+               clear_single_step(child);
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
 
 /*
  * make the child exit.  Best I can do is send it a sigkill. 
  * perhaps it should be put in the status that it wants to 
  * exit.
  */
-               case PTRACE_KILL: {
-                       ret = 0;
-                       if (child->state == TASK_ZOMBIE) /* already dead */
-                               goto out;
-                       wake_up_process(child);
-                       child->exit_code = SIGKILL;
-                       /* make sure the single step bit is not set. */
-                       clear_single_step(child);
-                       goto out;
-               }
+       case PTRACE_KILL: {
+               ret = 0;
+               if (child->state == TASK_ZOMBIE)        /* already dead */
+                       break;
+               child->exit_code = SIGKILL;
+               /* make sure the single step bit is not set. */
+               clear_single_step(child);
+               wake_up_process(child);
+               break;
+       }
 
-               case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-                       ret = -EIO;
-                       if ((unsigned long) data >= _NSIG)
-                               goto out;
-                       child->flags &= ~PF_TRACESYS;
-                       set_single_step(child);
-                       child->exit_code = data;
-                       /* give it a chance to run. */
-                       wake_up_process(child);
-                       ret = 0;
-                       goto out;
-               }
+       case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       break;
+               child->flags &= ~PF_TRACESYS;
+               set_single_step(child);
+               child->exit_code = data;
+               /* give it a chance to run. */
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
 
-               case PTRACE_DETACH: { /* detach a process that was attached. */
-                       ret = -EIO;
-                       if ((unsigned long) data >= _NSIG)
-                               goto out;
-                       child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-                       wake_up_process(child);
-                       child->exit_code = data;
-                       write_lock_irqsave(&tasklist_lock, flags);
-                       REMOVE_LINKS(child);
-                       child->p_pptr = child->p_opptr;
-                       SET_LINKS(child);
-                       write_unlock_irqrestore(&tasklist_lock, flags);
-                       /* make sure the single step bit is not set. */
-                       clear_single_step(child);
-                       ret = 0;
-                       goto out;
-               }
+       case PTRACE_DETACH: { /* detach a process that was attached. */
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       break;
+               child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+               child->exit_code = data;
+               write_lock_irq(&tasklist_lock);
+               REMOVE_LINKS(child);
+               child->p_pptr = child->p_opptr;
+               SET_LINKS(child);
+               write_unlock_irq(&tasklist_lock);
+               /* make sure the single step bit is not set. */
+               clear_single_step(child);
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
 
-               default:
-                       ret = -EIO;
-                       goto out;
+       default:
+               ret = -EIO;
+               break;
        }
+out_tsk:
+       free_task_struct(child);
 out:
        unlock_kernel();
        return ret;
 }
 
-asmlinkage void syscall_trace(void)
+void syscall_trace(void)
 {
        if ((current->flags & (PF_PTRACED|PF_TRACESYS))
                        != (PF_PTRACED|PF_TRACESYS))
-               goto out;
+               return;
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
        notify_parent(current, SIGCHLD);
@@ -518,5 +312,4 @@ asmlinkage void syscall_trace(void)
                send_sig(current->exit_code, current, 1);
                current->exit_code = 0;
        }
-out:
 }
index 49a8da139370d7bdb612c2b0c89e3a2b2b55302e..67895b87dca81d03d07183fceb40e059a9676b58 100644 (file)
@@ -776,8 +776,11 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
        id->word127        = __le16_to_cpu(id->word127);
        id->dlf            = __le16_to_cpu(id->dlf);
        id->csfo           = __le16_to_cpu(id->csfo);
-       for (i = 0; i < 30; i++)
-               id->words130_159[i] = __le16_to_cpu(id->words130_159[i]);
+       for (i = 0; i < 26; i++)
+               id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+       id->word156        = __le16_to_cpu(id->word156);
+       for (i = 0; i < 4; i++)
+               id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
        for (i = 0; i < 96; i++)
                id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
 }
index b821249d9600291ad62c51e72157491405b4727c..3877d11dce291e5b94ae887aef6050ccbc68abc3 100644 (file)
 #include <asm/processor.h>
 #include <asm/nvram.h>
 #include <asm/cache.h>
-/* Fixme - Why is this here? - Corey */
-#ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
-#endif
 #include <asm/machdep.h>
 
 #include "time.h"
@@ -62,6 +59,7 @@ time_t last_rtc_update = 0;
 unsigned decrementer_count;    /* count value for 1e6/HZ microseconds */
 unsigned count_period_num;     /* 1 decrementer count equals */
 unsigned count_period_den;     /* count_period_num / count_period_den us */
+unsigned long last_tb;
 
 /*
  * timer_interrupt - gets called when the decrementer overflows,
@@ -103,6 +101,8 @@ int timer_interrupt(struct pt_regs * regs)
         */
        while ((d = get_dec()) == dval)
                ;
+       asm volatile("mftb      %0" : "=r" (last_tb) );
+       
        /*
         * Don't play catchup between the call to time_init()
         * and sti() in init/main.c.
@@ -149,20 +149,21 @@ int timer_interrupt(struct pt_regs * regs)
  */
 void do_gettimeofday(struct timeval *tv)
 {
-       unsigned long flags;
+       unsigned long flags, diff;
 
        save_flags(flags);
        cli();
        *tv = xtime;
        /* XXX we don't seem to have the decrementers synced properly yet */
 #ifndef CONFIG_SMP
-       tv->tv_usec += (decrementer_count - get_dec())
-           * count_period_num / count_period_den;
-       if (tv->tv_usec >= 1000000) {
-               tv->tv_usec -= 1000000;
-               tv->tv_sec++;
-       }
+       asm volatile("mftb %0" : "=r" (diff) );
+       diff -= last_tb;
+       
+       tv->tv_usec += diff * count_period_num / count_period_den;
+       tv->tv_sec += tv->tv_usec / 1000000;
+       tv->tv_usec = tv->tv_usec % 1000000;
 #endif
+
        restore_flags(flags);
 }
 
@@ -334,6 +335,3 @@ void to_tm(int tim, struct rtc_time * tm)
         */
        GregorianDay(tm);
 }
-
-
-
index 28a5a5035e7d88599a4d00dda414482154d4b23d..0701f7118e3425672a7bf629c7a3deb2e3c3c267 100644 (file)
@@ -91,7 +91,7 @@ MachineCheckException(struct pt_regs *regs)
        {
 #if defined(CONFIG_8xx) && defined(CONFIG_PCI)
                /* the qspan pci read routines can cause machine checks -- Cort */
-               bad_page_fault(regs,regs->dar);
+               bad_page_fault(regs, regs->dar);
                return;
 #endif
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
@@ -214,8 +214,6 @@ AlignmentException(struct pt_regs *regs)
 {
        int fixed;
 
-       if (regs->msr & MSR_FP)
-               giveup_fpu(current);
        fixed = fix_alignment(regs);
        if (fixed == 1) {
                regs->nip += 4; /* skip over emulated instruction */
@@ -223,7 +221,10 @@ AlignmentException(struct pt_regs *regs)
        }
        if (fixed == -EFAULT) {
                /* fixed == -EFAULT means the operand address was bad */
-               bad_page_fault(regs, regs->dar);
+               if (user_mode(regs))
+                       force_sig(SIGSEGV, current);
+               else
+                       bad_page_fault(regs, regs->dar);
                return;
        }
        _exception(SIGBUS, regs);       
index 9dd5d64f36cd5aca38f2898f434ff9553996317f..53611aa582f4e76102459372021a3aba496934ee 100644 (file)
@@ -28,14 +28,14 @@ ISZ = 0
 TFTPIMAGE=/tftpboot/zImage.embedded
 
 ifdef CONFIG_8xx
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000
-OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
+ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00180000
+OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o gzimage.o rdimage.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
 endif
 
 ifdef CONFIG_8260
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000
-OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o
+ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00400000
+OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o gzimage.o rdimage.o
 CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260
 endif
 
@@ -61,21 +61,32 @@ endif
 all:   zImage
 
 zvmlinux.initrd: zvmlinux
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS)
+#
+# Build the boot loader images 
+#
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o
        $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
-               --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.initrd.tmp1 zvmlinux.initrd1
-       $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \
-               -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \
-               -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \
-               -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \
-               -c -o misc.o misc.c
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+               --add-section=.gzimage=../coffboot/vmlinux.gz \
+               --set-section-flags=.gzimage=alloc,load,readonly,data \
+               gzimage.o
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .rdimage rdimage.o
        $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
-               --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.initrd.tmp $@
+               --add-section=.rdimage=ramdisk.image.gz \
+               --set-section-flags=.rdimage=alloc,load,readonly,data \
+               rdimage.o
+       $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS)
+#
+# Compute the sizes/offsets for the final image, and rebuild with these values.
+#
+       $(CC) $(CFLAGS) \
+               -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .rdimage` \
+               -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .rdimage` \
+               -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .gzimage` \
+               -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .gzimage` \
+               -c -o misc.o misc.c
+       $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@
+       $(OBJDUMP) -h $@
 
 zImage: zvmlinux
        ln -sf zvmlinux zImage
@@ -85,23 +96,27 @@ zImage.initrd: zvmlinux.initrd
 
 zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 #
-# build the boot loader image and then compute the offset into it
-# for the kernel image
+# Build the boot loader images 
 #
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.tmp $@
 #
-# then with the offset rebuild the bootloader so we know where the kernel is
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section=.gzimage=../coffboot/vmlinux.gz \
+               --set-section-flags=.gzimage=alloc,load,readonly,data \
+               gzimage.o
+       $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS)
+#
+# Compute the sizes/offsets for the final image, and rebuild with these values.
 #
-       $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
-               -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
-               -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \
+       $(CC) $(CFLAGS) \
+               -DINITRD_OFFSET=0 \
+               -DINITRD_SIZE=0 \
+               -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux .gzimage` \
+               -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux .gzimage` \
                -c -o misc.o misc.c
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.tmp $@
-       rm zvmlinux.tmp
+       $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@
+       $(OBJDUMP) -h $@
 
 znetboot : zImage
        cp zImage $(TFTPIMAGE)
index 1d76be70c5a78805095c75c4db77543e7eec4959..eca2cb764f5998f744c72467db1cab5cbafa37d1 100644 (file)
@@ -3,7 +3,7 @@
  * not have boot monitor support for board information.
  */
 #include <sys/types.h>
-#include <linux/config.h>
+#include <linux/autoconf.h>
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #endif
@@ -236,12 +236,12 @@ embed_config(bd_t *bd)
         * here for those people that may load the kernel with
         * a JTAG/COP tool and not the rom monitor.
         */
-       bd->bi_baudrate = 115200;
-       bd->bi_intfreq = 200;
-       bd->bi_busfreq = 66;
-       bd->bi_cpmfreq = 66;
-       bd->bi_brgfreq = 33;
-       bd->bi_memsize = 16 * 1024 * 1024;
+       bd->bi_baudrate = 19200;
+       bd->bi_intfreq  = 165;
+       bd->bi_busfreq  = 33;
+       bd->bi_cpmfreq  = 132;
+       bd->bi_brgfreq  = bd->bi_cpmfreq / 2; /* BRGCLK = (CPM*2/4) */
+       bd->bi_memsize  = 16 * 1024 * 1024;
 #endif
 
        cp = (u_char *)def_enet_addr;
@@ -250,3 +250,4 @@ embed_config(bd_t *bd)
        }
 }
 #endif /* EST8260 */
+
diff --git a/arch/ppc/mbxboot/gzimage.c b/arch/ppc/mbxboot/gzimage.c
new file mode 100644 (file)
index 0000000..11ce5be
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * gzimage.c
+ *
+ * Dummy file to allow a compressed zImage to be added
+ * into a linker section, accessed by the boot coode
+ */
+
+char dummy_for_gzimage;
index 79377a2ac6676ed77b73e747d09901b53d3f81e4..0895ce025961f85b67c5501d2504708d9c077f19 100644 (file)
@@ -9,10 +9,17 @@
  * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $
  *     
  * Boot loader philosophy:
+ *
  *      ROM loads us to some arbitrary location
- *      Move the boot code to the link address (8M)
+ *      ROM loads these registers:
+ *     
+ *          R3 = Pointer to the board configuration data
+ *          R5 = Pointer to Open Firmware data         
+ *                     
+ *      ROM jumps to start/start_
+ *      Move the boot code to the link address (4 MB)
  *      Call decompress_kernel()
- *         Relocate the initrd, zimage and residual data to 8M
+ *         Relocate the initrd, zimage and residual data to 4 MB
  *         Decompress the kernel to 0
  *      Jump to the kernel entry
  *            -- Cort
index 683f53491011651e41e23aa00db30b9b7d643180..d5a44df1ef95256a2bbaf7196b1dc6dfe528e548 100644 (file)
 #include <asm/mpc8260.h>
 #endif
 
+/*
+ * The following references are needed to cause the linker to pull in the
+ * gzimage.o and rdimage.o files.  These object files are special,
+ * since they get placed into the .gzimage and .rdimage ELF sections 
+ * of the zvmlinux and zvmlinux.initrd files.
+ */
+extern char dummy_for_gzimage;
+extern char dummy_for_rdimage;
+
 /*
  * Please send me load/board info and such data for hardware not
  * listed here so I can keep track since things are getting tricky
diff --git a/arch/ppc/mbxboot/rdimage.c b/arch/ppc/mbxboot/rdimage.c
new file mode 100644 (file)
index 0000000..e40fd1e
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * rdimage.c
+ *
+ * Dummy file to allow a compressed initrd to be added
+ * into a linker section, accessed by the boot coode
+ */
+
+char dummy_for_rdimage;
diff --git a/arch/ppc/mbxboot/vmlinux.lds b/arch/ppc/mbxboot/vmlinux.lds
new file mode 100644 (file)
index 0000000..2bf2c87
--- /dev/null
@@ -0,0 +1,152 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+   __DYNAMIC = 0;    */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = + SIZEOF_HEADERS;
+  .interp : { *(.interp) }
+  .hash          : { *(.hash)          }
+  .dynsym        : { *(.dynsym)                }
+  .dynstr        : { *(.dynstr)                }
+  .rel.text      : { *(.rel.text)              }
+  .rela.text     : { *(.rela.text)     }
+  .rel.data      : { *(.rel.data)              }
+  .rela.data     : { *(.rela.data)     }
+  .rel.rodata    : { *(.rel.rodata)    }
+  .rela.rodata   : { *(.rela.rodata)   }
+  .rel.got       : { *(.rel.got)               }
+  .rela.got      : { *(.rela.got)              }
+  .rel.ctors     : { *(.rel.ctors)     }
+  .rela.ctors    : { *(.rela.ctors)    }
+  .rel.dtors     : { *(.rel.dtors)     }
+  .rela.dtors    : { *(.rela.dtors)    }
+  .rel.bss       : { *(.rel.bss)               }
+  .rela.bss      : { *(.rela.bss)              }
+  .rel.plt       : { *(.rel.plt)               }
+  .rela.plt      : { *(.rela.plt)              }
+/*  .init          : { *(.init)        } =0*/
+  .plt : { *(.plt) }
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  .fixup   : { *(.fixup) }
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { 
+    *(.data.init);
+    __vtop_table_begin = .;
+    *(.vtop_fixup);
+    __vtop_table_end = .;
+    __ptov_table_begin = .;
+    *(.ptov_fixup);
+    __ptov_table_end = .;
+  }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(4096);
+  __pmac_begin = .;
+  .text.pmac : { *(.text.pmac) }
+  .data.pmac : { *(.data.pmac) }
+  . = ALIGN(4096);
+  __pmac_end = .;
+
+  . = ALIGN(4096);
+  __prep_begin = .;
+  .text.prep : { *(.text.prep) }
+  .data.prep : { *(.data.prep) }
+  . = ALIGN(4096);
+  __prep_end = .;
+
+  . = ALIGN(4096);
+  __apus_begin = .;
+  .text.apus : { *(.text.apus) }
+  .data.apus : { *(.data.apus) }
+  . = ALIGN(4096);
+  __apus_end = .;
+
+  . = ALIGN(4096);
+  __apus_begin = .;
+  .text.apus : { *(.text.apus) }
+  .data.apus : { *(.data.apus) }
+  . = ALIGN(4096);
+  __apus_end = .;
+
+  . = ALIGN(4096);
+  __openfirmware_begin = .;
+  .text.openfirmware : { *(.text.openfirmware) }
+  .data.openfirmware : { *(.data.openfirmware) }
+  . = ALIGN(4096);
+  __openfirmware_end = .;
+
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+
+  /*
+   * For loader only: Put the zImage after everything else
+   */
+  _gzstart = . ;
+  .gzimage : { *(.gzimage) }
+  _gzend   = . ;
+  
+  /*
+   * For loader only: Put the initrd after zImage
+   */
+  _rdstart = . ;
+  .rdimage : { *(.rdimage) }
+  _rdend   = . ;
+  
+}
index 076ee56e57f1ca638f12bee68d95fcd1e9948c83..7a899252faf12661f1c41ba43576d96f36d79fdd 100644 (file)
@@ -62,10 +62,21 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
 {
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
+       siginfo_t info;
+       int code = SEGV_MAPERR;
 #if defined(CONFIG_4xx)
        int is_write = error_code & ESR_DST;
 #else
        int is_write = error_code & 0x02000000;
+
+       /*
+        * Fortunately the bit assignments in SRR1 for an instruction
+        * fault and DSISR for a data fault are mostly the same for the
+        * bits we are interested in.  But there are some bits which
+        * indicate errors in DSISR but can validly be set in SRR1.
+        */
+       if (regs->trap == 0x400)
+               error_code &= 0x48200000;
 #endif /* CONFIG_4xx */
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
@@ -82,16 +93,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
 #endif /* !CONFIG_4xx */
 #endif /* CONFIG_XMON || CONFIG_KGDB */
 
-       if (in_interrupt()) {
-               static int complained;
-               if (complained < 20) {
-                       ++complained;
-                       printk("page fault in interrupt handler, addr=%lx\n",
-                              address);
-                       show_regs(regs);
-               }
-       }
-       if (current == NULL || mm == NULL) {
+       if (in_interrupt() || mm == NULL) {
                bad_page_fault(regs, address);
                return;
        }
@@ -107,10 +109,12 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                goto bad_area;
 
 good_area:
+       code = SEGV_ACCERR;
 #if defined(CONFIG_6xx)
        if (error_code & 0x95700000)
                /* an error such as lwarx to I/O controller space,
                   address matching DABR, eciwx, etc. */
+               goto bad_area;
 #endif /* CONFIG_6xx */
 #if defined(CONFIG_8xx)
         /* The MPC8xx seems to always set 0x80000000, which is
@@ -119,9 +123,8 @@ good_area:
          */
        if (error_code & 0x10000000)
                 /* Guarded storage error. */
-#endif /* CONFIG_8xx */
                goto bad_area;
-       
+#endif /* CONFIG_8xx */
        
        /* a write */
        if (is_write) {
@@ -135,8 +138,25 @@ good_area:
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       if (!handle_mm_fault(mm, vma, address, is_write))
-               goto bad_area;
+
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+        switch (handle_mm_fault(mm, vma, address, is_write)) {
+        case 1:
+                current->min_flt++;
+                break;
+        case 2:
+                current->maj_flt++;
+                break;
+        case 0:
+                goto do_sigbus;
+        default:
+                goto out_of_memory;
+       }
+
        up(&mm->mmap_sem);
        /*
         * keep track of tlb+htab misses that are good addrs but
@@ -147,22 +167,55 @@ good_area:
        return;
 
 bad_area:
-
        up(&mm->mmap_sem);
        pte_errors++;   
+
+       /* User mode accesses cause a SIGSEGV */
+       if (user_mode(regs)) {
+               info.si_signo = SIGSEGV;
+               info.si_errno = 0;
+               info.si_code = code;
+               info.si_addr = (void *) address;
+               force_sig_info(SIGSEGV, &info, current);
+               return;
+       }
+
+       bad_page_fault(regs, address);
+       return;
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", current->comm);
+       if (user_mode(regs))
+               do_exit(SIGKILL);
        bad_page_fault(regs, address);
+       return;
+
+do_sigbus:
+       up(&mm->mmap_sem);
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void *)address;
+       force_sig_info (SIGBUS, &info, current);
+       if (!user_mode(regs))
+               bad_page_fault(regs, address);
 }
 
+/*
+ * bad_page_fault is called when we have a bad access from the kernel.
+ * It is called from do_page_fault above and from some of the procedures
+ * in traps.c.
+ */
 void
 bad_page_fault(struct pt_regs *regs, unsigned long address)
 {
        unsigned long fixup;
 
-       if (user_mode(regs)) {
-               force_sig(SIGSEGV, current);
-               return;
-       }
-       
        /* Are we prepared to handle this fault?  */
        if ((fixup = search_exception_table(regs->nip)) != 0) {
                regs->nip = fixup;
index 80fb7575e7ca8f65e502c6d89f2256be323507f5..fc3acdd5c25dda4272d1883d8c9c6f0c579160f5 100644 (file)
@@ -83,6 +83,7 @@ extern char _start[], _end[];
 extern char etext[], _stext[];
 extern char __init_begin, __init_end;
 extern char __prep_begin, __prep_end;
+extern char __chrp_begin, __chrp_end;
 extern char __pmac_begin, __pmac_end;
 extern char __apus_begin, __apus_end;
 extern char __openfirmware_begin, __openfirmware_end;
@@ -777,7 +778,7 @@ void __init free_initmem(void)
        unsigned long a;
        unsigned long num_freed_pages = 0, num_prep_pages = 0,
                num_pmac_pages = 0, num_openfirmware_pages = 0,
-               num_apus_pages = 0;
+               num_apus_pages = 0, num_chrp_pages = 0;
 #define FREESEC(START,END,CNT) do { \
        a = (unsigned long)(&START); \
        for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \
@@ -794,6 +795,7 @@ void __init free_initmem(void)
        case _MACH_Pmac:
                FREESEC(__apus_begin,__apus_end,num_apus_pages);
                FREESEC(__prep_begin,__prep_end,num_prep_pages);
+               FREESEC(__chrp_begin,__chrp_end,num_chrp_pages);
                break;
        case _MACH_chrp:
                FREESEC(__apus_begin,__apus_end,num_apus_pages);
@@ -803,20 +805,24 @@ void __init free_initmem(void)
        case _MACH_prep:
                FREESEC(__apus_begin,__apus_end,num_apus_pages);
                FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
+               FREESEC(__chrp_begin,__chrp_end,num_chrp_pages);
                break;
        case _MACH_mbx:
                FREESEC(__apus_begin,__apus_end,num_apus_pages);
                FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
                FREESEC(__prep_begin,__prep_end,num_prep_pages);
+               FREESEC(__chrp_begin,__chrp_end,num_chrp_pages);
                break;
        case _MACH_apus:
                FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
                FREESEC(__prep_begin,__prep_end,num_prep_pages);
+               FREESEC(__chrp_begin,__chrp_end,num_chrp_pages);
                break;
        case _MACH_gemini:
                FREESEC(__apus_begin,__apus_end,num_apus_pages);
                FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
                FREESEC(__prep_begin,__prep_end,num_prep_pages);
+               FREESEC(__chrp_begin,__chrp_end,num_chrp_pages);
                break;
        }
 
@@ -829,6 +835,8 @@ void __init free_initmem(void)
 
        if ( num_prep_pages )
                printk(" %ldk prep", PGTOKB(num_prep_pages));
+       if ( num_chrp_pages )
+               printk(" %ldk chrp", PGTOKB(num_chrp_pages));
        if ( num_pmac_pages )
                printk(" %ldk pmac", PGTOKB(num_pmac_pages));
        if ( num_openfirmware_pages )
index 76f849bb708b5d9ce6959049a005167d01eb9607..68eb4dd3f4eeebfe6c561d2bbe5c56e093056e46 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
 
 #
 #    Copyright (c) 1998-1999 TiVo, Inc.
index e8aa24e3d1c7b1e0a564f06312b2c4a25461098f..17a6f23281b3feac681d09260d3d1413f1c63e7b 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/local/bin/perl
+#!/usr/bin/perl
 #
 #    Copyright (c) 1998-1999 TiVo, Inc.
 #      Original ELF parsing code.
@@ -332,7 +332,7 @@ require 'elf.pl';
   syswrite(OUTPUT, $ibuf, $initialOffset);
 
   if ($imageFound) {
-    $testN = pack ("I2", $bss_addr + $bss_size, $image_size);
+    $testN = pack ("N2", $bss_addr + $bss_size, $image_size);
     syswrite(OUTPUT, $testN, length($testN));
     printf("Updated symbol \"imageSect_start\" to 0x%08x\n",
           $bss_addr + $bss_size);
@@ -342,7 +342,7 @@ require 'elf.pl';
   }
 
   if ($initrdFound) {
-    $testN = pack ("I2", $bss_addr + $bss_size + $image_size, $initrd_size);
+    $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size);
     syswrite(OUTPUT, $testN, length($testN));
     printf("Updated symbol \"initrdSect_start\" to 0x%08x\n",
           $bss_addr + $bss_size + $image_size);
index 707c4ad2febf628c16ebf6813c23156d0cfa55d9..7bfdc4efbf8b21ba40c84bdaae9107d9d2588bc8 100644 (file)
@@ -103,6 +103,13 @@ SECTIONS
   . = ALIGN(4096);
   __prep_end = .;
 
+  . = ALIGN(4096);
+  __chrp_begin = .;
+  .text.chrp : { *(.text.chrp) }
+  .data.chrp : { *(.data.chrp) }
+  . = ALIGN(4096);
+  __chrp_end = .;
+
   . = ALIGN(4096);
   __apus_begin = .;
   .text.apus : { *(.text.apus) }
@@ -135,4 +142,3 @@ SECTIONS
   _end = . ;
   PROVIDE (end = .);
 }
-
index 27811e92ff42742ee0339b566de5dc37a7021df2..095a43cef8ef51d7ea25d9dd2ba1d0937c571095 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for the Acorn ethercard network device drivers
 #
 
-L_TARGET := acorn-net.a
+O_TARGET := acorn-net.o
 MOD_LIST_NAME := ACORN_NET_MODULES
 
 obj-y  :=
@@ -11,11 +11,11 @@ obj-m       :=
 obj-n  :=
 obj-   :=
 
-obj-$(CONFIG_ARM_ETHER1)       += ether1.o
-obj-$(CONFIG_ARM_ETHER3)       += ether3.o
 obj-$(CONFIG_ARM_ETHERH)       += etherh.o
+obj-$(CONFIG_ARM_ETHER3)       += ether3.o
+obj-$(CONFIG_ARM_ETHER1)       += ether1.o
 
-L_OBJS := $(obj-y)
+O_OBJS := $(obj-y)
 M_OBJS := $(obj-m)
 
 include $(TOPDIR)/Rules.make
index 65673b7f4434dfbc1e2bfd306b851cb56b26ec14..d2a5ca052ab547b4ce82bd77df6b2f7fd7b1d9a7 100644 (file)
@@ -29,6 +29,7 @@
  *                             TDR time-distance.
  * 1.05        RMK     31/12/1997      Removed calls to dev_tint for 2.1
  * 1.06        RMK     10/02/2000      Updated for 2.3.43
+ * 1.07        RMK     13/05/2000      Updated for 2.3.99-pre8
  */
 
 #include <linux/module.h>
@@ -74,7 +75,7 @@ static void ether1_setmulticastlist(struct net_device *dev);
 static void ether1_timeout(struct net_device *dev);
 
 /* ------------------------------------------------------------------------- */
-static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.06\n";
+static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
 
 #define BUS_16 16
 #define BUS_8  8
@@ -620,95 +621,6 @@ ether1_init_for_open (struct net_device *dev)
        return failures ? 1 : 0;
 }
 
-static int __init
-ether1_probe1(struct net_device *dev)
-{
-       static unsigned int version_printed = 0;
-       struct ether1_priv *priv;
-       int i;
-
-       if (!dev->priv)
-               dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL);
-
-       if (!dev->priv)
-               return 1;
-
-       priv = (struct ether1_priv *)dev->priv;
-       memset (priv, 0, sizeof (struct ether1_priv));
-
-       if ((priv->bus_type = ether1_reset (dev)) == 0) {
-               kfree (dev->priv);
-               return 1;
-       }
-
-       if (net_debug && version_printed++ == 0)
-               printk (KERN_INFO "%s", version);
-
-       request_region (dev->base_addr, 16, "ether1");
-       request_region (dev->base_addr + 0x800, 4096, "ether1(ram)");
-
-       printk (KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ",
-               dev->name, dev->base_addr, dev->irq);
-
-       for (i = 0; i < 6; i++)
-               printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
-
-       if (ether1_init_2 (dev)) {
-               kfree (dev->priv);
-               return 1;
-       }
-
-       dev->open               = ether1_open;
-       dev->stop               = ether1_close;
-       dev->hard_start_xmit    = ether1_sendpacket;
-       dev->get_stats          = ether1_getstats;
-       dev->set_multicast_list = ether1_setmulticastlist;
-       dev->tx_timeout         = ether1_timeout;
-       dev->watchdog_timeo     = 5 * HZ / 100;
-
-       /* Fill in the fields of the device structure with ethernet values */
-       ether_setup (dev);
-
-       return 0;
-}      
-    
-/* ------------------------------------------------------------------------- */
-
-static void __init
-ether1_addr(struct net_device *dev)
-{
-       int i;
-    
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = inb (IDPROM_ADDRESS + i);
-}
-
-int __init
-ether1_probe(struct net_device *dev)
-{
-#ifndef MODULE
-       struct expansion_card *ec;
-
-       if (!dev)
-               return ENODEV;
-
-       ecard_startfind ();
-       if ((ec = ecard_find (0, ether1_cids)) == NULL)
-               return ENODEV;
-
-       dev->base_addr = ecard_address (ec, ECARD_IOC, ECARD_FAST);
-       dev->irq       = ec->irq;
-
-       ecard_claim (ec);
-
-#endif
-       ether1_addr (dev);
-
-       if (ether1_probe1 (dev) == 0)
-               return 0;
-       return ENODEV;
-}
-
 /* ------------------------------------------------------------------------- */
 
 static int
@@ -1087,66 +999,118 @@ ether1_setmulticastlist (struct net_device *dev)
 
 /* ------------------------------------------------------------------------- */
 
-#ifdef MODULE
+static void __init ether1_banner(void)
+{
+       static unsigned int version_printed = 0;
 
-static struct ether_dev {
-       struct expansion_card   *ec;
-       char                    name[9];
-       struct net_device       dev;
-} ether_devs[MAX_ECARDS];
+       if (net_debug && version_printed++ == 0)
+               printk (KERN_INFO "%s", version);
+}
 
-int
-init_module (void)
+static struct net_device * __init ether1_init_one(struct expansion_card *ec)
 {
-       struct expansion_card *ec;
-       int i, ret = -ENODEV;
-
-       memset(ether_devs, 0, sizeof(ether_devs));
+       struct net_device *dev;
+       struct ether1_priv *priv;
+       int i;
 
-       ecard_startfind ();
-       ec = ecard_find(0, ether1_cids);
-       i = 0;
+       ether1_banner();
 
-       while (ec && i < MAX_ECARDS) {
-               ecard_claim(ec);
+       ecard_claim(ec);
+       
+       dev = init_etherdev(NULL, sizeof(struct ether1_priv));
+       if (!dev)
+               goto out;
 
-               ether_devs[i].ec            = ec;
-               ether_devs[i].dev.irq       = ec->irq;
-               ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-               ether_devs[i].dev.init      = ether1_probe;
-               ether_devs[i].dev.name      = ether_devs[i].name;
+       dev->base_addr  = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+       dev->irq        = ec->irq;
 
-               ret = register_netdev(&ether_devs[i].dev);
+       /*
+        * these will not fail - the nature of the bus ensures this
+        */
+       request_region(dev->base_addr, 16, dev->name);
+       request_region(dev->base_addr + 0x800, 4096, dev->name);
 
-               if (ret) {
-                       ecard_release(ec);
-                       ether_devs[i].ec = NULL;
-                       break;
-               }
+       priv = (struct ether1_priv *)dev->priv;
+       if ((priv->bus_type = ether1_reset(dev)) == 0)
+               goto free_dev;
 
-               i += 1;
-               ec = ecard_find(0, ether1_cids);
+       printk(KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ",
+               dev->name, dev->base_addr, dev->irq);
+    
+       for (i = 0; i < 6; i++) {
+               dev->dev_addr[i] = inb(IDPROM_ADDRESS + i);
+               printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);
        }
 
-       return i != 0 ? 0 : ret;
+       if (ether1_init_2(dev))
+               goto free_dev;
+
+       dev->open               = ether1_open;
+       dev->stop               = ether1_close;
+       dev->hard_start_xmit    = ether1_sendpacket;
+       dev->get_stats          = ether1_getstats;
+       dev->set_multicast_list = ether1_setmulticastlist;
+       dev->tx_timeout         = ether1_timeout;
+       dev->watchdog_timeo     = 5 * HZ / 100;
+       return 0;
+
+free_dev:
+       release_region(dev->base_addr, 16);
+       release_region(dev->base_addr + 0x800, 4096);
+       unregister_netdev(dev);
+       kfree(dev);
+out:
+       ecard_release(ec);
+       return dev;
 }
 
-void
-cleanup_module (void)
+static struct expansion_card   *e_card[MAX_ECARDS];
+static struct net_device       *e_dev[MAX_ECARDS];
+
+static int __init ether1_init(void)
 {
-       int i;
+       int i, ret = -ENODEV;
+
+       ecard_startfind();
 
        for (i = 0; i < MAX_ECARDS; i++) {
-               if (ether_devs[i].ec) {
-                       unregister_netdev(&ether_devs[i].dev);
+               struct expansion_card *ec;
+               struct net_device *dev;
 
-                       release_region(ether_devs[i].dev.base_addr, 16);
-                       release_region(ether_devs[i].dev.base_addr + 0x800, 4096);
+               ec = ecard_find(0, ether1_cids);
+               if (!ec)
+                       break;
 
-                       ecard_release(ether_devs[i].ec);
+               dev = ether1_init_one(ec);
+               if (!dev)
+                       break;
+
+               e_card[i] = ec;
+               e_dev[i]  = dev;
+               ret = 0;
+       }
+
+       return ret;
+}
 
-                       ether_devs[i].ec = NULL;
+static void __exit ether1_exit(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_ECARDS; i++) {
+               if (e_dev[i]) {
+                       unregister_netdev(e_dev[i]);
+                       release_region(e_dev[i]->base_addr, 16);
+                       release_region(e_dev[i]->base_addr + 0x800, 4096);
+                       kfree(e_dev[i]);
+                       e_dev[i] = NULL;
+               }
+               if (e_card[i]) {
+                       ecard_release(e_card[i]);
+                       e_card[i] = NULL;
                }
        }
 }
-#endif /* MODULE */
+
+module_init(ether1_init);
+module_exit(ether1_exit);
index 03cc064c4ef1ec342f26abc7d602c60bd23c264d..11e3824810c12d4e11499b90044210b21ffe1265 100644 (file)
  * 1.15        RMK     30/04/1999      More fixes to the transmit routine for buggy
  *                             hardware.
  * 1.16        RMK     10/02/2000      Updated for 2.3.43
+ * 1.17        RMK     13/05/2000      Updated for 2.3.99-pre8
  */
 
-static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.16\n";
+static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -78,7 +79,6 @@ static const card_ids __init ether3_cids[] = {
 static void    ether3_setmulticastlist(struct net_device *dev);
 static int     ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
 static void    ether3_tx(struct net_device *dev, struct dev_priv *priv);
-static int     ether3_probe1 (struct net_device *dev);
 static int     ether3_open (struct net_device *dev);
 static int     ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
 static void    ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
@@ -406,132 +406,6 @@ ether3_probe_bus_16(struct net_device *dev, int val)
        return read_val == val;
 }
 
-/*
- * This is the real probe routine.
- */
-static int __init
-ether3_probe1(struct net_device *dev)
-{
-       static unsigned version_printed = 0;
-       struct dev_priv *priv;
-       unsigned int i, bus_type, error = ENODEV;
-       const char *name = "ether3";
-
-       if (net_debug && version_printed++ == 0)
-               printk(version);
-
-       if (!dev->priv) {
-               dev->priv = kmalloc(sizeof (struct dev_priv), GFP_KERNEL);
-               if (!dev->priv) {
-                       printk(KERN_ERR "ether3_probe1: no memory\n");
-                       return -ENOMEM;
-               }
-       }
-
-       priv = (struct dev_priv *) dev->priv;
-       memset(priv, 0, sizeof(struct dev_priv));
-
-       request_region(dev->base_addr, 128, name);
-
-       /* Reset card...
-        */
-       ether3_outb(0x80, REG_CONFIG2 + 1);
-       bus_type = BUS_UNKNOWN;
-       udelay(4);
-
-       /* Test using Receive Pointer (16-bit register) to find out
-        * how the ether3 is connected to the bus...
-        */
-       if (ether3_probe_bus_8(dev, 0x100) &&
-           ether3_probe_bus_8(dev, 0x201))
-               bus_type = BUS_8;
-
-       if (bus_type == BUS_UNKNOWN &&
-           ether3_probe_bus_16(dev, 0x101) &&
-           ether3_probe_bus_16(dev, 0x201))
-               bus_type = BUS_16;
-
-       switch (bus_type) {
-       case BUS_UNKNOWN:
-               printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
-               goto failed;
-
-       case BUS_8:
-               printk(KERN_ERR "%s: %s found, but is an unsupported "
-                       "8-bit card\n", dev->name, name);
-               goto failed;
-
-       default:
-               break;
-       }
-
-       printk("%s: %s at %lx, IRQ%d, ether address ",
-               dev->name, name, dev->base_addr, dev->irq);
-       for (i = 0; i < 6; i++)
-               printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
-
-       if (ether3_init_2(dev))
-               goto failed;
-
-       dev->open               = ether3_open;
-       dev->stop               = ether3_close;
-       dev->hard_start_xmit    = ether3_sendpacket;
-       dev->get_stats          = ether3_getstats;
-       dev->set_multicast_list = ether3_setmulticastlist;
-       dev->tx_timeout         = ether3_timeout;
-       dev->watchdog_timeo     = 5 * HZ / 100;
-
-       /* Fill in the fields of the device structure with ethernet values. */
-       ether_setup(dev);
-
-       return 0;
-
-failed:
-       kfree(dev->priv);
-       dev->priv = NULL;
-       release_region(dev->base_addr, 128);
-       return error;
-}
-
-static void __init
-ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
-{
-       ecard_claim(ec);
-
-       dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
-       dev->irq = ec->irq;
-
-       if (ec->cid.manufacturer == MANU_ANT &&
-           ec->cid.product == PROD_ANT_ETHERB) {
-               dev->base_addr += 0x200;
-       }
-
-       ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
-       ec->irqmask = 0xf0;
-
-       ether3_addr(dev->dev_addr, ec);
-}
-
-#ifndef MODULE
-int __init
-ether3_probe(struct net_device *dev)
-{
-       struct expansion_card *ec;
-
-       if (!dev)
-               return ENODEV;
-
-       ecard_startfind();
-
-       if ((ec = ecard_find(0, ether3_cids)) == NULL)
-               return ENODEV;
-
-       ether3_get_dev(dev, ec);
-
-       return ether3_probe1(dev);
-}
-#endif
-
 /*
  * Open/initialize the board.  This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -903,63 +777,163 @@ ether3_tx(struct net_device *dev, struct dev_priv *priv)
        }
 }
 
-#ifdef MODULE
+static void __init ether3_banner(void)
+{
+       static unsigned version_printed = 0;
 
-static struct ether_dev {
-       struct expansion_card   *ec;
-       char                    name[9];
-       struct net_device       dev;
-} ether_devs[MAX_ECARDS];
+       if (net_debug && version_printed++ == 0)
+               printk(version);
+}
 
-int
-init_module(void)
+static const char * __init
+ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
 {
-       struct expansion_card *ec;
-       int i, ret = -ENODEV;
+       const char *name = "ether3";
+       dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+       dev->irq = ec->irq;
+
+       if (ec->cid.manufacturer == MANU_ANT &&
+           ec->cid.product == PROD_ANT_ETHERB) {
+               dev->base_addr += 0x200;
+               name = "etherb";
+       }
 
-       memset(ether_devs, 0, sizeof(ether_devs));
+       ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
+       ec->irqmask = 0xf0;
 
-       ecard_startfind ();
-       ec = ecard_find(0, ether3_cids);
-       i = 0;
+       ether3_addr(dev->dev_addr, ec);
 
-       while (ec && i < MAX_ECARDS) {
-               ecard_claim(ec);
+       return name;
+}
 
-               ether_devs[i].ec            = ec;
-               ether_devs[i].dev.init      = ether3_probe1;
-               ether_devs[i].dev.name      = ether_devs[i].name;
-               ether3_get_dev(&ether_devs[i].dev, ec);
+static struct net_device * __init ether3_init_one(struct expansion_card *ec)
+{
+       struct net_device *dev;
+       struct dev_priv *priv;
+       const char *name;
+       int i, bus_type;
 
-               ret = register_netdev(&ether_devs[i].dev);
+       ether3_banner();
 
-               if (ret) {
-                       ecard_release(ec);
-                       ether_devs[i].ec = NULL;
-               } else
-                       i += 1;
+       ecard_claim(ec);
 
-               ec = ecard_find(0, ether3_cids);
+       dev = init_etherdev(NULL, sizeof(struct dev_priv));
+       if (!dev)
+               goto out;
+
+       name = ether3_get_dev(dev, ec);
+
+       /*
+        * this will not fail - the nature of the bus ensures this
+        */
+       request_region(dev->base_addr, 128, dev->name);
+
+       priv = (struct dev_priv *) dev->priv;
+
+       /* Reset card...
+        */
+       ether3_outb(0x80, REG_CONFIG2 + 1);
+       bus_type = BUS_UNKNOWN;
+       udelay(4);
+
+       /* Test using Receive Pointer (16-bit register) to find out
+        * how the ether3 is connected to the bus...
+        */
+       if (ether3_probe_bus_8(dev, 0x100) &&
+           ether3_probe_bus_8(dev, 0x201))
+               bus_type = BUS_8;
+
+       if (bus_type == BUS_UNKNOWN &&
+           ether3_probe_bus_16(dev, 0x101) &&
+           ether3_probe_bus_16(dev, 0x201))
+               bus_type = BUS_16;
+
+       switch (bus_type) {
+       case BUS_UNKNOWN:
+               printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
+               goto failed;
+
+       case BUS_8:
+               printk(KERN_ERR "%s: %s found, but is an unsupported "
+                       "8-bit card\n", dev->name, name);
+               goto failed;
+
+       default:
+               break;
        }
 
-       return i != 0 ? 0 : ret;
+       printk("%s: %s at %lx, IRQ%d, ether address ",
+               dev->name, name, dev->base_addr, dev->irq);
+       for (i = 0; i < 6; i++)
+               printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
+
+       if (ether3_init_2(dev))
+               goto failed;
+
+       dev->open               = ether3_open;
+       dev->stop               = ether3_close;
+       dev->hard_start_xmit    = ether3_sendpacket;
+       dev->get_stats          = ether3_getstats;
+       dev->set_multicast_list = ether3_setmulticastlist;
+       dev->tx_timeout         = ether3_timeout;
+       dev->watchdog_timeo     = 5 * HZ / 100;
+       return 0;
+
+failed:
+       release_region(dev->base_addr, 128);
+       unregister_netdev(dev);
+       kfree(dev);
+out:
+       ecard_release(ec);
+       return NULL;
 }
 
-void
-cleanup_module(void)
+static struct expansion_card   *e_card[MAX_ECARDS];
+static struct net_device       *e_dev[MAX_ECARDS];
+
+static int ether3_init(void)
 {
-       int i;
+       int i, ret = -ENODEV;
+
+       ecard_startfind();
 
        for (i = 0; i < MAX_ECARDS; i++) {
-               if (ether_devs[i].ec) {
-                       unregister_netdev(&ether_devs[i].dev);
+               struct net_device *dev;
+               struct expansion_card *ec;
 
-                       release_region(ether_devs[i].dev.base_addr, 128);
+               ec = ecard_find(0, ether3_cids);
+               if (!ec)
+                       break;
 
-                       ecard_release(ether_devs[i].ec);
+               dev = ether3_init_one(ec);
+               if (!dev)
+                       break;
+
+               e_card[i] = ec;
+               e_dev[i]  = dev;
+               ret = 0;
+       }
+
+       return ret;
+}
 
-                       ether_devs[i].ec = NULL;
+static void ether3_exit(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_ECARDS; i++) {
+               if (e_dev[i]) {
+                       unregister_netdev(e_dev[i]);
+                       release_region(e_dev[i]->base_addr, 128);
+                       kfree(e_dev[i]);
+                       e_dev[i] = NULL;
+               }
+               if (e_card[i]) {
+                       ecard_release(e_card[i]);
+                       e_card[i] = NULL;
                }
        }
 }
-#endif /* MODULE */
+
+module_init(ether3_init);
+module_exit(ether3_exit);
index 71dcbbdbca1df6d417dd3bbab68bbe4b0a58f6a6..96f51c68eba67a97a85223ab4177bc8b892d32bb 100644 (file)
@@ -14,6 +14,7 @@
  *  23-11-1997 RMK     1.04    Added media autodetection
  *  16-04-1998 RMK     1.05    Improved media autodetection
  *  10-02-2000 RMK     1.06    Updated for 2.3.43
+ *  13-05-2000 RMK     1.07    Updated for 2.3.99-pre8
  *
  * Insmod Module Parameters
  * ------------------------
@@ -62,7 +63,8 @@ static const card_ids __init etherh_cids[] = {
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("i3 EtherH driver");
 
-static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.06\n";
+static char *version __initdata =
+       "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n";
 
 #define ETHERH500_DATAPORT     0x200   /* MEMC */
 #define ETHERH500_NS8390       0x000   /* MEMC */
@@ -81,34 +83,10 @@ static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King
 
 /* --------------------------------------------------------------------------- */
 
-/*
- * Read the ethernet address string from the on board rom.
- * This is an ascii string...
- */
-static int __init
-etherh_addr(char *addr, struct expansion_card *ec)
-{
-       struct in_chunk_dir cd;
-       char *s;
-       
-       if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
-               int i;
-               for (i = 0; i < 6; i++) {
-                       addr[i] = simple_strtoul(s + 1, &s, 0x10);
-                       if (*s != (i == 5? ')' : ':'))
-                               break;
-               }
-               if (i == 6)
-                       return 0;
-       }
-       return ENODEV;
-}
-
 static void
 etherh_setif(struct net_device *dev)
 {
-       unsigned long addr;
-       unsigned long flags;
+       unsigned long addr, flags;
 
        save_flags_cli(flags);
 
@@ -118,19 +96,27 @@ etherh_setif(struct net_device *dev)
        case PROD_I3_ETHERLAN600A:
                addr = dev->base_addr + EN0_RCNTHI;
 
-               if (ei_status.interface_num)    /* 10b2 */
+               switch (dev->if_port) {
+               case IF_PORT_10BASE2:
                        outb((inb(addr) & 0xf8) | 1, addr);
-               else                            /* 10bT */
+                       break;
+               case IF_PORT_10BASET:
                        outb((inb(addr) & 0xf8), addr);
+                       break;
+               }
                break;
 
        case PROD_I3_ETHERLAN500:
                addr = dev->rmem_start;
 
-               if (ei_status.interface_num)    /* 10b2 */
+               switch (dev->if_port) {
+               case IF_PORT_10BASE2:
                        outb(inb(addr) & ~ETHERH_CP_IF, addr);
-               else                            /* 10bT */
+                       break;
+               case IF_PORT_10BASET:
                        outb(inb(addr) | ETHERH_CP_IF, addr);
+                       break;
+               }
                break;
 
        default:
@@ -143,22 +129,30 @@ etherh_setif(struct net_device *dev)
 static int
 etherh_getifstat(struct net_device *dev)
 {
-       int stat;
+       int stat = 0;
 
        switch (dev->mem_end) {
        case PROD_I3_ETHERLAN600:
        case PROD_I3_ETHERLAN600A:
-               if (ei_status.interface_num)    /* 10b2 */
+               switch (dev->if_port) {
+               case IF_PORT_10BASE2:
                        stat = 1;
-               else                            /* 10bT */
+                       break;
+               case IF_PORT_10BASET:
                        stat = inb(dev->base_addr+EN0_RCNTHI) & 4;
+                       break;
+               }
                break;
 
        case PROD_I3_ETHERLAN500:
-               if (ei_status.interface_num)    /* 10b2 */
+               switch (dev->if_port) {
+               case IF_PORT_10BASE2:
                        stat = 1;
-               else                            /* 10bT */
+                       break;
+               case IF_PORT_10BASET:
                        stat = inb(dev->rmem_start) & ETHERH_CP_HEARTBEAT;
+                       break;
+               }
                break;
 
        default:
@@ -170,14 +164,54 @@ etherh_getifstat(struct net_device *dev)
 }
 
 /*
- * Reset the 8390 (hard reset)
+ * Configure the interface.  Note that we ignore the other
+ * parts of ifmap, since its mostly meaningless for this driver.
+ */
+static int etherh_set_config(struct net_device *dev, struct ifmap *map)
+{
+       switch (map->port) {
+       case IF_PORT_10BASE2:
+       case IF_PORT_10BASET:
+               /*
+                * If the user explicitly sets the interface
+                * media type, turn off automedia detection.
+                */
+               dev->flags &= ~IFF_AUTOMEDIA;
+               dev->if_port = map->port;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       etherh_setif(dev);
+
+       return 0;
+}
+
+/*
+ * Reset the 8390 (hard reset).  Note that we can't actually do this.
  */
 static void
 etherh_reset(struct net_device *dev)
 {
        outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
 
-       etherh_setif(dev);
+       /*
+        * See if we need to change the interface type.
+        * Note that we use 'interface_num' as a flag
+        * to indicate that we need to change the media.
+        */
+       if (dev->flags & IFF_AUTOMEDIA && ei_status.interface_num) {
+               ei_status.interface_num = 0;
+
+               if (dev->if_port == IF_PORT_10BASET)
+                       dev->if_port = IF_PORT_10BASE2;
+               else
+                       dev->if_port = IF_PORT_10BASET;
+
+               etherh_setif(dev);
+       }
 }
 
 /*
@@ -332,8 +366,31 @@ etherh_open(struct net_device *dev)
                return -EAGAIN;
        }
 
+       /*
+        * Make sure that we aren't going to change the
+        * media type on the next reset - we are about to
+        * do automedia manually now.
+        */
+       ei_status.interface_num = 0;
+
+       /*
+        * If we are doing automedia detection, do it now.
+        * This is more reliable than the 8390's detection.
+        */
+       if (dev->flags & IFF_AUTOMEDIA) {
+               dev->if_port = IF_PORT_10BASET;
+               etherh_setif(dev);
+               mdelay(1);
+               if (!etherh_getifstat(dev)) {
+                       dev->if_port = IF_PORT_10BASE2;
+                       etherh_setif(dev);
+               }
+       } else
+               etherh_setif(dev);
+
        etherh_reset(dev);
        ei_open(dev);
+
        return 0;
 }
 
@@ -350,281 +407,266 @@ etherh_close(struct net_device *dev)
        return 0;
 }
 
+static void etherh_irq_enable(ecard_t *ec, int irqnr)
+{
+       unsigned int ctrl_addr = (unsigned int)ec->irq_data;
+       outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr);
+}
+
+static void etherh_irq_disable(ecard_t *ec, int irqnr)
+{
+       unsigned int ctrl_addr = (unsigned int)ec->irq_data;
+       outb(inb(ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr);
+}
+
+static expansioncard_ops_t etherh_ops = {
+       etherh_irq_enable,
+       etherh_irq_disable,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
 /*
- * This is the real probe routine.
+ * Initialisation
  */
-static int __init
-etherh_probe1(struct net_device *dev)
+
+static void __init etherh_banner(void)
 {
        static int version_printed;
-       unsigned int addr, i, reg0, tmp;
-       const char *dev_type;
-       const char *if_type;
-       const char *name = "etherh";
-
-       addr = dev->base_addr;
 
        if (net_debug && version_printed++ == 0)
                printk(version);
+}
 
-       switch (dev->mem_end) {
-       case PROD_I3_ETHERLAN500:
-               dev_type = "500";
-               break;
-       case PROD_I3_ETHERLAN600:
-               dev_type = "600";
-               break;
-       case PROD_I3_ETHERLAN600A:
-               dev_type = "600A";
-               break;
-       default:
-               dev_type = "";
-       }
+static int __init etherh_check_presence(struct net_device *dev)
+{
+       unsigned int addr = dev->base_addr, reg0, tmp;
 
-       reg0 = inb (addr);
+       reg0 = inb(addr);
        if (reg0 == 0xff) {
                if (net_debug & DEBUG_INIT)
-                       printk("%s: %s error: NS8390 command register wrong\n",
-                               dev->name, name);
+                       printk("%s: etherh error: NS8390 command register wrong\n",
+                               dev->name);
                return -ENODEV;
        }
 
-       outb (E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD);
-       tmp = inb (addr + 13);
-       outb (0xff, addr + 13);
-       outb (E8390_NODMA | E8390_PAGE0, addr + E8390_CMD);
-       inb (addr + EN0_COUNTER0);
-       if (inb (addr + EN0_COUNTER0) != 0) {
+       outb(E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD);
+       tmp = inb(addr + 13);
+       outb(0xff, addr + 13);
+       outb(E8390_NODMA | E8390_PAGE0, addr + E8390_CMD);
+       inb(addr + EN0_COUNTER0);
+       if (inb(addr + EN0_COUNTER0) != 0) {
                if (net_debug & DEBUG_INIT)
-                       printk("%s: %s error: NS8390 not found\n",
-                               dev->name, name);
-               outb (reg0, addr);
-               outb (tmp, addr + 13);
+                       printk("%s: etherh error: NS8390 not found\n",
+                               dev->name);
+               outb(reg0, addr);
+               outb(tmp, addr + 13);
                return -ENODEV;
        }
 
-       if (ethdev_init(dev))
-               return -ENOMEM;
-
-       request_region(addr, 16, name);
-
-       printk("%s: %s %s at %lx, IRQ%d, ether address ",
-               dev->name, name, dev_type, dev->base_addr, dev->irq);
-
-       for (i = 0; i < 6; i++)
-               printk (i == 5 ? "%2.2x " : "%2.2x:", dev->dev_addr[i]);
-
-       ei_status.name          = name;
-       ei_status.word16        = 1;
-       ei_status.tx_start_page = ETHERH_TX_START_PAGE;
-       ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
-       ei_status.stop_page     = ETHERH_STOP_PAGE;
-       ei_status.reset_8390    = etherh_reset;
-       ei_status.block_input   = etherh_block_input;
-       ei_status.block_output  = etherh_block_output;
-       ei_status.get_8390_hdr  = etherh_get_header;
-       dev->open               = etherh_open;
-       dev->stop               = etherh_close;
-
-       /* select 10bT */
-       ei_status.interface_num = 0;
-       if_type = "10BaseT";
-       etherh_setif(dev);
-       mdelay(1);
-       if (!etherh_getifstat(dev)) {
-               if_type = "10Base2";
-               ei_status.interface_num = 1;
-               etherh_setif(dev);
-       }
-       if (!etherh_getifstat(dev))
-               if_type = "UNKNOWN";
-
-       printk("%s\n", if_type);
-
-       etherh_reset(dev);
-       NS8390_init (dev, 0);
        return 0;
 }
 
-static void etherh_irq_enable(ecard_t *ec, int irqnr)
+/*
+ * Read the ethernet address string from the on board rom.
+ * This is an ascii string...
+ */
+static int __init etherh_addr(char *addr, struct expansion_card *ec)
 {
-       unsigned int ctrl_addr = (unsigned int)ec->irq_data;
-       outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr);
+       struct in_chunk_dir cd;
+       char *s;
+       
+       if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
+               int i;
+               for (i = 0; i < 6; i++) {
+                       addr[i] = simple_strtoul(s + 1, &s, 0x10);
+                       if (*s != (i == 5? ')' : ':'))
+                               break;
+               }
+               if (i == 6)
+                       return 0;
+       }
+       return ENODEV;
 }
 
-static void etherh_irq_disable(ecard_t *ec, int irqnr)
+static struct net_device * __init etherh_init_one(struct expansion_card *ec)
 {
-       unsigned int ctrl_addr = (unsigned int)ec->irq_data;
-       outb(inb(ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr);
-}
+       struct net_device *dev;
+       const char *dev_type;
+       int i;
 
-static expansioncard_ops_t etherh_ops = {
-       etherh_irq_enable,
-       etherh_irq_disable,
-       NULL,
-       NULL,
-       NULL,
-       NULL
-};
+       etherh_banner();
 
-static void __init
-etherh_initdev(ecard_t *ec, struct net_device *dev)
-{
-       ecard_claim (ec);
+       ecard_claim(ec);
        
-       dev->irq = ec->irq;
-       dev->mem_end = ec->cid.product;
+       dev = init_etherdev(NULL, 0);
+       if (!dev)
+               goto out;
+
+       etherh_addr(dev->dev_addr, ec);
+
+       dev->open       = etherh_open;
+       dev->stop       = etherh_close;
+       dev->set_config = etherh_set_config;
+       dev->irq        = ec->irq;
+       dev->base_addr  = ecard_address(ec, ECARD_MEMC, 0);
+       dev->mem_end    = ec->cid.product;
+       ec->ops         = &etherh_ops;
 
        switch (ec->cid.product) {
        case PROD_I3_ETHERLAN500:
-               dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH500_NS8390;
-               dev->mem_start = dev->base_addr + ETHERH500_DATAPORT;
+               dev->base_addr += ETHERH500_NS8390;
+               dev->mem_start  = dev->base_addr + ETHERH500_DATAPORT;
                dev->rmem_start = (unsigned long)
-               ec->irq_data   = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST)
+               ec->irq_data    = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST)
                                  + ETHERH500_CTRLPORT;
                break;
 
        case PROD_I3_ETHERLAN600:
        case PROD_I3_ETHERLAN600A:
-               dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH600_NS8390;
+               dev->base_addr += ETHERH600_NS8390;
                dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
-               ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT);
+               ec->irq_data   = (void *)(dev->base_addr + ETHERH600_CTRLPORT);
                break;
 
        default:
-               printk ("%s: etherh error: unknown card type\n", dev->name);
+               printk("%s: etherh error: unknown card type %x\n",
+                      dev->name, ec->cid.product);
+               goto out;
        }
-       ec->ops = &etherh_ops;
 
-       etherh_addr(dev->dev_addr, ec);
-}
+       if (!request_region(dev->base_addr, 16, dev->name))
+               goto region_not_free;
 
-#ifndef MODULE
-int __init
-etherh_probe(struct net_device *dev)
-{
-       if (!dev)
-               return ENODEV;
+       if (etherh_check_presence(dev) || ethdev_init(dev))
+               goto release;
 
-       if (!dev->base_addr || dev->base_addr == 0xffe0) {
-               struct expansion_card *ec;
+       switch (ec->cid.product) {
+       case PROD_I3_ETHERLAN500:
+               dev_type = "500";
+               break;
 
-               ecard_startfind();
+       case PROD_I3_ETHERLAN600:
+               dev_type = "600";
+               break;
 
-               if ((ec = ecard_find (0, etherh_cids)) == NULL)
-                       return ENODEV;
+       case PROD_I3_ETHERLAN600A:
+               dev_type = "600A";
+               break;
 
-               etherh_initdev(ec, dev);
+       default:
+               dev_type = "unknown";
+               break;
        }
-       return etherh_probe1(dev);
-}
-#endif
 
-#ifdef MODULE
-#define MAX_ETHERH_CARDS 2
+       printk("%s: etherh %s at %lx, IRQ%d, ether address ",
+               dev->name, dev_type, dev->base_addr, dev->irq);
 
-static int io[MAX_ETHERH_CARDS];
-static int irq[MAX_ETHERH_CARDS];
-static char ethernames[MAX_ETHERH_CARDS][9];
-static struct net_device *my_ethers[MAX_ETHERH_CARDS];
-static struct expansion_card *ec[MAX_ETHERH_CARDS];
+       for (i = 0; i < 6; i++)
+               printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]);
 
-static int
-init_all_cards(void)
-{
-       struct net_device *dev = NULL;
-       int i, found = 0;
+       /*
+        * Unfortunately, ethdev_init eventually calls
+        * ether_setup, which re-writes dev->flags.
+        */
+       switch (ec->cid.product) {
+       case PROD_I3_ETHERLAN500:
+               dev->if_port   = IF_PORT_UNKNOWN;
+               break;
 
-       for (i = 0; i < MAX_ETHERH_CARDS; i++) {
-               my_ethers[i] = NULL;
-               ec[i] = NULL;
-               strcpy (ethernames[i], "        ");
+       case PROD_I3_ETHERLAN600:
+       case PROD_I3_ETHERLAN600A:
+               dev->flags    |= IFF_PORTSEL | IFF_AUTOMEDIA;
+               dev->if_port   = IF_PORT_10BASET;
+               break;
        }
 
-       ecard_startfind();
-
-       for (i = 0; i < MAX_ETHERH_CARDS; i++) {
-               if (!dev)
-                       dev = (struct net_device *)kmalloc (sizeof (struct net_device), GFP_KERNEL);
-               if (dev)
-                       memset (dev, 0, sizeof (struct net_device));
-
-               if (!io[i]) {
-                       if ((ec[i] = ecard_find (0, etherh_cids)) == NULL)
-                               continue;
-
-                       if (!dev)
-                               return -ENOMEM;
-
-                       etherh_initdev (ec[i], dev);
-               } else {
-                       ec[i] = NULL;
-                       if (!dev)
-                               return -ENOMEM;
-                       dev->base_addr = io[i];
-                       dev->irq = irq[i];
-               }
-
-               dev->init = etherh_probe1;
-               dev->name = ethernames[i];
+       ei_status.name          = dev->name;
+       ei_status.word16        = 1;
+       ei_status.tx_start_page = ETHERH_TX_START_PAGE;
+       ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES;
+       ei_status.stop_page     = ETHERH_STOP_PAGE;
 
-               my_ethers[i] = dev;
+       ei_status.reset_8390    = etherh_reset;
+       ei_status.block_input   = etherh_block_input;
+       ei_status.block_output  = etherh_block_output;
+       ei_status.get_8390_hdr  = etherh_get_header;
+       ei_status.interface_num = 0;
 
-               if (register_netdev(dev) != 0) {
-                       printk(KERN_ERR "No etherh card found at %08lX\n",
-                               dev->base_addr);
-                       if (ec[i]) {
-                               ecard_release(ec[i]);
-                               ec[i] = NULL;
-                       }
-                       continue;
-               }
-               found ++;
-               dev = NULL;
-       }
+       etherh_reset(dev);
+       NS8390_init(dev, 0);
+       return dev;
+
+release:
+       release_region(dev->base_addr, 16);
+region_not_free:
+       unregister_netdev(dev);
+       kfree(dev);
+out:
+       ecard_release(ec);
+       return NULL;
+}
 
-       if (dev)
-               kfree (dev);
+#define MAX_ETHERH_CARDS 2
 
-       return found ? 0 : -ENODEV;
-}
+static struct net_device *e_dev[MAX_ETHERH_CARDS];
+static struct expansion_card *e_card[MAX_ETHERH_CARDS];
 
-int
-init_module(void)
+static int __init etherh_init(void)
 {
-       int ret;
+       int i, ret = -ENODEV;
 
-       if (load_8390_module(__FILE__))
+       if (load_8390_module("etherh.c"))
                return -ENOSYS;
 
        lock_8390_module();
 
-       ret = init_all_cards();
+       ecard_startfind();
 
-       if (ret) {
-               unlock_8390_module();
+       for (i = 0; i < MAX_ECARDS; i++) {
+               struct expansion_card *ec;
+               struct net_device *dev;
+
+               ec = ecard_find(0, etherh_cids);
+               if (!ec)
+                       break;
+
+               dev = etherh_init_one(ec);
+               if (!dev)
+                       break;
+
+               e_card[i] = ec;
+               e_dev[i]  = dev;
+               ret = 0;
        }
 
+       if (ret)
+               unlock_8390_module();
+
        return ret;
 }
 
-void
-cleanup_module(void)
+static void __exit etherh_exit(void)
 {
        int i;
+
        for (i = 0; i < MAX_ETHERH_CARDS; i++) {
-               if (my_ethers[i]) {
-                       unregister_netdev(my_ethers[i]);
-                       release_region (my_ethers[i]->base_addr, 16);
-                       kfree (my_ethers[i]);
-                       my_ethers[i] = NULL;
+               if (e_dev[i]) {
+                       unregister_netdev(e_dev[i]);
+                       release_region(e_dev[i]->base_addr, 16);
+                       kfree(e_dev[i]);
+                       e_dev[i] = NULL;
                }
-               if (ec[i]) {
-                       ec[i]->ops = NULL;
-                       ecard_release(ec[i]);
-                       ec[i] = NULL;
+               if (e_card[i]) {
+                       e_card[i]->ops = NULL;
+                       ecard_release(e_card[i]);
+                       e_card[i] = NULL;
                }
        }
        unlock_8390_module();
 }
-#endif /* MODULE */
+
+module_init(etherh_init);
+module_exit(etherh_exit);
index 679545b7c71623f5647c15c9d6e4c38581c0969c..37f0669d6dbee20274d907d6c6736a636673d310 100644 (file)
@@ -49,10 +49,12 @@ fi
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 dep_tristate '  Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD
 dep_tristate '  RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD
-bool         '   DANGEROUS! RAID1/RAID5 code' CONFIG_RAID15_DANGEROUS
-if [ "$CONFIG_RAID15_DANGEROUS" = "y" ]; then
- dep_tristate '    RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD
- dep_tristate '    RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool '    RAID-1/RAID-5 code (DANGEROUS)' CONFIG_RAID15_DANGEROUS
+  if [ "$CONFIG_RAID15_DANGEROUS" = "y" ]; then
+    dep_tristate '      RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD
+    dep_tristate '      RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
+  fi
 fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
index 8254d0a7aa8ca72abe62295df0f5226dc31a1d62..64c70e33a5d8086975b535cd803c4ca49e727a5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/kernel/floppy.c
+ *  linux/drivers/block/floppy.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1993, 1994  Alain Knaff
  * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
  * features to asm/floppy.h.
  */
+
+/*
+ * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
+ * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
+ * use of '0' for NULL.
+ */
  
 /*
  * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
 /* do print messages for unexpected interrupts */
 static int print_unex=1;
 #include <linux/module.h>
-
-/* the following is the mask of allowed drives. By default units 2 and
- * 3 of both floppy controllers are disabled, because switching on the
- * motor of these drives causes system hangs on some PCI computers. drive
- * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
- * a drive is allowed. */
-static int FLOPPY_IRQ=6;
-static int FLOPPY_DMA=2;
-static int allowed_drive_mask = 0x33;
-static int irqdma_allocated = 0;
-
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -177,6 +170,8 @@ static int slow_floppy = 0;
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+static int FLOPPY_IRQ=6;
+static int FLOPPY_DMA=2;
 static int can_use_virtual_dma=2;
 /* =======
  * can use virtual DMA:
@@ -186,7 +181,7 @@ static int can_use_virtual_dma=2;
  * but fall back on virtual DMA when not enough memory available
  */
 
-static int use_virtual_dma=0;
+static int use_virtual_dma;
 /* =======
  * use virtual DMA
  * 0 using hard DMA
@@ -207,6 +202,14 @@ static devfs_handle_t devfs_handle = NULL;
 #define K_64   0x10000         /* 64KB */
 #include <asm/floppy.h>
 
+/* the following is the mask of allowed drives. By default units 2 and
+ * 3 of both floppy controllers are disabled, because switching on the
+ * motor of these drives causes system hangs on some PCI computers. drive
+ * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
+ * a drive is allowed. */
+
+static int allowed_drive_mask = 0x33;
+static int irqdma_allocated = 0;
 
 #define MAJOR_NR FLOPPY_MAJOR
 
@@ -231,9 +234,9 @@ static devfs_handle_t devfs_handle = NULL;
 static inline void fallback_on_nodma_alloc(char **addr, size_t l)
 {
 #ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
-       if(*addr)
+       if (*addr)
                return; /* we have the memory */
-       if(can_use_virtual_dma != 2)
+       if (can_use_virtual_dma != 2)
                return; /* no fallback allowed */
        printk("DMA memory shortage. Temporarily falling back on virtual DMA\n");
        *addr = (char *) nodma_mem_alloc(l);
@@ -393,6 +396,16 @@ static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
  * 'options'.  Other parameters should be self-explanatory (see also
  * setfdprm(8)).
  */
+/*
+           Size
+            |  Sectors per track
+            |  | Head
+            |  | |  Tracks
+            |  | |  | Stretch
+            |  | |  | |  Gap 1 size
+            |  | |  | |    |  Data rate, | 0x40 for perp
+            |  | |  | |    |    |  Spec1 (stepping rate, head unload
+            |  | |  | |    |    |    |    /fmt gap (gap2) */
 static struct floppy_struct floppy_type[32] = {
        {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    }, /*  0 no testing    */
        {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
@@ -403,7 +416,7 @@ static struct floppy_struct floppy_type[32] = {
        { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  }, /*  6 720KB AT      */
        { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /*  7 1.44MB 3.5"   */
        { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /*  8 2.88MB 3.5"   */
-       { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120"},  /*  9 3.12MB 3.5"   */
+       { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /*  9 3.12MB 3.5"   */
 
        { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */
        { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */
@@ -491,8 +504,8 @@ static struct format_descr format_req;
  * not contain a 64k byte boundary crossing, or data will be
  * corrupted/lost.
  */
-static char *floppy_track_buffer=0;
-static int max_buffer_sectors=0;
+static char *floppy_track_buffer;
+static int max_buffer_sectors;
 
 static int *errors;
 typedef void (*done_f)(int);
@@ -503,7 +516,7 @@ static struct cont_t {
        void (*error)(void); /* this is called to tally an error */
        done_f done; /* this is called to say if the operation has 
                      * succeeded/failed */
-} *cont=NULL;
+} *cont;
 
 static void floppy_ready(void);
 static void floppy_start(void);
@@ -551,14 +564,13 @@ static struct floppy_struct *_floppy = floppy_type;
 static unsigned char current_drive = 0;
 static long current_count_sectors = 0;
 static unsigned char sector_t; /* sector in track */
-static unsigned char in_sector_offset; /* offset within physical sector,
-                                                                               * expressed in units of 512 bytes */
+static unsigned char in_sector_offset; /* offset within physical sector,
+                                        * expressed in units of 512 bytes */
 
 #ifndef fd_eject
 #define fd_eject(x) -EINVAL
 #endif
 
-
 #ifdef DEBUGT
 static long unsigned debugtimer;
 #endif
@@ -602,10 +614,10 @@ static void is_alive(const char *message)
 #define OLOGSIZE 20
 
 static void (*lasthandler)(void) = NULL;
-static unsigned long interruptjiffies=0;
-static unsigned long resultjiffies=0;
-static int resultsize=0;
-static unsigned long lastredo=0;
+static unsigned long interruptjiffies;
+static unsigned long resultjiffies;
+static int resultsize;
+static unsigned long lastredo;
 
 static struct output_log {
        unsigned char data;
@@ -613,7 +625,7 @@ static struct output_log {
        unsigned long jiffies;
 } output_log[OLOGSIZE];
 
-static int output_log_pos=0;
+static int output_log_pos;
 #endif
 
 #define CURRENTD -1
@@ -640,7 +652,7 @@ static void reschedule_timeout(int drive, const char *message, int marg)
 
 static int maximum(int a, int b)
 {
-       if(a > b)
+       if (a > b)
                return a;
        else
                return b;
@@ -649,7 +661,7 @@ static int maximum(int a, int b)
 
 static int minimum(int a, int b)
 {
-       if(a < b)
+       if (a < b)
                return a;
        else
                return b;
@@ -697,11 +709,11 @@ static int disk_change(int drive)
        if (jiffies - UDRS->select_date < UDP->select_delay)
                DPRINT("WARNING disk change called early\n");
        if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
-          (FDCS->dor & 3) != UNIT(drive) ||
-          fdc != FDC(drive)){
+           (FDCS->dor & 3) != UNIT(drive) ||
+           fdc != FDC(drive)){
                DPRINT("probing disk change on unselected drive\n");
                DPRINT("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),
-                       FDCS->dor);
+                       (unsigned int)FDCS->dor);
        }
 #endif
 
@@ -791,7 +803,7 @@ static void twaddle(void)
 {
        if (DP->select_delay)
                return;
-       fd_outb(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
+       fd_outb(FDCS->dor & ~(0x10<<UNIT(current_drive)), FD_DOR);
        fd_outb(FDCS->dor, FD_DOR);
        DRS->select_date = jiffies;
 }
@@ -1034,7 +1046,7 @@ static int wait_for_completion(unsigned long delay, timeout_fn function)
 }
 
 static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED;
-static int hlt_disabled=0;
+static int hlt_disabled;
 static void floppy_disable_hlt(void)
 {
        unsigned long flags;
@@ -1090,7 +1102,7 @@ static void setup_DMA(void)
        f=claim_dma_lock();
        fd_disable_dma();
 #ifdef fd_dma_setup
-       if(fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, 
+       if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, 
                        (raw_cmd->flags & FD_RAW_READ)?
                        DMA_MODE_READ : DMA_MODE_WRITE,
                        FDCS->address) < 0) {
@@ -1120,7 +1132,7 @@ static void show_floppy(void);
 static int wait_til_ready(void)
 {
        int counter, status;
-       if(FDCS->reset)
+       if (FDCS->reset)
                return -1;
        for (counter = 0; counter < 10000; counter++) {
                status = fd_inb(FD_STATUS);             
@@ -1184,7 +1196,7 @@ static int result(void)
                else
                        break;
        }
-       if(!initialising) {
+       if (!initialising) {
                DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
                       fdc, status, i);
                show_floppy();
@@ -1198,7 +1210,7 @@ static int result(void)
 static int need_more_output(void)
 {
        int status;
-       if(status = wait_til_ready()) < 0)
+       if ((status = wait_til_ready()) < 0)
                return -1;
        if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY)
                return MORE_OUTPUT;
@@ -1249,7 +1261,7 @@ static int fdc_configure(void)
 {
        /* Turn on FIFO */
        output_byte(FD_CONFIGURE);
-       if(need_more_output() != MORE_OUTPUT)
+       if (need_more_output() != MORE_OUTPUT)
                return 0;
        output_byte(0);
        output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
@@ -1304,7 +1316,7 @@ static void fdc_specify(void)
                                /* chose the default rate table, not the one
                                 * where 1 = 2 Mbps */
                                output_byte(FD_DRIVESPEC);
-                               if(need_more_output() == MORE_OUTPUT) {
+                               if (need_more_output() == MORE_OUTPUT) {
                                        output_byte(UNIT(current_drive));
                                        output_byte(0xc0);
                                }
@@ -1745,14 +1757,14 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        do_print = !handler && print_unex && !initialising;
 
        inr = result();
-       if(do_print)
+       if (do_print)
                print_result("unexpected interrupt", inr);
        if (inr == 0){
                int max_sensei = 4;
                do {
                        output_byte(FD_SENSEI);
                        inr = result();
-                       if(do_print)
+                       if (do_print)
                                print_result("sensei", inr);
                        max_sensei--;
                } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei);
@@ -2325,31 +2337,31 @@ static void rw_interrupt(void)
        nr_sectors = 0;
        CODE2SIZE;
 
-       if(ST1 & ST1_EOC)
+       if (ST1 & ST1_EOC)
                eoc = 1;
        else
                eoc = 0;
 
-       if(COMMAND & 0x80)
+       if (COMMAND & 0x80)
                heads = 2;
        else
                heads = 1;
 
-       nr_sectors = (((R_TRACK-TRACK) * heads + 
+       nr_sectors = (((R_TRACK-TRACK) * heads +
                                   R_HEAD-HEAD) * SECT_PER_TRACK +
-                                 R_SECTOR-SECTOR + eoc) << SIZECODE >> 2;
+                                  R_SECTOR-SECTOR + eoc) << SIZECODE >> 2;
 
 #ifdef FLOPPY_SANITY_CHECK
        if (nr_sectors / ssize > 
-               (in_sector_offset + current_count_sectors + ssize - 1)/ssize) {
+               (in_sector_offset + current_count_sectors + ssize - 1) / ssize) {
                DPRINT("long rw: %x instead of %lx\n",
                        nr_sectors, current_count_sectors);
                printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
                printk("rh=%d h=%d\n", R_HEAD, HEAD);
                printk("rt=%d t=%d\n", R_TRACK, TRACK);
                printk("heads=%d eoc=%d\n", heads, eoc);
-               printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, 
-                          sector_t, ssize);
+               printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
+                      sector_t, ssize);
                printk("in_sector_offset=%d\n", in_sector_offset);
        }
 #endif
@@ -2547,22 +2559,24 @@ static inline int check_dma_crossing(char *start,
  * does not work with MT, hence we can only transfer one head at
  * a time
  */
-static void virtualdmabug_workaround(void) {
+static void virtualdmabug_workaround(void)
+{
        int hard_sectors, end_sector;
+
        if(CT(COMMAND) == FD_WRITE) {
                COMMAND &= ~0x80; /* switch off multiple track mode */
-          
+
                hard_sectors = raw_cmd->length >> (7 + SIZECODE);
                end_sector = SECTOR + hard_sectors - 1;
 #ifdef FLOPPY_SANITY_CHECK
                if(end_sector > SECT_PER_TRACK) {
-                       printk("too many sectors %d > %d\n", 
-                                  end_sector, SECT_PER_TRACK);
+                       printk("too many sectors %d > %d\n",
+                              end_sector, SECT_PER_TRACK);
                        return;
                }
 #endif
                SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points
-                                                                         * to end of transfer */
+                                             * to end of transfer */
        }
 }
 
@@ -2603,7 +2617,7 @@ static int make_raw_rw_request(void)
        TRACK = CURRENT->sector / max_sector;
        sector_t = CURRENT->sector % max_sector;
        if (_floppy->track && TRACK >= _floppy->track) {
-               if(CURRENT->current_nr_sectors & 1) {
+               if (CURRENT->current_nr_sectors & 1) {
                        current_count_sectors = 1;
                        return 1;
                } else
@@ -2935,7 +2949,7 @@ static void process_fd_request(void)
 
 static void do_fd_request(request_queue_t * q)
 {
-       if(usage_count == 0) {
+       if (usage_count == 0) {
                printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT);
                printk("sect=%ld cmd=%d\n", CURRENT->sector, CURRENT->cmd);
                return;
@@ -3057,7 +3071,7 @@ static void raw_cmd_done(int flag)
                raw_cmd->flags |= FD_RAW_HARDFAILURE;
        } else {
                raw_cmd->reply_count = inr;
-               if(raw_cmd->reply_count > MAX_REPLIES)
+               if (raw_cmd->reply_count > MAX_REPLIES)
                        raw_cmd->reply_count=0;
                for (i=0; i< raw_cmd->reply_count; i++)
                        raw_cmd->reply[i] = reply_buffer[i];
@@ -3382,7 +3396,7 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
                process_fd_request();           
                *g = current_type[drive];
        }
-       if(!*g)
+       if (!*g)
                return -ENODEV;
        return 0;
 }
@@ -3420,8 +3434,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        /* convert compatibility eject ioctls into floppy eject ioctl.
         * We do this in order to provide a means to eject floppy disks before
         * installing the new fdutils package */
-       if(cmd == CDROMEJECT || /* CD-ROM eject */
-          cmd == 0x6470 /* SunOS floppy eject */) {
+       if (cmd == CDROMEJECT || /* CD-ROM eject */
+           cmd == 0x6470 /* SunOS floppy eject */) {
                DPRINT("obsolete eject ioctl\n");
                DPRINT("please use floppycontrol --eject\n");
                cmd = FDEJECT;
@@ -3467,7 +3481,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 
        switch (cmd) {
                case FDEJECT:
-                       if(UDRS->fd_ref != 1)
+                       if (UDRS->fd_ref != 1)
                                /* somebody else has this drive open */
                                return -EBUSY;
                        LOCK_FDC(drive,1);
@@ -3508,9 +3522,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        CALL(poll_drive(1, FD_RAW_NEED_DISK));
                        ret = UDRS->flags;
                        process_fd_request();
-                       if(ret & FD_VERIFY)
+                       if (ret & FD_VERIFY)
                                return -ENODEV;
-                       if(!(ret & FD_DISK_WRITABLE))
+                       if (!(ret & FD_DISK_WRITABLE))
                                return -EROFS;
                        return 0;
                case FDFMTTRK:
@@ -3705,7 +3719,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
                        INFBOUND(try, 16);
                        tmp= (char *)fd_dma_mem_alloc(1024*try);
                }
-               if(!tmp &&  !floppy_track_buffer) {
+               if (!tmp && !floppy_track_buffer) {
                        fallback_on_nodma_alloc(&tmp, 2048 * try);
                }
                if (!tmp && !floppy_track_buffer) {
@@ -3713,7 +3727,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
                        RETERR(ENXIO);
                }
                if (floppy_track_buffer) {
-                       if(tmp)
+                       if (tmp)
                                fd_dma_mem_free((unsigned long)tmp,try*1024);
                } else {
                        buffer_min = buffer_max = -1;
@@ -3787,9 +3801,9 @@ static int floppy_revalidate(kdev_t dev)
        int cf;
 
        if (UTESTF(FD_DISK_CHANGED) ||
-          UTESTF(FD_VERIFY) ||
-          test_bit(drive, &fake_change) ||
-          NO_GEOM){
+           UTESTF(FD_VERIFY) ||
+           test_bit(drive, &fake_change) ||
+           NO_GEOM){
                lock_fdc(drive,0);
                cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
                if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)){
@@ -3892,13 +3906,13 @@ static char __init get_fdc_version(void)
                return FDC_UNKNOWN;
        }
 
-       if(!fdc_configure()) {
+       if (!fdc_configure()) {
                printk(KERN_INFO "FDC %d is an 82072\n",fdc);
                return FDC_82072;       /* 82072 doesn't know CONFIGURE */
        }
 
        output_byte(FD_PERPENDICULAR);
-       if(need_more_output() == MORE_OUTPUT) {
+       if (need_more_output() == MORE_OUTPUT) {
                output_byte(0);
        } else {
                printk(KERN_INFO "FDC %d is an 82072A\n", fdc);
@@ -4037,7 +4051,8 @@ static struct param_table {
 
        { "unexpected_interrupts", 0, &print_unex, 1, 0 },
        { "no_unexpected_interrupts", 0, &print_unex, 0, 0 },
-       { "L40SX", 0, &print_unex, 0, 0 } };
+       { "L40SX", 0, &print_unex, 0, 0 }
+};
 
 static int __init floppy_setup(char *str)
 {
@@ -4053,11 +4068,11 @@ static int __init floppy_setup(char *str)
                                        param = ints[1];
                                else
                                        param = config_params[i].def_param;
-                               if(config_params[i].fn)
+                               if (config_params[i].fn)
                                        config_params[i].
                                                fn(ints,param,
                                                   config_params[i].param2);
-                               if(config_params[i].var) {
+                               if (config_params[i].var) {
                                        DPRINT("%s=%d\n", str, param);
                                        *config_params[i].var = param;
                                }
@@ -4086,7 +4101,7 @@ int __init floppy_init(void)
        int i,unit,drive;
 
 
-       raw_cmd = 0;
+       raw_cmd = NULL;
 
        devfs_handle = devfs_mk_dir (NULL, "floppy", 0, NULL);
        if (devfs_register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
@@ -4174,7 +4189,7 @@ int __init floppy_init(void)
                        FDCS->address = -1;
                        continue;
                }
-               if(can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
+               if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
                        can_use_virtual_dma = 0;
 
                have_no_fdc = 0;
@@ -4192,13 +4207,13 @@ int __init floppy_init(void)
        if (have_no_fdc) 
        {
                DPRINT("no floppy controllers found\n");
-               floppy_tq.routine = (void *)(void *) empty;
+               floppy_tq.routine = (void *)(void *) empty;
                mark_bh(IMMEDIATE_BH);
                schedule();
-               if (usage_count)
-                       floppy_release_irq_and_dma();
+               if (usage_count)
+                       floppy_release_irq_and_dma();
                blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-               devfs_unregister_blkdev(MAJOR_NR,"fd");         
+               devfs_unregister_blkdev(MAJOR_NR,"fd");
        }
        
        for (drive = 0; drive < N_DRIVE; drive++) {
@@ -4324,7 +4339,7 @@ static void floppy_release_irq_and_dma(void)
        if (floppy_track_buffer && max_buffer_sectors) {
                tmpsize = max_buffer_sectors*1024;
                tmpaddr = (unsigned long)floppy_track_buffer;
-               floppy_track_buffer = 0;
+               floppy_track_buffer = NULL;
                max_buffer_sectors = 0;
                buffer_min = buffer_max = -1;
                fd_dma_mem_free(tmpaddr, tmpsize);
@@ -4357,7 +4372,7 @@ static void floppy_release_irq_and_dma(void)
 
 #ifdef MODULE
 
-char *floppy=NULL;
+char *floppy;
 
 static void __init parse_floppy_cfg_string(char *cfg)
 {
@@ -4365,11 +4380,11 @@ static void __init parse_floppy_cfg_string(char *cfg)
 
        while(*cfg) {
                for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++);
-               if(*cfg) {
+               if (*cfg) {
                        *cfg = '\0';
                        cfg++;
                }
-               if(*ptr)
+               if (*ptr)
                        floppy_setup(ptr);
        }
 }
@@ -4378,7 +4393,7 @@ int init_module(void)
 {
        printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n");
                
-       if(floppy)
+       if (floppy)
                parse_floppy_cfg_string(floppy);
        return floppy_init();
 }
@@ -4411,7 +4426,7 @@ __setup ("floppy=", floppy_setup);
 void floppy_eject(void)
 {
        int dummy;
-       if(have_no_fdc)
+       if (have_no_fdc)
                return;
        if(floppy_grab_irq_and_dma()==0)
        {
index bacb62fba9a8af56820bce829c60ae9a00fc2e66..9d518eaf9c3135ff3c15beff36f83779d457aae7 100644 (file)
@@ -289,7 +289,8 @@ repeat:
                if (lo->lo_flags & LO_FLAGS_READ_ONLY)
                        goto error_out;
        } else if (current_request->cmd != READ) {
-               printk(KERN_ERR "unknown loop device command (%d)?!?", current_request->cmd);
+               printk(KERN_ERR "unknown loop device command (%d)?!?",
+                      current_request->cmd);
                goto error_out;
        }
 
@@ -423,8 +424,28 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
                /* Backed by a block device - don't need to hold onto
                   a file structure */
                lo->lo_backing_file = NULL;
+
+               if (error)
+                       goto out_putf;
        } else if (S_ISREG(inode->i_mode)) {
                struct address_space_operations *aops;
+
+               aops = inode->i_mapping->a_ops;
+               /*
+                * If we can't read - sorry. If we only can't write - well,
+                * it's going to be read-only.
+                */
+               error = -EINVAL;
+               if (!aops->readpage)
+                       goto out_putf;
+
+               if (!aops->prepare_write || !aops->commit_write)
+                       lo->lo_flags |= LO_FLAGS_READ_ONLY;
+
+               error = get_write_access(inode);
+               if (error)
+                       goto out_putf;
+
                /* Backed by a regular file - we need to hold onto a file
                   structure for this file.  Friggin' NFS can't live without
                   it on write and for reading we use do_generic_file_read(),
@@ -437,35 +458,23 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
 
                error = -ENFILE;
                lo->lo_backing_file = get_empty_filp();
-               if (lo->lo_backing_file) {
-                       lo->lo_backing_file->f_mode = file->f_mode;
-                       lo->lo_backing_file->f_pos = file->f_pos;
-                       lo->lo_backing_file->f_flags = file->f_flags;
-                       lo->lo_backing_file->f_owner = file->f_owner;
-                       lo->lo_backing_file->f_dentry = file->f_dentry;
-                       lo->lo_backing_file->f_vfsmnt = file->f_vfsmnt;
-                       lo->lo_backing_file->f_op = file->f_op;
-                       lo->lo_backing_file->private_data = file->private_data;
-                       file_moveto(lo->lo_backing_file, file);
-
-                       error = get_write_access(inode);
-                       if (error) {
-                               put_filp(lo->lo_backing_file);
-                               lo->lo_backing_file = NULL;
-                       }
+               if (lo->lo_backing_file == NULL) {
+                       put_write_access(inode);
+                       goto out_putf;
                }
-               aops = inode->i_mapping->a_ops;
-               /*
-                * If we can't read - sorry. If we only can't write - well,
-                * it's going to be read-only.
-                */
-               if (!aops->readpage)
-                       error = -EINVAL;
-               else if (!aops->prepare_write || !aops->commit_write)
-                       lo->lo_flags |= LO_FLAGS_READ_ONLY;
+
+               lo->lo_backing_file->f_mode = file->f_mode;
+               lo->lo_backing_file->f_pos = file->f_pos;
+               lo->lo_backing_file->f_flags = file->f_flags;
+               lo->lo_backing_file->f_owner = file->f_owner;
+               lo->lo_backing_file->f_dentry = file->f_dentry;
+               lo->lo_backing_file->f_vfsmnt = mntget(file->f_vfsmnt);
+               lo->lo_backing_file->f_op = file->f_op;
+               lo->lo_backing_file->private_data = file->private_data;
+               file_moveto(lo->lo_backing_file, file);
+
+               error = 0;
        }
-       if (error)
-               goto out_putf;
 
        if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
                lo->lo_flags |= LO_FLAGS_READ_ONLY;
@@ -477,9 +486,9 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
        lo->ioctl = NULL;
        figure_loop_size(lo);
 
-out_putf:
+ out_putf:
        fput(file);
-out:
+ out:
        if (error)
                MOD_DEC_USE_COUNT;
        return error;
@@ -530,6 +539,7 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
        lo->lo_dentry = NULL;
 
        if (lo->lo_backing_file != NULL) {
+               put_write_access(lo->lo_backing_file->f_dentry->d_inode);
                fput(lo->lo_backing_file);
                lo->lo_backing_file = NULL;
        } else {
index ca1bb15649fd1713be9c6146ab3d0d3b0150f7fb..9f54be5a2877fa261216c6e756988bf5e6fce9b8 100644 (file)
@@ -15,6 +15,7 @@
  * (for example /usr/src/linux/COPYING); if not, write to the Free
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+#include <linux/config.h>
 #define BH_TRACE 0
 #include <linux/module.h>
 #include <linux/raid/md.h>
index 280bf4a927a63b571fd7ac23cd668543d8a04800..e0831dd1e140ae89a8ac278b15b57ad72610a588 100644 (file)
@@ -232,7 +232,8 @@ else
   endif
 endif
 
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o
+obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \
+       tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o
 ifeq ($(CONFIG_VIDEO_BT848),y)
 L_TUNERS=y
 else
index f55f992d8c20b2ba4e881501f56020bbbf119426..f7c9b0db6b101e65325c4b744d129ba07c599d08 100644 (file)
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 
-#ifdef LOCK_I2C_BUS
-# error INSTALL ERROR
-# error gcc uses the old, obsolete i2c.h include file.  Please install the \
-       new i2c stack.  Please install it by patching the kernel, otherwise \
-       gcc will not find the new header files.
-#endif
-
 #include "bttv.h"
 #include "tuner.h"
 
@@ -100,7 +93,7 @@ static int triton1=0;
 static unsigned long remap[BTTV_MAX];
 static unsigned int radio[BTTV_MAX];
 static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
-static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0};
+static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1};
 static unsigned int fieldnr = 0;
 static unsigned int verbose = 1;
 static unsigned int debug = 0;
@@ -713,19 +706,23 @@ static struct CARD {
        char *name;
 } cards[] = {
        { 0x00011002, BTTV_HAUPPAUGE878,  "ATI TV Wonder" },
-       { 0x00031461, BTTV_AVERMEDIA98,   "AVerMedia TVPhone98" },
+       { 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00041461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
        { 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
        { 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
+       { 0x1200bd11, BTTV_PINNACLERAVE,  "Pinnacle PCTV Rave" },
        { 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
        { 0x14610002, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
        { 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
        { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+       { 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
        { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
        { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
        { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
        { 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
+       { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" },
        { 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x1200bd11, BTTV_PINNACLERAVE,  "Pinnacle PCTV Rave" },
        { 0, -1, NULL }
 };
 
@@ -747,6 +744,13 @@ struct tvcard
        int tda9840:1;
        int tda985x:1;
        int tea63xx:1;
+       int tea64xx:1;
+       int tda7432:1;
+       int tda9875:1;
+
+       /* other settings */
+       int pll;
+       int tuner_type;
 };
 
 static struct tvcard tvcards[] = 
@@ -754,144 +758,157 @@ static struct tvcard tvcards[] =
        /* 0x00 */
         { " *** UNKNOWN *** ",
           3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "MIRO PCTV",
           4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Hauppauge old",
           4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,0,1,0 },
+         1,1,0,1,0,0,0,1,  PLL_NONE, -1 },
         { "STB",
           3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
-         0,1,1,1,1 },
+         0,1,1,1,1,0,0,1,  PLL_NONE, -1 },
 
         { "Intel",
-          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0 },
+          3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "Diamond DTV2000",
           3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "AVerMedia TVPhone",
           3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "MATRIX-Vision MV-Delta",
           5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
 
        /* 0x08 */
         { "Fly Video II",
           3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},
          { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "TurboTV",
           3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Hauppauge new (bt878)",
          4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,0,1,0 },
+         1,1,0,1,0,0,0,1,  PLL_28,   -1 },
         { "MIRO PCTV pro",
           3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
 
        { "ADS Technologies Channel Surfer TV",
          3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "AVerMedia TVCapture 98",
          3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
         { "Aimslab VHX",
           3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Zoltrix TV-Max",
           3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
 
        /* 0x10 */
         { "Pixelview PlayTV (bt878)",
-          3, 1, 0, 2, 0x01e000, { 2, 0, 1, 1},
+          3, 1, 0, 2, 0x01fe00, { 2, 0, 1, 1},
          { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
         { "Leadtek WinView 601",
           3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0},
          { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "AVEC Intercapture",
          3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "LifeView FlyKit w/o Tuner",
          3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0,
-         0,0,0,0,0 },
+         0,0,0,0,0,0,0,1,  PLL_NONE, -1 },
 
         { "CEI Raffles Card",
          3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "Lucky Star Image World ConferenceTV",
-         3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0,
-         1,1,1,1,0 },
+         3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0,
+         1,1,1,1,0,0,0,1,  PLL_28,   TUNER_PHILIPS_PAL_I },
        { "Phoebe Tv Master + FM",
          3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Modular Technology MM205 PCTV, bt878",
          2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
 
        /* 0x18 */
         { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
          3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
         { "Terratec/Vobis TV-Boostar",
           3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Newer Hauppauge WinCam (bt878)",
          4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "MAXI TV Video PCI2",
           3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, TUNER_PHILIPS_SECAM },
 
         { "Terratec TerraTV+",
           3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, 
           { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "Imagenation PXC200",
           5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "FlyVideo 98",
           3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, 
           { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
         { "iProTV",
          3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
 
        /* 0x20 */
        { "Intel Create and Share PCI",
          4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "Terratec TerraTValue",
-          3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
-         1,1,1,1,0 },
+         3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1},
+         { 0x500, 0, 0x300, 0x900, 0x900},0,
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
        { "Leadtek WinFast 2000",
          3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0},
          { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0,
-         1,1,1,1,1 },
+         1,1,1,1,1,0,0,1,  PLL_28,   -1 },
        { "Chronos Video Shuttle II",
          3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
 
        { "Typhoon TView TV/FM Tuner",
          3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0,
-         1,1,1,1,0 },
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
        { "PixelView PlayTV pro",
           3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
-          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 },
+          { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0,
+         0,0,0,0,0,0,0,1,  PLL_28,   -1 },
        { "TView99 CPH063",
-         3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1},
-         { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 },
+         3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1},
+         { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0,
+         1,1,1,1,0,0,0,1,  PLL_28,   -1 },
        { "Pinnacle PCTV Rave",
          3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0,
-         1,1,1,1,0 },
-       
+         1,1,1,1,0,0,0,1,  PLL_NONE, -1 },
+
+        /* 0x28 */
+        { "STB2",
+          3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
+         0,1,1,1,0,1,1,1,  PLL_NONE, -1 },
+        { "AVerMedia TVPhone 98",
+         3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
+         1,1,1,1,0,0,0,1,  PLL_28,   5 },
+        { "ProVideo PV951", /* pic16c54 */
+          3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
+         0,0,0,0,0,0,0,0,  PLL_28,   1 },
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
@@ -1477,6 +1494,10 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int
         unsigned char lmask, rmask, *p;
         int W, l, r;
        int i;
+
+       if (debug)
+               printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y);
+
        /* bitmap is fixed width, 128 bytes (1024 pixels represented) */
         if (x<0)
         {
@@ -1497,10 +1518,10 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int
                 w=1024-x;
 
         l=x>>3;
-        r=(x+w)>>3;
+        r=(x+w-1)>>3;
         W=r-l-1;
         lmask=lmaskt[x&7];
-        rmask=rmaskt[(x+w)&7];
+        rmask=rmaskt[(x+w-1)&7];
         p=clipmap+128*y+l;
         
         if (W>0) 
@@ -1885,6 +1906,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
 #endif
 
        if (btv->gq_in == btv->gq_out) {
+               btv->gq_start = 1;
                btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
         }
        btv->gqueue[btv->gq_in++] = mp->frame;
@@ -2033,14 +2055,15 @@ static void bttv_close(struct video_device *dev)
 
        btread(BT848_I2C);      /* This fixes the PCI posting delay */
        
-       /*
-        *      This is sucky but right now I can't find a good way to
-        *      be sure its safe to free the buffer. We wait 5-6 fields
-        *      which is more than sufficient to be sure.
-        */
-
-       current->state = TASK_UNINTERRUPTIBLE;
-       schedule_timeout(HZ/10);        /* Wait 1/10th of a second */
+       if (-1 != btv->gq_grab) {
+               /*
+                *      This is sucky but right now I can't find a good way to
+                *      be sure its safe to free the buffer. We wait 5-6 fields
+                *      which is more than sufficient to be sure.
+                */
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ/10);        /* Wait 1/10th of a second */
+       }
        
        /*
         *      We have allowed it to drain.
@@ -3063,7 +3086,7 @@ static void idcard(int i)
                                btv->type=BTTV_HAUPPAUGE;
                        }
 
-               /* STB cards have a eeprom @ 0xae */
+               /* STB cards have a eeprom @ 0xae (old bt848) */
                } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
                        btv->type=BTTV_STB;
                }
@@ -3078,20 +3101,20 @@ static void idcard(int i)
        }
 
        /* print which board we have found */
-       printk(KERN_INFO "bttv%d: model: ",btv->nr);
-
        sprintf(btv->video_dev.name,"BT%d%s(%.22s)",
                btv->id,
                (btv->id==848 && btv->revision==0x12) ? "A" : "",
                tvcards[btv->type].name);
-       printk("%s\n",btv->video_dev.name);
+       printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name);
 
+       
         /* board specific initialisations */
         if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
                 /* auto detect tuner for MIRO cards */
                 btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
         }
         if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
+               /* pick up some config infos from the eeprom */
                if (0xa0 != eeprom) {
                        eeprom = 0xa0;
                        readee(btv,eeprom_data,0xa0);
@@ -3099,32 +3122,42 @@ static void idcard(int i)
                 hauppauge_eeprom(btv);
                 hauppauge_boot_msp34xx(btv);
         }
-       if (btv->type == BTTV_MAXI) {
-               /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */
-               btv->tuner_type=TUNER_PHILIPS_SECAM;
-       }
        if (btv->type == BTTV_PXC200)
                init_PXC200(btv);
-       
-        if (btv->type == BTTV_CONFERENCETV)
-                btv->tuner_type = 1;
-       
-        if (btv->type == BTTV_HAUPPAUGE878     ||
-           btv->type == BTTV_CONFERENCETV      ||
-           btv->type == BTTV_PIXVIEWPLAYTV     ||
-           btv->type == BTTV_AVERMEDIA98       ||
-           btv->type == BTTV_MAGICTVIEW061     ||
-           btv->type == BTTV_MAGICTVIEW063     ||
-           btv->type == BTTV_CHRONOS_VS2       ||
-           btv->type == BTTV_TYPHOON_TVIEW     ||
-           btv->type == BTTV_PXELVWPLTVPRO     ||
-           btv->type == BTTV_WINFAST2000) {
-                btv->pll.pll_ifreq=28636363;
-                btv->pll.pll_crystal=BT848_IFORM_XT0;
-        }
 
-       if (btv->tuner_type != -1) 
+
+       /* pll configuration */
+        if (!(btv->id==848 && btv->revision==0x11)) {
+               /* defaults from card list */
+               if (PLL_28 == tvcards[btv->type].pll) {
+                       btv->pll.pll_ifreq=28636363;
+                       btv->pll.pll_crystal=BT848_IFORM_XT0;
+               }
+               /* insmod options can override */
+                switch (pll[btv->nr]) {
+                case 0: /* none */
+                       btv->pll.pll_crystal = 0;
+                       btv->pll.pll_ifreq   = 0;
+                       btv->pll.pll_ofreq   = 0;
+                        break;
+                case 1: /* 28 MHz */
+                        btv->pll.pll_ifreq   = 28636363;
+                       btv->pll.pll_ofreq   = 0;
+                        btv->pll.pll_crystal=BT848_IFORM_XT0;
+                        break;
+                case 2: /* 35 MHz */
+                        btv->pll.pll_ifreq   = 35468950;
+                       btv->pll.pll_ofreq   = 0;
+                        btv->pll.pll_crystal=BT848_IFORM_XT1;
+                        break;
+                }
+        }
+       
+       
+       /* tuner configuration */
+       if (-1 != tvcards[btv->type].tuner_type)
+                btv->tuner_type = tvcards[btv->type].tuner_type;
+       if (btv->tuner_type != -1)
                call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
 
        /* try to detect audio/fader chips */
@@ -3154,12 +3187,28 @@ static void idcard(int i)
                        request_module("tda985x");
        }
 
-       if (tvcards[btv->type].tea63xx /* &&
-           I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0 */) {
+       if (tvcards[btv->type].tda9875 &&
+           I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
+               if (autoload)
+                       request_module("tda9875");
+       }
+
+       if (tvcards[btv->type].tda7432 &&
+           I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
+               if (autoload)
+                       request_module("tda7432");
+       }
+
+       if (tvcards[btv->type].tea63xx) {
                if (autoload)
                        request_module("tea6300");
        }
 
+       if (tvcards[btv->type].tea64xx) {
+               if (autoload)
+                       request_module("tea6420");
+       }
+
        if (tvcards[btv->type].tuner != -1) {
                if (autoload)
                        request_module("tuner");
@@ -3242,7 +3291,11 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
                btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
        }
 
-       btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
+       if (btv->gq_start) {
+               btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
+       } else {
+               btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
+       }
        btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
 
        /* enable cpaturing and DMA */
@@ -3561,6 +3614,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                        }
                        if (stat&(8<<28)) 
                        {
+                               btv->gq_start = 0;
                                btv->gq_grab = btv->gqueue[btv->gq_out++];
                                btv->gq_out  = btv->gq_out % MAX_GBUFFERS;
                                if (debug)
@@ -3661,8 +3715,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
 
         btv->id=dev->device;
         btv->irq=dev->irq;
-        btv->bt848_adr=pci_resource_start(dev, 0);
-
+       btv->bt848_adr=pci_resource_start(dev, 0);
        if (pci_enable_device(dev))
                return -EIO;
        if (!request_mem_region(pci_resource_start(dev,0),
@@ -3689,29 +3742,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
         cmd = (cmd | PCI_COMMAND_MEMORY ); 
         pci_write_config_dword(dev, PCI_COMMAND, cmd);
 #endif
-        
-        btv->pll.pll_crystal = 0;
-        btv->pll.pll_ifreq   = 0;
-        btv->pll.pll_ofreq   = 0;
-        btv->pll.pll_current = 0;
-        if (!(btv->id==848 && btv->revision==0x11)) {
-                switch (pll[btv->nr]) {
-                case 0:
-                        /* off */
-                        break;
-                case 1:
-                        /* 28 MHz crystal installed */
-                        btv->pll.pll_ifreq=28636363;
-                        btv->pll.pll_crystal=BT848_IFORM_XT0;
-                        break;
-                case 2:
-                        /* 35 MHz crystal installed */
-                        btv->pll.pll_ifreq=35468950;
-                        btv->pll.pll_crystal=BT848_IFORM_XT1;
-                        break;
-                }
-        }
-       
+
 #ifdef __sparc__
        btv->bt848_mem=(unsigned char *)btv->bt848_adr;
 #else
index be929c6c9be2a6e8ac1998cd66b32d36f94ef039..4ac092e1e927b708ff0eafeea90a72d45676c0a0 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
@@ -21,7 +21,7 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,25
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,28
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -183,7 +183,7 @@ struct bttv {
 
        struct bttv_gbuf *gbuf;
        int gqueue[MAX_GBUFFERS];
-       int gq_in,gq_out,gq_grab;
+       int gq_in,gq_out,gq_grab,gq_start;
         char *fbuffer;
 
        struct bttv_pll_info pll;
@@ -272,7 +272,13 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
 #define BTTV_PXELVWPLTVPRO 0x25
 #define BTTV_MAGICTVIEW063 0x26
 #define BTTV_PINNACLERAVE  0x27
+#define BTTV_STB2          0x28
+#define BTTV_AVPHONE98     0x29
+#define BTTV_PV951         0x2a
 
+#define PLL_NONE 0
+#define PLL_28   1
+#define PLL_35   2
 
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
@@ -289,9 +295,11 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
 #define TEA6300            0x04
 
 #define I2C_TSA5522        0xc2
+#define I2C_TDA7432        0x8a
+#define I2C_TDA8425        0x82
 #define I2C_TDA9840        0x84
 #define I2C_TDA9850        0xb6
-#define I2C_TDA8425        0x82
+#define I2C_TDA9875        0xb0
 #define I2C_HAUPEE         0xa0
 #define I2C_STBEE          0xae
 #define I2C_VHX            0xc0
index 6763b068a21ccc2aa0581f42a8837a26a696a28e..9238ae3eb214ce35fa2f5727aed9e8e8c99f01ae 100644 (file)
@@ -4075,7 +4075,7 @@ err_out:
 }
 
 
-static struct pci_device_id epca_pci_tbl[] __devinitdata = {
+static struct pci_device_id epca_pci_tbl[] __initdata = {
        { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
        { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
        { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
index 2d275e59259e5202ca95e82dab02e370543ddba9..ab6b65f0abe2ef83b2a3934d06a00974199d2e20 100644 (file)
@@ -231,9 +231,10 @@ static ssize_t read_kmem(struct file *file, char *buf,
 {
        unsigned long p = *ppos;
        ssize_t read = 0;
-       ssize_t virtr;
+       ssize_t virtr = 0;
+       char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
                
-       if (p < (unsigned long) high_memory) { 
+       if (p < (unsigned long) high_memory) {
                read = count;
                if (count > (unsigned long) high_memory - p)
                        read = (unsigned long) high_memory - p;
@@ -258,11 +259,27 @@ static ssize_t read_kmem(struct file *file, char *buf,
                count -= read;
        }
 
-       virtr = vread(buf, (char *)p, count);
-       if (virtr < 0)
-               return virtr;
-       *ppos += p + virtr;
-       return virtr + read;
+       kbuf = (char *)__get_free_page(GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+       while (count > 0) {
+               int len = count;
+
+               if (len > PAGE_SIZE)
+                       len = PAGE_SIZE;
+               len = vread(kbuf, (char *)p, len);
+               if (len && copy_to_user(buf, kbuf, len)) {
+                       free_page((unsigned long)kbuf);
+                       return -EFAULT;
+               }
+               count -= len;
+               buf += len;
+               virtr += len;
+               p += len;
+       }
+       free_page((unsigned long)kbuf);
+       *ppos = p;
+       return virtr + read;
 }
 
 /*
index 6b86db95be81cdbbdb5d176ed919b726b76dc802..f4252a07122cd64ea9f0cece536e99af0f377dff 100644 (file)
@@ -871,7 +871,7 @@ static int msp3400c_thread(void *data)
                /* unmute */
                msp3400c_setvolume(client, msp->left, msp->right);
 
-               if (msp->watch_stereo) 
+               if (msp->watch_stereo)
                        mod_timer(&msp->wake_stereo, jiffies+5*HZ);
 
                if (debug)
@@ -1086,7 +1086,7 @@ static int msp3410d_thread(void *data)
                msp3400c_settreble(client, msp->treble);
                msp3400c_setvolume(client, msp->left, msp->right);
 
-               if (msp->watch_stereo) 
+               if (msp->watch_stereo)
                        mod_timer(&msp->wake_stereo, jiffies+HZ);
 
                msp->active = 0;
@@ -1236,7 +1236,7 @@ static int
 msp3400c_mixer_open(struct inode *inode, struct file *file)
 {
         int minor = MINOR(inode->i_rdev);
-       struct i2c_client *client = NULL;
+       struct i2c_client *client;
        struct msp3400c *msp;
        int i;
 
@@ -1246,12 +1246,12 @@ msp3400c_mixer_open(struct inode *inode, struct file *file)
                if (msp->mixer_num == minor) {
                        client = msps[i];
                        file->private_data = client;
-                       goto match;
+                       break;
                }
        }
-       return -ENODEV;
+       if (MSP3400_MAX == i)
+               return -ENODEV;
 
-match:
        /* lock bttv in memory while the mixer is in use  */
        if (client->adapter->inc_use)
                client->adapter->inc_use(client->adapter);
@@ -1265,8 +1265,8 @@ msp3400c_mixer_release(struct inode *inode, struct file *file)
 {
        struct i2c_client *client = file->private_data;
 
-       if (client->adapter->inc_use) 
-               client->adapter->inc_use(client->adapter);
+       if (client->adapter->dec_use) 
+               client->adapter->dec_use(client->adapter);
         MOD_DEC_USE_COUNT;
         return 0;
 }
diff --git a/drivers/char/tda7432.c b/drivers/char/tda7432.c
new file mode 100644 (file)
index 0000000..4880913
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * For the STS-Thompson TDA7432 audio processor chip
+ * 
+ * Handles audio functions: volume, balance, tone, loudness
+ * This driver will not complain if used with any 
+ * other i2c device with the same address.
+ *
+ * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
+ * This code is placed under the terms of the GNU General Public License
+ * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Which was based on tda8425.c by Greg Alexander (c) 1998
+ *
+ * OPTIONS:
+ * debug    - set to 1 if you'd like to see debug messages
+ *            set to 2 if you'd like to be inundated with debug messages
+ *
+ * loudness - set between 0 and 15 for varying degrees of loudness effect
+ *
+ * TODO:
+ *  Implement tone controls
+ *
+ *  Revision: 0.3 - Fixed silly reversed volume controls.  :)
+ *  Revision: 0.2 - Cleaned up #defines
+ *                     fixed volume control
+ *                  Added I2C_DRIVERID_TDA7432
+ *                     added loudness insmod control
+ *  Revision: 0.1 - initial version
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bttv.h"
+#include "audiochip.h"
+
+/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
+#ifndef I2C_DRIVERID_TDA7432
+  #define I2C_DRIVERID_TDA7432 27
+#endif
+
+
+MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
+MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(loudness,"i");
+static int loudness = 0; /* disable loudness by default */
+static int debug = 0;   /* insmod parameter */
+
+
+/* Address to scan (I2C address of this chip) */
+static unsigned short normal_i2c[] = {
+       I2C_TDA7432 >> 1,
+       I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+       normal_i2c, normal_i2c_range, 
+       probe, probe_range, 
+       ignore, ignore_range, 
+       force
+};
+
+/* Structure of address and subaddresses for the tda7432 */
+
+struct tda7432 {
+       int addr;
+       int input;
+       int volume;
+       int tone;
+       int lf, lr, rf, rr;
+       int loud;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+#define dprintk  if (debug) printk
+#define d2printk if (debug > 1) printk
+
+/* The TDA7432 is made by STS-Thompson
+ * http://www.st.com
+ * http://us.st.com/stonline/books/pdf/docs/4056.pdf
+ *
+ * TDA7432: I2C-bus controlled basic audio processor
+ *
+ * The TDA7432 controls basic audio functions like volume, balance,
+ * and tone control (including loudness).  It also has four channel
+ * output (for front and rear).  Since most vidcap cards probably
+ * don't have 4 channel output, this driver will set front & rear
+ * together (no independent control).
+ */ 
+
+               /* Subaddresses for TDA7432 */
+
+#define TDA7432_IN     0x00 /* Input select                 */
+#define TDA7432_VL     0x01 /* Volume                       */
+#define TDA7432_TN     0x02 /* Bass, Treble (Tone)          */
+#define TDA7432_LF     0x03 /* Attenuation LF (Left Front)  */
+#define TDA7432_LR     0x04 /* Attenuation LR (Left Rear)   */
+#define TDA7432_RF     0x05 /* Attenuation RF (Right Front) */
+#define TDA7432_RR     0x06 /* Attenuation RR (Right Rear)  */
+#define TDA7432_LD     0x07 /* Loudness                     */
+
+
+               /* Masks for bits in TDA7432 subaddresses */
+
+/* Many of these not used - just for documentation */
+
+/* Subaddress 0x00 - Input selection and bass control */
+
+/* Bits 0,1,2 control input:
+ * 0x00 - Stereo input
+ * 0x02 - Mono input
+ * 0x03 - Mute
+ * Mono probably isn't used - I'm guessing only the stereo
+ * input is connected on most cards, so we'll set it to stereo.
+ * 
+ * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut
+ * Bit 4 controls bass range: 0/1 is extended/standard bass range
+ * 
+ * Highest 3 bits not used
+ */
+#define TDA7432_STEREO_IN      0
+#define TDA7432_MONO_IN                2       /* Probably won't be used */
+#define TDA7432_MUTE           3       /* Probably won't be used */
+#define TDA7432_BASS_SYM       1 << 3
+#define TDA7432_BASS_NORM      1 << 4
+
+/* Subaddress 0x01 - Volume */
+
+/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps
+ * Recommended maximum is +20 dB
+ *
+ * +32dB: 0x00
+ * +20dB: 0x0c
+ *   0dB: 0x20
+ * -79dB: 0x6f
+ *
+ * MSB (bit 7) controls loudness: 1/0 is loudness on/off
+ */
+
+#define        TDA7432_VOL_0DB         0x20
+#define TDA7432_LD_ON          1 << 7
+
+
+/* Subaddress 0x02 - Tone control */ 
+
+/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB
+ * 0x0 is 14dB, 0x7 is 0dB
+ *
+ * Bit 3 controls treble attenuation/gain (sign)
+ * 1 = gain (+)
+ * 0 = attenuation (-)
+ *
+ * Bits 4,5,6 control absolute bass gain from 0dB to 14dB
+ * (This is only true for normal base range, set in 0x00)
+ * 0x0 << 4 is 14dB, 0x7 is 0dB
+ * 
+ * Bit 7 controls bass attenuation/gain (sign)
+ * 1 << 7 = gain (+)
+ * 0 << 7 = attenuation (-) 
+ *
+ * Example:
+ * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble
+ */
+
+#define TDA7432_TREBLE_0DB             0xf 
+#define TDA7432_TREBLE                 7
+#define TDA7432_TREBLE_GAIN            1 << 3
+#define TDA7432_BASS_0DB               0xf << 4
+#define TDA7432_BASS                   7 << 4
+#define TDA7432_BASS_GAIN              1 << 7
+
+/* Subaddress 0x03 - Left  Front attenuation */
+/* Subaddress 0x04 - Left  Rear  attenuation */
+/* Subaddress 0x05 - Right Front attenuation */
+/* Subaddress 0x06 - Right Rear  attenuation */
+
+/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB
+ * in 1.5dB steps.
+ *
+ * 0x00 is     0dB
+ * 0x1f is -37.5dB
+ *
+ * Bit 5 mutes that channel when set (1 = mute, 0 = unmute)
+ * We'll use the mute on the input, though (above) 
+ * Bits 6,7 unused
+ */
+
+#define TDA7432_ATTEN_0DB      0x00
+
+
+/* Subaddress 0x07 - Loudness Control */
+
+/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps
+ * when bit 4 is NOT set
+ *
+ * 0x0 is   0dB
+ * 0xf is -15dB
+ *
+ * If bit 4 is set, then there is a flat attenuation according to
+ * the lower 4 bits, as above.
+ *
+ * Bits 5,6,7 unused
+ */
+
+/* Begin code */
+
+static int tda7432_write(struct i2c_client *client, int subaddr, int val)
+{
+       unsigned char buffer[2];
+       d2printk("tda7432: In tda7432_write\n");
+       dprintk("tda7432: Writing %d 0x%x\n", subaddr, val);
+       buffer[0] = subaddr;
+       buffer[1] = val;
+       if (2 != i2c_master_send(client,buffer,2)) {
+               printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n",
+                      subaddr, val);
+               return -1;
+       }
+       return 0;
+}
+
+/* I don't think we ever actually _read_ the chip... */
+#if 0
+static int tda7432_read(struct i2c_client *client)
+{
+       unsigned char buffer;
+       d2printk("tda7432: In tda7432_read\n");
+       if (1 != i2c_master_recv(client,&buffer,1)) {
+               printk(KERN_WARNING "tda7432: I/O error, trying (read)\n");
+               return -1;
+       }
+       dprintk("tda7432: Read 0x%02x\n", buffer); 
+       return buffer;
+}
+#endif
+
+static int tda7432_set(struct i2c_client *client)
+{
+       struct tda7432 *t = client->data;
+       unsigned char buf[16];
+       d2printk("tda7432: In tda7432_set\n");
+       
+       dprintk(KERN_INFO 
+               "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+               t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud);
+       buf[0]  = TDA7432_IN;
+       buf[1]  = t->input;
+       buf[2]  = t->volume;
+       buf[3]  = t->tone;
+       buf[4]  = t->lf;
+       buf[5]  = t->lr;
+       buf[6]  = t->rf;
+       buf[7]  = t->rr;
+       buf[8]  = t->loud;
+       if (9 != i2c_master_send(client,buf,9)) {
+               printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void do_tda7432_init(struct i2c_client *client)
+{
+       struct tda7432 *t = client->data;
+       d2printk("tda7432: In tda7432_init\n");
+
+       t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
+                   TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
+                   TDA7432_BASS_NORM;   /* Normal bass range     */ 
+       t->volume = TDA7432_VOL_0DB;     /* 0dB Volume            */
+       if (loudness)                    /* Turn loudness on?     */
+               t->volume |= TDA7432_LD_ON;     
+       t->tone   = TDA7432_TREBLE_0DB | /* 0dB Treble            */
+                   TDA7432_BASS_0DB;    /* 0dB Bass              */
+       t->lf     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
+       t->lr     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
+       t->rf     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
+       t->rr     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
+       t->loud   = loudness;            /* insmod parameter      */
+
+       tda7432_set(client);
+}
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda7432_attach(struct i2c_adapter *adap, int addr,
+                         unsigned short flags, int kind)
+{
+       struct tda7432 *t;
+       struct i2c_client *client;
+       d2printk("tda7432: In tda7432_attach\n");
+       client = kmalloc(sizeof *client,GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;         
+        memcpy(client,&client_template,sizeof(struct i2c_client));
+        client->adapter = adap;
+        client->addr = addr;
+       
+       client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       memset(t,0,sizeof *t);
+       do_tda7432_init(client);
+       MOD_INC_USE_COUNT;
+       strcpy(client->name,"TDA7432");
+       printk(KERN_INFO "tda7432: init\n");
+
+       i2c_attach_client(client);
+       return 0;
+}
+
+static int tda7432_probe(struct i2c_adapter *adap)
+{
+       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+               return i2c_probe(adap, &addr_data, tda7432_attach);
+       return 0;
+}
+
+static int tda7432_detach(struct i2c_client *client)
+{
+       struct tda7432 *t  = client->data;
+
+       do_tda7432_init(client);
+       i2c_detach_client(client);
+       
+       kfree(t);
+       kfree(client);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int tda7432_command(struct i2c_client *client,
+                          unsigned int cmd, void *arg)
+{
+       struct tda7432 *t = client->data;
+       d2printk("tda7432: In tda7432_command\n");
+#if 0
+       __u16 *sarg = arg;
+#endif
+
+       switch (cmd) {
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       
+       /* Query card - scale from TDA7432 settings to V4L settings */
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+               dprintk("tda7432: VIDIOCGAUDIO\n");
+
+               va->flags |= VIDEO_AUDIO_VOLUME |
+                       VIDEO_AUDIO_BASS |
+                       VIDEO_AUDIO_TREBLE;
+
+               /* Master volume control
+                * V4L volume is min 0, max 65535
+                * TDA7432 Volume: 
+                * Min (-79dB) is 0x6f
+                * Max (+20dB) is 0x07
+                * (Mask out bit 7 of vol - it's for the loudness setting)
+                */
+
+               va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+               
+               /* Balance depends on L,R attenuation
+                * V4L balance is 0 to 65535, middle is 32768
+                * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f
+                * to scale up to V4L numbers, mult by 1057
+                * attenuation exists for lf, lr, rf, rr
+                * we use only lf and rf (front channels)
+                */
+                
+               if ( (t->lf) < (t->rf) )
+                       /* right is attenuated, balance shifted left */
+                       va->balance = (32768 - 1057*(t->rf));
+               else
+                       /* left is attenuated, balance shifted right */
+                       va->balance = (32768 + 1057*(t->lf));
+
+               /* Bass/treble */
+               va->bass = 32768;   /* brain hurts... set to middle for now */
+               va->treble = 32768; /* brain hurts... set to middle for now */
+               
+               break; /* VIDIOCGAUDIO case */
+       }
+
+       /* Set card - scale from V4L settings to TDA7432 settings */
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *va = arg;
+               dprintk("tda7432: VIDEOCSAUDIO\n");
+
+               t->volume = 0x6f - ( (va->volume)/630 );
+               
+               if (loudness)           /* Turn on the loudness bit */
+                       t->volume |= TDA7432_LD_ON;
+               
+               if (va->balance < 32768) {
+                       /* shifted to left, attenuate right */
+                       t->rr = (32768 - va->balance)/1057;
+                       t->rf = t->rr;
+               }
+               else {
+                       /* shifted to right, attenuate left */
+                       t->lf = (va->balance - 32768)/1057;
+                       t->lr = t->lf;
+               }
+               
+               /* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */
+
+               tda7432_write(client,TDA7432_VL, t->volume);
+               /* tda7432_write(client,TDA7432_TN, t->tone); */
+               tda7432_write(client,TDA7432_LF, t->lf);
+               tda7432_write(client,TDA7432_LR, t->lr);
+               tda7432_write(client,TDA7432_RF, t->rf);
+               tda7432_write(client,TDA7432_RR, t->rr);
+
+               break;
+
+       } /* end of VIDEOCSAUDIO case */
+
+       default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+
+               /* nothing */
+               d2printk("tda7432: Default\n");
+
+       } /* end of (cmd) switch */
+
+       return 0;
+}
+
+
+static struct i2c_driver driver = {
+        "i2c tda7432 driver",
+       I2C_DRIVERID_TDA7432,
+        I2C_DF_NOTIFY,
+       tda7432_probe,
+        tda7432_detach,
+        tda7432_command,
+};
+
+static struct i2c_client client_template =
+{
+        "(unset)",             /* name */
+        -1,
+        0,
+        0,
+        NULL,
+        &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tda7432_init(void)
+#endif
+{
+
+       if ( (loudness < 0) || (loudness > 15) )
+       {
+               printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
+               return -EINVAL;
+       }
+
+
+       i2c_add_driver(&driver);
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       i2c_del_driver(&driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 73df0b4ac89afc779182bd7d7f0ff357b9a3f3ac..a1dec22ebc5b67a3525d9e5f92ddaf83786a7f8b 100644 (file)
@@ -31,7 +31,6 @@
 #include "audiochip.h"
 
 /* Addresses to scan */
-#define I2C_TDA8425        0x82
 static unsigned short normal_i2c[] = {
     I2C_TDA8425 >> 1,
     I2C_CLIENT_END};
index 62bcf15ba2cd0e91c1bec1b8afd91a7a74dd6dbd..73fb9bd522011eca5e22e117cd97bf0698e4e280 100644 (file)
@@ -13,6 +13,7 @@
  *
  * OPTIONS:
  * debug   - set to 1 if you'd like to see debug messages
+ *         - set to 2 if you'd like to be flooded with debug messages
  * chip    - set to 9850 or 9855 to select your chip (default 9855)
  *
  * TODO:
@@ -20,7 +21,8 @@
  *                            and unmote to fix. - Is this still here?
  *   Fine tune sound
  *   Get rest of capabilities into video_audio struct...
- * 
+ *
+ *  Revision  0.5 - cleaned up debugging messages, added debug level=2 
  *  Revision: 0.4 - check for correct chip= insmod value
  *                  also cleaned up comments a bit
  *  Revision: 0.3 - took out extraneous tda985x_write in tda985x_command
@@ -55,9 +57,10 @@ static int chip = 9855;      /* insmod parameter */
 #define I2C_TDA985x_H        0xb6
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
 static unsigned short normal_i2c_range[] = {
-    I2C_TDA985x_L >> 1,
-    I2C_TDA985x_H >> 1,
-    I2C_CLIENT_END};
+       I2C_TDA985x_L >> 1,
+       I2C_TDA985x_H >> 1,
+       I2C_CLIENT_END
+};
 static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
 static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
 static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
@@ -84,6 +87,7 @@ static struct i2c_driver driver;
 static struct i2c_client client_template;
 
 #define dprintk  if (debug) printk
+#define d2printk if (debug == 2) printk
 
 /* The TDA9850 and TDA9855 are both made by Philips Semiconductor
  * http://www.semiconductors.philips.com
@@ -154,9 +158,9 @@ static struct i2c_client client_template;
 #define TDA9855_AVL    1<<6 /* AVL, Automatic Volume Level */
 #define TDA9855_LOUD   1<<5 /* Loudness, 1==off */
 #define TDA9855_SUR    1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
-                               /* Bits 0 to 3 select various combinations
-                                 * of line in and line out, only the 
-                                 * interesting ones are defined */
+                            /* Bits 0 to 3 select various combinations
+                              * of line in and line out, only the 
+                              * interesting ones are defined */
 #define TDA9855_EXT    1<<2 /* Selects inputs LIR and LIL.  Pins 41 & 12 */
 #define TDA9855_INT    0    /* Selects inputs LOR and LOL.  (internal) */
 
@@ -213,8 +217,8 @@ static struct i2c_client client_template;
 static int tda985x_write(struct i2c_client *client, int subaddr, int val)
 {
        unsigned char buffer[2];
-       dprintk("In tda985x_write\n");
-       dprintk("Writing %d 0x%x\n", subaddr, val);
+       d2printk("tda985x: In tda985x_write\n");
+       dprintk("tda985x: Writing %d 0x%x\n", subaddr, val);
        buffer[0] = subaddr;
        buffer[1] = val;
        if (2 != i2c_master_send(client,buffer,2)) {
@@ -228,12 +232,12 @@ static int tda985x_write(struct i2c_client *client, int subaddr, int val)
 static int tda985x_read(struct i2c_client *client)
 {
        unsigned char buffer;
-       dprintk("In tda985x_read\n");
+       d2printk("tda985x: In tda985x_read\n");
        if (1 != i2c_master_recv(client,&buffer,1)) {
                printk(KERN_WARNING "tda985x: I/O error, trying (read)\n");
                return -1;
        }
-       dprintk("Read 0x%02x\n", buffer); 
+       dprintk("tda985x: Read 0x%02x\n", buffer); 
        return buffer;
 }
 
@@ -241,12 +245,12 @@ static int tda985x_set(struct i2c_client *client)
 {
        struct tda985x *t = client->data;
        unsigned char buf[16];
-       dprintk("In tda985x_set\n");
+       d2printk("tda985x: In tda985x_set\n");
        
        if (chip == 9855)
        {
                dprintk(KERN_INFO 
-                       "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+                       "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
                        t->rvol,t->lvol,t->bass,t->treble,t->sub,
                        t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
                buf[0]  = TDA9855_VR;
@@ -262,7 +266,7 @@ static int tda985x_set(struct i2c_client *client)
                buf[10] = t->a2;
                buf[11] = t->a3;
                if (12 != i2c_master_send(client,buf,12)) {
-                       printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n");
+                       printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
                        return -1;
                }
        }
@@ -270,7 +274,7 @@ static int tda985x_set(struct i2c_client *client)
        else if (chip == 9850)
        {
                dprintk(KERN_INFO 
-                       "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+                       "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
                         t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
                buf[0]  = TDA9850_C4;
                buf[1]  = t->c4;
@@ -281,7 +285,7 @@ static int tda985x_set(struct i2c_client *client)
                buf[6]  = t->a2;
                buf[7]  = t->a3;
                if (8 != i2c_master_send(client,buf,8)) {
-                       printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n");
+                       printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
                        return -1;
                }
        }
@@ -292,11 +296,11 @@ static int tda985x_set(struct i2c_client *client)
 static void do_tda985x_init(struct i2c_client *client)
 {
        struct tda985x *t = client->data;
-       dprintk("In tda985x_init\n");
+       d2printk("tda985x: In tda985x_init\n");
 
        if (chip == 9855)
        {
-               printk("Using tda9855 options\n");
+               printk("tda985x: Using tda9855 options\n");
                t->rvol = 0x6f;         /* 0dB */
                t->lvol = 0x6f;         /* 0dB */
                t->bass = 0x0e;         /* 0dB */
@@ -313,7 +317,7 @@ static void do_tda985x_init(struct i2c_client *client)
 
        else if (chip == 9850)
        {
-               printk("Using tda9850 options\n");
+               printk("tda985x: Using tda9850 options\n");
                t->c4 = 0x08;           /* Set stereo noise thresh to nominal */
                t->c5 = 0x08;           /* Set SAP noise threshold to nominal */
                t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */
@@ -337,7 +341,7 @@ static int tda985x_attach(struct i2c_adapter *adap, int addr,
 {
        struct tda985x *t;
        struct i2c_client *client;
-       dprintk("In tda985x_attach\n");
+       d2printk("tda985x: In tda985x_attach\n");
        client = kmalloc(sizeof *client,GFP_KERNEL);
        if (!client)
                return -ENOMEM;         
@@ -382,7 +386,7 @@ static int tda985x_command(struct i2c_client *client,
                           unsigned int cmd, void *arg)
 {
        struct tda985x *t = client->data;
-       dprintk("In tda985x_command...\n");
+       d2printk("tda985x: In tda985x_command\n");
 #if 0
        __u16 *sarg = arg;
 #endif
@@ -394,7 +398,7 @@ static int tda985x_command(struct i2c_client *client,
        case VIDIOCGAUDIO:
        {
                struct video_audio *va = arg;
-               dprintk("VIDIOCGAUDIO\n");
+               dprintk("tda985x: VIDIOCGAUDIO\n");
                if (chip == 9855)
                {
                        int left,right;
@@ -430,7 +434,7 @@ static int tda985x_command(struct i2c_client *client,
        case VIDIOCSAUDIO:
        {
                struct video_audio *va = arg;
-               dprintk("VIDEOCSAUDIO...\n");
+               dprintk("tda985x: VIDEOCSAUDIO\n");
                if (chip == 9855)
                {
                        int left,right;
@@ -453,17 +457,17 @@ static int tda985x_command(struct i2c_client *client,
 
                switch (va->mode) {
                        case VIDEO_SOUND_MONO:
-                               dprintk("VIDEO_SOUND_MONO\n");
+                               dprintk("tda985x: VIDEO_SOUND_MONO\n");
                                t->c6= TDA985x_MONO | (t->c6 & 0x3f);
                                tda985x_write(client,TDA985x_C6,t->c6);
                                break;
                        case VIDEO_SOUND_STEREO:
-                               dprintk("VIDEO_SOUND_STEREO\n");
+                               dprintk("tda985x: VIDEO_SOUND_STEREO\n");
                                t->c6= TDA985x_STEREO | (t->c6 & 0x3f);
                                tda985x_write(client,TDA985x_C6,t->c6); 
                                break;
                        case VIDEO_SOUND_LANG1:
-                               dprintk("VIDEO_SOUND_LANG1\n");
+                               dprintk("tda985x: VIDEO_SOUND_LANG1\n");
                                t->c6= TDA985x_SAP | (t->c6 & 0x3f);
                                tda985x_write(client,TDA985x_C6,t->c6);
                                break;
@@ -476,7 +480,7 @@ static int tda985x_command(struct i2c_client *client,
        default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
 
                /* nothing */
-               dprintk("Default\n");
+               d2printk("tda985x: Default\n");
 
        } /* end of (cmd) switch */
 
diff --git a/drivers/char/tda9875.c b/drivers/char/tda9875.c
new file mode 100644 (file)
index 0000000..da3ceeb
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * For the TDA9875 chip
+ * (The TDA9875 is used on the Diamond DTV2000 french version 
+ * Other cards probably use these chips as well.)
+ * This driver will not complain if used with any 
+ * other i2c device with the same address.
+ *
+ * Copyright (c) 2000 Guillamue Delvit based on Gerd Knorr source and
+ * Eric Sandeen 
+ * This code is placed under the terms of the GNU General Public License
+ * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Which was based on tda8425.c by Greg Alexander (c) 1998
+ *
+ * OPTIONS:
+ * debug   - set to 1 if you'd like to see debug messages
+ * 
+ *  Revision: 0.1 - original version
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bttv.h"
+#include "audiochip.h"
+
+/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
+#ifndef I2C_DRIVERID_TDA9875
+  #define I2C_DRIVERID_TDA9875  28
+#endif
+
+
+MODULE_PARM(debug,"i");
+
+static int debug = 0;  /* insmod parameter */
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] =  {
+    I2C_TDA9875 >> 1,
+    I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+       normal_i2c, normal_i2c_range, 
+       probe, probe_range, 
+       ignore, ignore_range, 
+       force
+};
+
+/* This is a superset of the TDA9875 */
+struct tda9875 {
+       int mode;
+       int rvol, lvol;
+       int bass, treble;
+};
+
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+#define dprintk  if (debug) printk
+
+/* The TDA9875 is made by Philips Semiconductor
+ * http://www.semiconductors.philips.com
+ * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
+ *
+ */ 
+
+               /* subaddresses for TDA9875 */
+#define TDA9875_MUT         0x12  /*General mute  (value --> 0b11001100*/
+#define TDA9875_CFG         0x01  /* Config register (value --> 0b00000000 */
+#define TDA9875_DACOS       0x13  /*DAC i/o select (ADC) 0b0000100*/
+#define TDA9875_LOSR        0x16  /*Line output select regirter 0b0100 0001*/
+
+#define TDA9875_CH1V        0x0c  /*Chanel 1 volume (mute)*/
+#define TDA9875_CH2V        0x0d  /*Chanel 2 volume (mute)*/
+#define TDA9875_SC1         0x14  /*SCART 1 in (mono)*/
+#define TDA9875_SC2         0x15  /*SCART 2 in (mono)*/
+
+#define TDA9875_ADCIS       0x17  /*ADC input select (mono) 0b0110 000*/
+#define TDA9875_AER         0x19  /*Audio effect (AVL+Pseudo) 0b0000 0110*/
+#define TDA9875_MCS         0x18  /*Main channel select (DAC) 0b0000100*/
+#define TDA9875_MVL         0x1a  /* Main volume gauche */
+#define TDA9875_MVR         0x1b  /* Main volume droite */
+#define TDA9875_MBA         0x1d  /* Main Basse */
+#define TDA9875_MTR         0x1e  /* Main treble */
+#define TDA9875_ACS         0x1f  /* Auxilary channel select (FM) 0b0000000*/
+#define TDA9875_AVL         0x20  /* Auxilary volume gauche */
+#define TDA9875_AVR         0x21  /* Auxilary volume droite */
+#define TDA9875_ABA         0x22  /* Auxilary Basse */
+#define TDA9875_ATR         0x23  /* Auxilary treble */
+
+#define TDA9875_MSR         0x02  /* Monitor select register */
+#define TDA9875_C1MSB       0x03  /* Carrier 1 (FM) frequency register MSB */
+#define TDA9875_C1MIB       0x04  /* Carrier 1 (FM) frequency register (16-8]b */
+#define TDA9875_C1LSB       0x05  /* Carrier 1 (FM) frequency register LSB */
+#define TDA9875_C2MSB       0x06  /* Carrier 2 (nicam) frequency register MSB */
+#define TDA9875_C2MIB       0x07  /* Carrier 2 (nicam) frequency register (16-8]b */
+#define TDA9875_C2LSB       0x08  /* Carrier 2 (nicam) frequency register LSB */
+#define TDA9875_DCR         0x09  /* Demodulateur configuration regirter*/
+#define TDA9875_DEEM        0x0a  /* FM de-emphasis regirter*/
+#define TDA9875_FMAT        0x0b  /* FM Matrix regirter*/
+
+/* values */
+#define TDA9875_MUTE_ON            0xff /* general mute */
+#define TDA9875_MUTE_OFF    0xcc /* general no mute */
+
+
+
+/* Begin code */
+
+static int tda9875_write(struct i2c_client *client, int subaddr, int val)
+{
+       unsigned char buffer[2];
+       dprintk("In tda9875_write\n");
+       dprintk("Writing %d 0x%x\n", subaddr, val);
+       buffer[0] = subaddr;
+       buffer[1] = val;
+       if (2 != i2c_master_send(client,buffer,2)) {
+               printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n",
+                      subaddr, val);
+               return -1;
+       }
+       return 0;
+}
+
+#if 0
+static int tda9875_read(struct i2c_client *client)
+{
+       unsigned char buffer;
+       dprintk("In tda9875_read\n");
+       if (1 != i2c_master_recv(client,&buffer,1)) {
+               printk(KERN_WARNING "tda9875: I/O error, trying (read)\n");
+               return -1;
+       }
+       dprintk("Read 0x%02x\n", buffer); 
+       return buffer;
+}
+#endif
+
+static void tda9875_set(struct i2c_client *client)
+{
+       struct tda9875 *tda = client->data;
+       
+       dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble);
+       tda9875_write(client, TDA9875_MVL, tda->lvol / 600 - 84);
+       tda9875_write(client, TDA9875_MVR, tda->rvol / 600 -84);
+       tda9875_write(client, TDA9875_MBA, tda->bass / 2340 -12);
+       tda9875_write(client, TDA9875_MTR, tda->treble / 2621 -12);
+}
+
+static void do_tda9875_init(struct i2c_client *client)
+{
+       struct tda9875 *t = client->data;
+       dprintk("In tda9875_init\n"); 
+       tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
+       tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
+       tda9875_write(client, TDA9875_C1MSB, 0x00 );  /*Car1(FM) MSB XMHz*/
+       tda9875_write(client, TDA9875_C1MIB, 0x00 );  /*Car1(FM) MIB XMHz*/
+       tda9875_write(client, TDA9875_C1LSB, 0x00 );  /*Car1(FM) LSB XMHz*/
+       tda9875_write(client, TDA9875_C2MSB, 0x00 );  /*Car2(NICAM) MSB XMHz*/
+       tda9875_write(client, TDA9875_C2MIB, 0x00 );  /*Car2(NICAM) MIB XMHz*/
+       tda9875_write(client, TDA9875_C2LSB, 0x00 );  /*Car2(NICAM) LSB XMHz*/
+       tda9875_write(client, TDA9875_DCR, 0x00 );    /*Demod config 0x00*/
+       tda9875_write(client, TDA9875_DEEM, 0x44 );   /*DE-Emph 0b0100 0100*/
+       tda9875_write(client, TDA9875_FMAT, 0x00 );   /*FM Matrix reg 0x00*/
+       tda9875_write(client, TDA9875_SC1, 0x00 );    /* SCART 1 (SC1)*/
+       tda9875_write(client, TDA9875_SC2, 0x01 );    /* SCART 2 (sc2)*/
+        
+       tda9875_write(client, TDA9875_CH1V, 0x10 );  /* Chanel volume 1 mute*/
+       tda9875_write(client, TDA9875_CH2V, 0x10 );  /* Chanel volume 2 mute */
+       tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
+       tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
+       tda9875_write(client, TDA9875_LOSR, 0x00 );  /* line out (in:mono)*/
+       tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
+       tda9875_write(client, TDA9875_MCS, 0x44 );   /* Main ch select (DAC) */
+       tda9875_write(client, TDA9875_MVL, 0x03 );   /* Vol Main left 10dB */
+       tda9875_write(client, TDA9875_MVR, 0x03 );   /* Vol Main right 10dB*/
+       tda9875_write(client, TDA9875_MBA, 0x00 );   /* Main Bass Main 0dB*/
+       tda9875_write(client, TDA9875_MTR, 0x00 );   /* Main Treble Main 0dB*/
+       tda9875_write(client, TDA9875_ACS, 0x44 );   /* Aux chan select (dac)*/ 
+       tda9875_write(client, TDA9875_AVL, 0x00 );   /* Vol Aux left 0dB*/
+       tda9875_write(client, TDA9875_AVR, 0x00 );   /* Vol Aux right 0dB*/
+       tda9875_write(client, TDA9875_ABA, 0x00 );   /* Aux Bass Main 0dB*/
+       tda9875_write(client, TDA9875_ATR, 0x00 );   /* Aux Aigus Main 0dB*/
+       
+       tda9875_write(client, TDA9875_MUT, 0xcc );   /* General mute  */
+        
+       t->mode=AUDIO_MUTE;
+       t->lvol=t->rvol =51000;         /* 0dB */
+       t->bass=30420;          /* 0dB */
+       t->treble=34073;                /* 0dB */
+       tda9875_set(client);
+
+}
+
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda9875_attach(struct i2c_adapter *adap, int addr,
+                         unsigned short flags, int kind)
+{
+       struct tda9875 *t;
+       struct i2c_client *client;
+       dprintk("In tda9875_attach\n");
+       client = kmalloc(sizeof *client,GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;         
+        memcpy(client,&client_template,sizeof(struct i2c_client));
+        client->adapter = adap;
+        client->addr = addr;
+       
+       client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       memset(t,0,sizeof *t);
+       do_tda9875_init(client);
+       MOD_INC_USE_COUNT;
+       strcpy(client->name,"TDA9875");
+       printk(KERN_INFO "tda9875: init\n");
+
+       i2c_attach_client(client);
+       return 0;
+}
+
+static int tda9875_probe(struct i2c_adapter *adap)
+{
+       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+               return i2c_probe(adap, &addr_data, tda9875_attach);
+       return 0;
+}
+
+static int tda9875_detach(struct i2c_client *client)
+{
+       struct tda9875 *t  = client->data;
+
+       do_tda9875_init(client);
+       i2c_detach_client(client);
+       
+       kfree(t);
+       kfree(client);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int tda9875_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       struct tda9875 *t = client->data;
+
+       dprintk("In tda9875_command...\n"); 
+
+       switch (cmd) {  
+        /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+               int left,right;
+
+               dprintk("VIDIOCGAUDIO\n");
+
+               va->flags |= VIDEO_AUDIO_VOLUME |
+                       VIDEO_AUDIO_BASS |
+                       VIDEO_AUDIO_TREBLE;
+
+               /* min is -84 max is 24 */
+               left = (t->lvol+85)*600;
+               right = (t->rvol+85)*600;
+               va->volume=MAX(left,right);
+               va->balance=(32768*MIN(left,right))/
+                       (va->volume ? va->volume : 1);
+               va->balance=(left<right)?
+                       (65535-va->balance) : va->balance;
+               va->bass = (t->bass+13)*2340;     /* min -12 max +15 */
+               va->treble = (t->treble+13)*2621;/* min -12 max +12 */
+
+               va->mode |= VIDEO_SOUND_MONO;
+
+
+               break; /* VIDIOCGAUDIO case */
+       }
+
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *va = arg;
+               int left,right;
+
+               dprintk("VIDEOCSAUDIO...\n"); 
+               left = (MIN(65536 - va->balance,32768) *
+                       va->volume) / 32768;
+               right = (MIN(va->balance,32768) *
+                        va->volume) / 32768;
+               t->lvol = left/600-84;
+               t->rvol = right/600-84;
+               t->bass = va->bass/2340-12;
+               t->treble = va->treble/2621-12;
+               tda9875_set(client);
+
+               break;
+
+       } /* end of VIDEOCSAUDIO case */
+
+       default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+
+               /* nothing */
+               dprintk("Default\n");
+
+       } /* end of (cmd) switch */
+
+       return 0;
+}
+
+
+static struct i2c_driver driver = {
+        "i2c tda9875 driver",
+        I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */
+        I2C_DF_NOTIFY,
+       tda9875_probe,
+        tda9875_detach,
+        tda9875_command,
+};
+
+static struct i2c_client client_template =
+{
+        "(unset)",             /* name */
+        -1,
+        0,
+        0,
+        NULL,
+        &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tda9875_init(void)
+#endif
+{
+       i2c_add_driver(&driver);
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       i2c_del_driver(&driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/char/tea6420.c b/drivers/char/tea6420.c
new file mode 100644 (file)
index 0000000..231ed9e
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best
+ * of my knowledge)
+ * Copyright (C) 2000 Dave Stuart <justdave@ynn.com>
+ * This code is placed under the terms of the GNU General Public License
+ * Code liberally copied from tea6300 by . . .
+ *
+ * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
+ * This code is placed under the terms of the GNU General Public License
+ * Code liberally copied from msp3400.c, which is by Gerd Knorr
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bttv.h"
+#include "audiochip.h"
+
+
+/* Addresses to scan */
+#define I2C_TEA6420    0x98
+static unsigned short normal_i2c[] = {
+    I2C_TEA6420 >> 1,
+    I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+       normal_i2c, normal_i2c_range, 
+       probe, probe_range, 
+       ignore, ignore_range, 
+       force
+};
+
+
+MODULE_PARM(debug,"i");
+static int debug = 0; /* insmod parameter */
+
+#define dprintk  if (debug) printk
+
+
+struct tea6420 {
+       int mode;               /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
+       int stereo;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+#define TEA6420_S_SA       0x00  /* stereo A input */
+#define TEA6420_S_SB       0x01  /* stereo B */
+#define TEA6420_S_SC       0x02  /* stereo C */
+#define TEA6420_S_SD       0x03  /* stereo D */
+#define TEA6420_S_SE       0x04  /* stereo E */
+#define TEA6420_S_GMU      0x05  /* general mute */
+
+
+/* ******************************** *
+ * functions for talking to TEA6420 *
+ * ******************************** */
+
+static int tea6420_write(struct i2c_client *client, int val)
+{
+       unsigned char buffer[2];
+       int result;
+
+/*     buffer[0] = addr; */
+       buffer[0] = val;
+       result = i2c_master_send(client,buffer,1);
+       if (1 != result) {
+               printk(KERN_WARNING "tea6420: I/O error, trying (write
+0x%x) result = %d\n", val, result);
+               return -1;
+       }
+       return 0;
+}
+
+
+static void do_tea6420_init(struct i2c_client *client)
+{
+       struct tea6420 *tea = client->data;
+       
+       tea->mode=AUDIO_OFF;
+       tea->stereo=1;
+       tea6420_write(client, TEA6420_S_GMU); /* mute */
+}
+
+static void tea6420_audio(struct i2c_client *client, int mode)
+{
+       struct tea6420 *tea = client->data;
+       
+       /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
+       dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode);
+       tea->mode=mode;
+       if (mode==AUDIO_OFF) {  /* just mute it */
+               tea6420_write(client, TEA6420_S_GMU);
+               return;
+       }
+       switch(mode) {
+               case AUDIO_TUNER:
+                       tea6420_write(client, TEA6420_S_SA);
+                       break;
+               case AUDIO_RADIO:
+                       tea6420_write(client, TEA6420_S_SB);
+                       break;
+               case AUDIO_EXTERN:
+                       tea6420_write(client, TEA6420_S_SC);
+                       break;
+       }
+}
+
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tea6420_attach(struct i2c_adapter *adap, int addr,
+                         unsigned short flags, int kind)
+{
+       struct tea6420 *tea;
+       struct i2c_client *client;
+
+       client = kmalloc(sizeof *client,GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;         
+        memcpy(client,&client_template,sizeof(struct i2c_client));
+        client->adapter = adap;
+        client->addr = addr;
+
+       client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL);
+       if (!tea)
+               return -ENOMEM;
+       memset(tea,0,sizeof *tea);
+       do_tea6420_init(client);
+
+       MOD_INC_USE_COUNT;
+       strcpy(client->name,"TEA6420");
+       printk(KERN_INFO "tea6420: initialized\n");
+
+       i2c_attach_client(client);
+       return 0;
+}
+
+static int tea6420_probe(struct i2c_adapter *adap)
+{      
+       if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+               return i2c_probe(adap, &addr_data, tea6420_attach);
+       return 0;
+}
+
+static int tea6420_detach(struct i2c_client *client)
+{
+       struct tea6420 *tea  = client->data;
+    
+       do_tea6420_init(client);
+       i2c_detach_client(client);
+
+       kfree(tea);
+       kfree(client);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int
+tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+        __u16 *sarg = arg;
+
+       switch (cmd) {
+       case AUDC_SET_RADIO:
+               tea6420_audio(client,AUDIO_RADIO);
+               break;
+       case AUDC_SET_INPUT:
+               tea6420_audio(client,*sarg);
+               break;
+
+       /* --- v4l ioctls --- */
+       /* take care: bttv does userspace copying, we'll get a
+          kernel pointer here... */
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *va = arg;
+
+               va->flags |= VIDEO_AUDIO_VOLUME |
+                       VIDEO_AUDIO_BASS |
+                       VIDEO_AUDIO_TREBLE;
+/*             va->volume=MAX(tea->left,tea->right);
+               va->balance=(32768*MIN(tea->left,tea->right))/
+                       (va->volume ? va->volume : 1);
+               va->balance=(tea->left<tea->right)?
+                       (65535-va->balance) : va->balance;
+               va->bass = tea->bass;
+               va->treble = tea->treble;
+*/             break;
+       }
+       case VIDIOCSAUDIO:
+       {
+
+/*             tea->left = (MIN(65536 - va->balance,32768) *
+                            va->volume) / 32768;
+               tea->right = (MIN(va->balance,32768) *
+                             va->volume) / 32768;
+               tea->bass = va->bass;
+               tea->treble = va->treble;
+               tea6420_set(client);
+*/             break;
+       }
+
+default:
+               /* nothing */
+       }
+       return 0;
+}
+
+static struct i2c_driver driver = {
+        "i2c tea6420 driver",
+        I2C_DRIVERID_TEA6420,
+        I2C_DF_NOTIFY,
+       tea6420_probe,
+        tea6420_detach,
+        tea6420_command,
+};
+
+static struct i2c_client client_template =
+{
+        "(unset)",             /* name */
+        -1,
+        0,
+        0,
+        NULL,
+        &driver
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int tea6420_init(void)
+#endif
+{
+       i2c_add_driver(&driver);
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       i2c_del_driver(&driver);
+}
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 6d68bd5ea0f504b52aef26880ed82fc97d9ce33c..45e2da6b353223543bac88f53fe5dc7457a3bbd5 100644 (file)
@@ -12,6 +12,15 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
 
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+
+   define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
+   dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    IMB Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
+   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
+
    dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
index 0158b427975bb3852214892651357e4d216a0f7b..75b3153b7ad15006495fed789fe35b6313b95ff7 100644 (file)
@@ -176,6 +176,7 @@ struct chipset_bus_clock_list_entry {
 };
 
 struct chipset_bus_clock_list_entry aec62xx_base [] = {
+#ifdef CONFIG_BLK_DEV_IDEDMA
        {       XFER_UDMA_4,    0x41,   0x04,   0x31,   0x05    },
        {       XFER_UDMA_3,    0x41,   0x03,   0x31,   0x04    },
        {       XFER_UDMA_2,    0x41,   0x02,   0x31,   0x03    },
@@ -185,7 +186,7 @@ struct chipset_bus_clock_list_entry aec62xx_base [] = {
        {       XFER_MW_DMA_2,  0x41,   0x00,   0x31,   0x00    },
        {       XFER_MW_DMA_1,  0x42,   0x00,   0x31,   0x00    },
        {       XFER_MW_DMA_0,  0x7a,   0x00,   0x0a,   0x00    },
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        {       XFER_PIO_4,     0x41,   0x00,   0x31,   0x00    },
        {       XFER_PIO_3,     0x43,   0x00,   0x33,   0x00    },
        {       XFER_PIO_2,     0x78,   0x00,   0x08,   0x00    },
@@ -202,18 +203,22 @@ extern char *ide_xfer_verbose (byte xfer_rate);
 
 static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
+       int bus_speed = system_bus_clock();
+
        for ( ; chipset_table->xfer_speed ; chipset_table++)
                if (chipset_table->xfer_speed == speed) {
-                       return ((byte) ((1) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
+                       return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
                }
        return 0x00;
 }
 
 static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
+       int bus_speed = system_bus_clock();
+
        for ( ; chipset_table->xfer_speed ; chipset_table++)
                if (chipset_table->xfer_speed == speed) {
-                       return ((byte) ((1) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
+                       return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
                }
        return 0x00;
 }
@@ -222,8 +227,6 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       byte unit               = (drive->select.b.unit & 0x01);
-       int drive_number        = ((hwif->channel ? 2 : 0) + unit);
        int err                 = 0;
        unsigned short d_conf   = 0x0000;
        byte ultra              = 0x00;
@@ -236,18 +239,18 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
        __save_flags(flags);    /* local CPU only */
        __cli();                /* local CPU only */
 
-       pci_read_config_word(dev, 0x40|(2*drive_number), &d_conf);
+       pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
        tmp0 = pci_bus_clock_list(speed, aec62xx_base);
        SPLIT_BYTE(tmp0,tmp1,tmp2);
        MAKE_WORD(d_conf,tmp1,tmp2);
-       pci_write_config_word(dev, 0x40|(2*drive_number), d_conf);
+       pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
 
        tmp1 = 0x00;
        tmp2 = 0x00;
        pci_read_config_byte(dev, 0x54, &ultra);
-       tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number))));
+       tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
        ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-       tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number))));
+       tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
        pci_write_config_byte(dev, 0x54, tmp2);
 
        __restore_flags(flags); /* local CPU only */
@@ -261,7 +264,6 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        byte unit               = (drive->select.b.unit & 0x01);
-       int drive_number        = ((hwif->channel ? 2 : 0) + unit);
        byte ultra_pci          = hwif->channel ? 0x45 : 0x44;
        int err                 = 0;
        byte drive_conf         = 0x00;
@@ -269,15 +271,14 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
        byte ultra              = 0x00;
        byte tmp1               = 0x00;
        byte tmp2               = 0x00;
-
        unsigned long flags;
 
        __save_flags(flags);    /* local CPU only */
        __cli();                /* local CPU only */
 
-       pci_read_config_byte(dev, 0x40|drive_number, &drive_conf);
+       pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
        drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-       pci_write_config_byte(dev, 0x40|drive_number, drive_conf);
+       pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
 
        pci_read_config_byte(dev, ultra_pci, &ultra);
        tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
@@ -286,10 +287,24 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
        pci_write_config_byte(dev, ultra_pci, tmp2);
        __restore_flags(flags); /* local CPU only */
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
        err = ide_config_drive_speed(drive, speed);
+       drive->current_speed = speed;
        return(err);
 }
 
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
+{
+       if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+               return ((int) aec6210_tune_chipset(drive, speed));
+       } else {
+               return ((int) aec6260_tune_chipset(drive, speed));
+       }
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
@@ -524,7 +539,7 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif)
 {
 #ifdef CONFIG_AEC62XX_TUNING
        hwif->tuneproc = &aec62xx_tune_drive;
-
+       hwif->speedproc = &aec62xx_tune_chipset;
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_base)
                hwif->dmaproc = &aec62xx_dmaproc;
index c5f570674a10721f531fc8cf831f9d06d7040a45..02af0a0f801a1080f15adf571f3a2c79b4e5466e 100644 (file)
@@ -333,6 +333,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
 
        err = ide_config_drive_speed(drive, speed);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
        if (speed >= XFER_SW_DMA_0) {
                unsigned long dma_base = hwif->dma_base;
 
@@ -353,6 +354,9 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
                        pci_write_config_byte(dev, 0x4b, tmpbyte);
                }
        }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+       drive->current_speed = speed;
 
        return (err);
 }
@@ -399,6 +403,9 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
 
        (void) ali15x3_tune_chipset(drive, speed);
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
        rval = (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 :
@@ -629,7 +636,7 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
         * has 80-pin (from host view)
         */
        pci_read_config_byte(dev, 0x4a, &tmpbyte);
-       ata66 = (!(tmpbyte & ata66mask)) ? 0 : 1;
+       ata66 = (!(tmpbyte & ata66mask)) ? 1 : 0;
        __restore_flags(flags);
 
        return(ata66);
@@ -673,6 +680,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
        hwif->tuneproc = &ali15x3_tune_drive;
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
+       hwif->speedproc = &ali15x3_tune_chipset;
 #ifndef CONFIG_BLK_DEV_IDEDMA
        hwif->autodma = 0;
        return;
index 14a8a83f15c789f2dc551546fdd6d3da00f6379d..d54a240d4c931c64632ccb1d1e3f8c2ee9b5a22c 100644 (file)
@@ -81,21 +81,22 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
        struct pci_dev *dev     = hwif->pci_dev;
        int err                 = 0;
        byte unit               = (drive->select.b.unit & 0x01);
-       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + unit);
+#ifdef CONFIG_BLK_DEV_IDEDMA
        unsigned long dma_base  = hwif->dma_base;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        byte drive_pci          = 0x00;
        byte drive_pci2         = 0x00;
        byte ultra_timing       = 0x00;
        byte dma_pio_timing     = 0x00;
        byte pio_timing         = 0x00;
 
-        switch (drive_number) {
+        switch (drive->dn) {
                case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
                case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
                case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
                case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
                default:
-                        return ((int) ide_dma_off_quietly);
+                        return -1;
         }
 
        pci_read_config_byte(dev, drive_pci, &ultra_timing);
@@ -109,7 +110,7 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
 
        ultra_timing &= ~0xC7;
        dma_pio_timing &= ~0xFF;
-       pio_timing &= ~(0x03 << drive_number);
+       pio_timing &= ~(0x03 << drive->dn);
 
 #ifdef DEBUG
        printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
@@ -117,67 +118,74 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
 #endif
 
        switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
                case XFER_UDMA_4:
                        ultra_timing |= 0x45;
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_UDMA_3:
                        ultra_timing |= 0x44;
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_UDMA_2:
                        ultra_timing |= 0x40;
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_UDMA_1:
                        ultra_timing |= 0x41;
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_UDMA_0:
                        ultra_timing |= 0x42;
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_MW_DMA_2:
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_MW_DMA_1:
                        dma_pio_timing |= 0x21;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_MW_DMA_0:
                        dma_pio_timing |= 0x77;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
                case XFER_PIO_4:
                        dma_pio_timing |= 0x20;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_PIO_3:
                        dma_pio_timing |= 0x22;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_PIO_2:
                        dma_pio_timing |= 0x42;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_PIO_1:
                        dma_pio_timing |= 0x65;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
                case XFER_PIO_0:
                default:
                        dma_pio_timing |= 0xA8;
-                       pio_timing |= (0x03 << drive_number);
+                       pio_timing |= (0x03 << drive->dn);
                        break;
         }
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
        pci_write_config_byte(dev, drive_pci, ultra_timing);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
        pci_write_config_byte(dev, 0x4c, pio_timing);
 
@@ -186,12 +194,16 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
                ultra_timing, dma_pio_timing, pio_timing);
 #endif
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
        if (speed > XFER_PIO_4) {
                outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
        } else {
                outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
        }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
        err = ide_config_drive_speed(drive, speed);
+       drive->current_speed = speed;
        return (err);
 }
 
@@ -231,6 +243,7 @@ static void config_chipset_for_pio (ide_drive_t *drive)
                        break;
        }
        (void) amd7409_tune_chipset(drive, speed);
+       drive->current_speed = speed;
 }
 
 static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
@@ -403,13 +416,14 @@ unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
 void __init ide_init_amd7409 (ide_hwif_t *hwif)
 {
        hwif->tuneproc = &amd7409_tune_drive;
+       hwif->speedproc = &amd7409_tune_chipset;
 
 #ifndef CONFIG_BLK_DEV_IDEDMA
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
        hwif->autodma = 0;
        return;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#else
 
        if (hwif->dma_base) {
                hwif->dmaproc = &amd7409_dmaproc;
@@ -419,6 +433,7 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif)
                hwif->drives[0].autotune = 1;
                hwif->drives[1].autotune = 1;
        }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
 void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase)
index 8e100de3c20a12fd73edafa44146aa9377eff0d7..7e9f0c7eecb9a4dfe339016d0730c921e2a67b63 100644 (file)
@@ -344,9 +344,9 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
                (void) ide_config_drive_speed(drive, speed);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
+static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
 {
+#ifdef CONFIG_BLK_DEV_IDEDMA
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        byte unit               = (drive->select.b.unit & 0x01);
@@ -357,6 +357,8 @@ static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
        u8 regU                 = 0;
        u8 regD                 = 0;
 
+       if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))      return 1;
+
        (void) pci_read_config_byte(dev, pciD, &regD);
        (void) pci_read_config_byte(dev, pciU, &regU);
        regD &= ~(unit ? 0x40 : 0x20);
@@ -378,17 +380,37 @@ static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
                case XFER_SW_DMA_2:     regD |= (unit ? 0x40 : 0x10); break;
                case XFER_SW_DMA_1:     regD |= (unit ? 0x80 : 0x20); break;
                case XFER_SW_DMA_0:     regD |= (unit ? 0xC0 : 0x30); break;
+#else
+       int err                 = 0;
+
+       switch(speed) {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               case XFER_PIO_4:        cmd64x_tuneproc(drive, 4); break;
+               case XFER_PIO_3:        cmd64x_tuneproc(drive, 3); break;
+               case XFER_PIO_2:        cmd64x_tuneproc(drive, 2); break;
+               case XFER_PIO_1:        cmd64x_tuneproc(drive, 1); break;
+               case XFER_PIO_0:        cmd64x_tuneproc(drive, 0); break;
+
                default:
                        return 1;
        }
+#ifdef CONFIG_BLK_DEV_IDEDMA
        (void) pci_write_config_byte(dev, pciU, regU);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
        err = ide_config_drive_speed(drive, speed);
+
+       drive->current_speed = speed;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
        regD |= (unit ? 0x40 : 0x20);
        (void) pci_write_config_byte(dev, pciD, regD);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
        return err;
 }
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
 static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
        struct hd_driveid *id   = drive->id;
@@ -450,12 +472,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
                set_pio = 1;
        }
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
        config_chipset_for_pio(drive, set_pio);
 
        if (set_pio)
                return ((int) ide_dma_off_quietly);
 
-       if (tune_chipset_for_dma(drive, speed))
+       if (cmd64x_tune_chipset(drive, speed))
                return ((int) ide_dma_off);
 
        rval = (int)(   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
@@ -680,8 +705,9 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
        class_rev &= 0xff;
 
        hwif->tuneproc = &cmd64x_tuneproc;
+       hwif->speedproc = &cmd64x_tune_chipset;
        hwif->drives[0].autotune = 1;
-       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
 
        if (!hwif->dma_base)
                return;
index a68e7f7408af1f4ca97f272be0a427fac753805a..911068f7846139fe4d00836066117a7ef8df1adc 100644 (file)
@@ -96,14 +96,13 @@ extern char *ide_xfer_verbose (byte xfer_rate);
 
 static void hpt34x_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 = (reg2 & ~(0x11 << drive_number));
+       tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+       tmp2 = (reg2 & ~(0x11 << drive->dn));
        pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
        pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
 }
@@ -112,7 +111,6 @@ static int hpt34x_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;
 
@@ -127,20 +125,24 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
 
        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);
+       tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+       tmp2 = ((hi_speed << drive->dn) | reg2);
        err = ide_config_drive_speed(drive, speed);
        pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
        pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
 #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,
+               drive->dn, reg1, tmp1, reg2, tmp2,
                hi_speed, lo_speed, err);
 #endif /* HPT343_DEBUG_DRIVE_INFO */
 
+       drive->current_speed = speed;
        return(err);
 }
 
@@ -410,6 +412,7 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
 void __init ide_init_hpt34x (ide_hwif_t *hwif)
 {
        hwif->tuneproc = &hpt34x_tune_drive;
+       hwif->speedproc = &hpt34x_tune_chipset;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_base) {
index fd5971ef96497220c9bd3bb4f367d488106d44de..28232b5768dc51ebf1a45dd51a762d7242fe8ca5 100644 (file)
@@ -173,6 +173,14 @@ extern char *ide_xfer_verbose (byte xfer_rate);
 byte hpt363_shared_irq = 0;
 byte hpt363_shared_pin = 0;
 
+static unsigned int pci_rev_check_hpt366 (struct pci_dev *dev)
+{
+       unsigned int class_rev;
+       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+       class_rev &= 0xff;
+       return ((int) (class_rev == 0x03) ? 1 : 0);
+}
+
 static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 {
        struct hd_driveid *id = drive->id;
@@ -212,9 +220,6 @@ static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_lis
 static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
        int                     err;
-#if HPT366_DEBUG_DRIVE_INFO
-       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-#endif /* HPT366_DEBUG_DRIVE_INFO */
        byte regtime            = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
        unsigned int reg1       = 0;
        unsigned int reg2       = 0;
@@ -251,11 +256,15 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
        pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
        err = ide_config_drive_speed(drive, speed);
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
 #if HPT366_DEBUG_DRIVE_INFO
        printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n",
                drive->name, speed, ide_xfer_verbose(speed),
-               drive_number, reg1, reg2, err);
+               drive->dn, reg1, reg2, err);
 #endif /* HPT366_DEBUG_DRIVE_INFO */
+       drive->current_speed = speed;
        return(err);
 }
 
@@ -469,10 +478,12 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                case ide_dma_check:
                        return config_drive_xfer_rate(drive);
                case ide_dma_lostirq:
+#if 0
                        pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
                        pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0x03);
                        pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
                        /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */
+#endif
                case ide_dma_timeout:
                default:
                        break;
@@ -508,6 +519,8 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
        if (!hpt366_proc) {
                hpt366_proc = 1;
                bmide_dev = dev;
+               if (pci_rev_check_hpt366(dev))
+                       bmide2_dev = dev;
                hpt366_display_info = &hpt366_get_info;
        }
        if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
@@ -533,7 +546,11 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+       if (pci_rev_check_hpt366(hwif->pci_dev)) return;
+
        hwif->tuneproc = &hpt366_tune_drive;
+       hwif->speedproc = &hpt366_tune_chipset;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_base) {
                hwif->dmaproc = &hpt366_dmaproc;
@@ -556,6 +573,11 @@ void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
        byte dma_new = 0, dma_old = inb(dmabase+2);
        unsigned long flags;
 
+       if (pci_rev_check_hpt366(hwif->pci_dev)) {
+               ide_setup_dma(hwif, dmabase, 8);
+               return;
+       }
+
        __save_flags(flags);    /* local CPU only */
        __cli();                /* local CPU only */
 
index 8ef0f9356e1b80acf2a864f9f72aa7af7a133ebf..dcc50362faae8c4e5c100333b04fe45b78fb6219 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/pci.h>
 #include <linux/init.h>
 
 #include <asm/dma.h>
@@ -219,55 +220,73 @@ static iftype_t icside_identifyif (struct expansion_card *ec)
  * here, but we rely on the main IDE driver spotting that both
  * interfaces use the same IRQ, which should guarantee this.
  */
-#define TABLE_SIZE 2048
+#define NR_ENTRIES 256
+#define TABLE_SIZE (NR_ENTRIES * 8)
 
-static int
-icside_build_dmatable(ide_drive_t *drive, int reading)
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
 {
-       struct request *rq = HWGROUP(drive)->rq;
-       struct buffer_head *bh = rq->bh;
-       unsigned long addr, size;
-       unsigned char *virt_addr;
-       unsigned int count = 0;
-       dmasg_t *sg = (dmasg_t *)HWIF(drive)->dmatable_cpu;
+       struct buffer_head *bh;
+       struct scatterlist *sg = hwif->sg_table;
+       int nents = 0;
 
+       if (rq->cmd == READ)
+               hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+       else
+               hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+       bh = rq->bh;
        do {
-               if (bh == NULL) {
-                       /* paging requests have (rq->bh == NULL) */
-                       virt_addr = rq->buffer;
-                       addr = virt_to_bus (virt_addr);
-                       size = rq->nr_sectors << 9;
-               } else {
-                       /* group sequential buffers into one large buffer */
-                       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))
-                                       break;
-                               size += bh->b_size;
-                       }
-               }
+               unsigned char *virt_addr = bh->b_data;
+               unsigned int size = bh->b_size;
 
-               if (addr & 3) {
-                       printk("%s: misaligned DMA buffer\n", drive->name);
-                       return 0;
+               while ((bh = bh->b_reqnext) != NULL) {
+                       if ((virt_addr + size) != (unsigned char *)bh->b_data)
+                               break;
+                       size += bh->b_size;
                }
+               memset(&sg[nents], 0, sizeof(*sg));
+               sg[nents].address = virt_addr;
+               sg[nents].length = size;
+               nents++;
+       } while (bh != NULL);
 
-               if (size) {
-                       if (reading)
-                               dma_cache_inv((unsigned int)virt_addr, size);
-                       else
-                               dma_cache_wback((unsigned int)virt_addr, size);
-               }
+       return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
 
-               sg[count].address = addr;
-               sg[count].length = size;
-               if (++count >= (TABLE_SIZE / sizeof(dmasg_t))) {
-                       printk("%s: DMA table too small\n", drive->name);
+static int
+icside_build_dmatable(ide_drive_t *drive, int reading)
+{
+       dmasg_t *ide_sg = (dmasg_t *)HWIF(drive)->dmatable_cpu;
+       unsigned int count = 0;
+       int i;
+       struct scatterlist *sg;
+
+       HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+
+       sg = HWIF(drive)->sg_table;
+       while (i && sg_dma_len(sg)) {
+               u32 cur_addr;
+               u32 cur_len;
+
+               cur_addr = sg_dma_address(sg);
+               cur_len  = sg_dma_len(sg);
+
+               if (count >= (TABLE_SIZE / sizeof(dmasg_t))) {
+                       printk("%s: DMA table too small\n",
+                               drive->name);
+                       pci_unmap_sg(NULL,
+                                    HWIF(drive)->sg_table,
+                                    HWIF(drive)->sg_nents,
+                                    HWIF(drive)->sg_dma_direction);
                        return 0;
+               } else {
+                       ide_sg[count].address = cur_addr;
+                       ide_sg[count].length  = cur_len;
                }
-       } while (bh != NULL);
+
+               count++;
+               sg++;
+               i--;
+       }
 
        if (!count)
                printk("%s: empty DMA table?\n", drive->name);
@@ -275,6 +294,15 @@ icside_build_dmatable(ide_drive_t *drive, int reading)
        return count;
 }
 
+/* Teardown mappings after DMA has completed.  */
+static void icside_destroy_dmatable(ide_drive_t *drive)
+{
+       struct scatterlist *sg = HWIF(drive)->sg_table;
+       int nents = HWIF(drive)->sg_nents;
+
+       pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
 static int
 icside_config_if(ide_drive_t *drive, int xfer_mode)
 {
@@ -303,6 +331,9 @@ icside_config_if(ide_drive_t *drive, int xfer_mode)
                break;
        }
 
+       if (!drive->init_speed)
+               drive->init_speed = (byte) xfer_mode;
+
        if (drive->drive_data &&
            ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
                func = ide_dma_on;
@@ -312,9 +343,17 @@ icside_config_if(ide_drive_t *drive, int xfer_mode)
        printk("%s: %s selected (peak %dMB/s)\n", drive->name,
                ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 
+       drive->current_speed = (byte) xfer_mode;
+
        return func;
 }
 
+static int
+icside_set_speed(ide_drive_t *drive, byte speed)
+{
+       return ((int) icside_config_if(drive, (int) speed));
+}
+
 static int
 icside_dma_check(ide_drive_t *drive)
 {
@@ -415,6 +454,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
        case ide_dma_end:
                drive->waiting_for_dma = 0;
                disable_dma(hwif->hw.dma);
+               icside_destroy_dmatable(drive);
                return get_dma_residue(hwif->hw.dma) != 0;
 
        case ide_dma_test_irq:
@@ -425,8 +465,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
        }
 }
 
-static unsigned long
-icside_alloc_dmatable(void)
+static void *icside_alloc_dmatable(void)
 {
        static unsigned long dmatable;
        static unsigned int leftover;
@@ -448,28 +487,39 @@ icside_alloc_dmatable(void)
                leftover -= TABLE_SIZE;
        }
 
-       return table;
+       return (void *)table;
 }
 
 static int
 icside_setup_dma(ide_hwif_t *hwif, int autodma)
 {
-       unsigned long table = icside_alloc_dmatable();
-
        printk("    %s: SG-DMA", hwif->name);
 
-       if (!table)
-               printk(" -- ERROR, unable to allocate DMA table\n");
-       else {
-               hwif->dmatable_cpu = (void *)table;
-               hwif->dmaproc = icside_dmaproc;
-               hwif->autodma = autodma;
+       hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+                                GFP_KERNEL);
+       if (!hwif->sg_table)
+               goto failed;
+
+       hwif->dmatable_cpu = icside_alloc_dmatable();
 
-               printk(" capable%s\n", autodma ?
-                       ", auto-enable" : "");
+       if (!hwif->dmatable_cpu) {
+               kfree(hwif->sg_table);
+               hwif->sg_table = NULL;
+               goto failed;
        }
 
-       return hwif->dmatable_cpu != NULL;
+       hwif->dmaproc = &icside_dmaproc;
+       hwif->autodma = autodma;
+       hwif->speedproc = &icside_set_speed;
+
+       printk(" capable%s\n", autodma ?
+               ", auto-enable" : "");
+
+       return 1;
+
+failed:
+       printk(" -- ERROR, unable to allocate DMA table\n");
+       return 0;
 }
 #endif
 
index 66bf35a70c0d551ca2a3545cef8e5f95b076e1d6..4e29520180495d621ff31d5338b24b5d4b1fc85b 100644 (file)
@@ -33,8 +33,6 @@
 
 #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>
@@ -688,13 +686,12 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
-       unsigned long flags;
-
-       if (ide_spin_wait_hwgroup(drive, &flags))
+       if (ide_spin_wait_hwgroup(drive))
                return -EBUSY;
+
        drive->nowerr = arg;
        drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-       spin_unlock_irqrestore(&io_request_lock, flags);
+       spin_unlock_irq(&io_request_lock);
        return 0;
 }
 
@@ -713,7 +710,7 @@ static void idedisk_add_settings(ide_drive_t *drive)
        ide_add_setting(drive,  "breada_readahead",     SETTING_RW,                                     BLKRAGET,               BLKRASET,               TYPE_INT,       0,      255,                            1,      2,      &read_ahead[major],             NULL);
        ide_add_setting(drive,  "file_readahead",       SETTING_RW,                                     BLKFRAGET,              BLKFRASET,              TYPE_INTA,      0,      INT_MAX,                        1,      1024,   &max_readahead[major][minor],   NULL);
        ide_add_setting(drive,  "max_kb_per_request",   SETTING_RW,                                     BLKSECTGET,             BLKSECTSET,             TYPE_INTA,      1,      255,                            1,      2,      &max_sectors[major][minor],     NULL);
-
+       ide_add_setting(drive,  "lun",                  SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      7,                              1,      1,      &drive->lun,                    NULL);
 }
 
 /*
index 371f57ad8dbe0fd0e1ed92edc93ee7494eba45cc..fcf0aab6337729b7a25ae7023a848ca899251f89 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/malloc.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/byteorder.h>
@@ -108,6 +109,46 @@ char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
        }
 }
 
+/*
+ *
+ */
+byte ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+       switch(drive->current_speed) {
+               case XFER_UDMA_7:       return XFER_UDMA_6;
+               case XFER_UDMA_6:       return XFER_UDMA_5;
+               case XFER_UDMA_5:       return XFER_UDMA_4;
+               case XFER_UDMA_4:       return XFER_UDMA_3;
+               case XFER_UDMA_3:       return XFER_UDMA_2;
+               case XFER_UDMA_2:       return XFER_UDMA_1;
+               case XFER_UDMA_1:       return XFER_UDMA_0;
+               case XFER_UDMA_0:
+                       if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
+                       else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
+                       else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
+                       else return XFER_PIO_4;
+               case XFER_MW_DMA_2:     return XFER_MW_DMA_1;
+               case XFER_MW_DMA_1:     return XFER_MW_DMA_0;
+               case XFER_MW_DMA_0:
+                       if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
+                       else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
+                       else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
+                       else return XFER_PIO_4;
+               case XFER_SW_DMA_2:     return XFER_SW_DMA_1;
+               case XFER_SW_DMA_1:     return XFER_SW_DMA_0;
+               case XFER_SW_DMA_0:
+                       {
+                               return XFER_PIO_4;
+                       }
+               case XFER_PIO_4:        return XFER_PIO_3;
+               case XFER_PIO_3:        return XFER_PIO_2;
+               case XFER_PIO_2:        return XFER_PIO_1;
+               case XFER_PIO_1:        return XFER_PIO_0;
+               case XFER_PIO_0:
+               default:                return XFER_PIO_SLOW;
+       }
+}
+
 /*
  * Update the 
  */
@@ -136,8 +177,10 @@ int ide_driveid_update (ide_drive_t *drive)
                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))
+       if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+               printk("%s: CHECK for good STATUS\n", drive->name);
                return 0;
+       }
        __save_flags(flags);    /* local CPU only */
        __cli();                /* local CPU only; some systems need this */
        id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
@@ -146,17 +189,14 @@ int ide_driveid_update (ide_drive_t *drive)
        ide__sti();             /* local CPU only */
        __restore_flags(flags); /* local CPU only */
        ide_fix_driveid(id);
-       if (id && id->cyls) {
+       if (id) {
                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);
        }
+
        return 1;
 }
 
@@ -167,7 +207,7 @@ int ide_driveid_update (ide_drive_t *drive)
  * in combination with the device (usually a disk) properly detect
  * and acknowledge each end of the ribbon.
  */
-int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature)
+int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
 {
        if ((cmd == WIN_SETFEATURES) &&
            (nsect > XFER_UDMA_2) &&
@@ -189,15 +229,16 @@ int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature)
  * 1 : Safe to update drive->id DMA registers.
  * 0 : OOPs not allowed.
  */
-int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature)
+int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
 {
-       struct hd_driveid *id = drive->id;
-
        if ((cmd == WIN_SETFEATURES) &&
            (nsect >= XFER_SW_DMA_0) &&
            (feature == SETFEATURES_XFER) &&
-           (id->dma_ultra || id->dma_mword || id->dma_1word))
+           (drive->id->dma_ultra ||
+            drive->id->dma_mword ||
+            drive->id->dma_1word))
                return 1;
+
        return 0;
 }
 
@@ -219,6 +260,8 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
        byte unit = (drive->select.b.unit & 0x01);
        byte stat;
 
+       outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+
        /*
         * Don't use ide_wait_cmd here - it will
         * attempt to set_geometry and recalibrate,
@@ -307,6 +350,7 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
        return error;
 }
 
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
 EXPORT_SYMBOL(ide_driveid_update);
 EXPORT_SYMBOL(ide_ata66_check);
 EXPORT_SYMBOL(set_transfer);
index 8d999d91c618f48f1029866616f4731d5e830b51..c10ae4b51cbf9144dde16c8050a4deff01a630f7 100644 (file)
@@ -30,6 +30,7 @@
 #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_PIIX4E   ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
+#define DEVID_PIIX4E2  ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
 #define DEVID_PIIX4U   ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
 #define DEVID_PIIX4U2  ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
 #define DEVID_VIA_IDE  ((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
@@ -303,6 +304,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
        {DEVID_PIIX3,   "PIIX3",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
        {DEVID_PIIX4,   "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
        {DEVID_PIIX4E,  "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
+       {DEVID_PIIX4E2, "PIIX4",        PCI_PIIX,       NULL,           INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
        {DEVID_PIIX4U,  "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
        {DEVID_PIIX4U2, "PIIX4",        PCI_PIIX,       ATA66_PIIX,     INIT_PIIX,      NULL,           {{0x41,0x80,0x80}, {0x43,0x80,0x80}},   ON_BOARD,       0 },
        {DEVID_VIA_IDE, "VIA_IDE",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
@@ -476,6 +478,7 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *
        unsigned short pcicmd = 0, tried_config = 0;
        byte tmp = 0;
        ide_hwif_t *hwif, *mate = NULL;
+       unsigned int class_rev;
 
 #ifdef CONFIG_IDEDMA_AUTO
        autodma = 1;
@@ -504,6 +507,11 @@ check_if_enabled:
        }
        if (tried_config)
                printk("%s: device enabled (Linux)\n", d->name);
+
+       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+       class_rev &= 0xff;
+       printk("%s: chipset revision %d\n", d->name, class_rev);
+
        /*
         * Can we trust the reported IRQ?
         */
@@ -545,7 +553,7 @@ check_if_enabled:
                ide_pci_enablebit_t *e = &(d->enablebits[port]);
                if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
                        continue;       /* port not enabled */
-               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port))
+               if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev != 0x03))
                        return;
                if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
                        ctl  = dev->resource[(2*port)+1].start;
@@ -656,9 +664,19 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_devic
        struct pci_dev *dev2 = NULL, *findev;
        ide_pci_device_t *d2;
        unsigned char pin1 = 0, pin2 = 0;
+       unsigned int class_rev;
 
        if (PCI_FUNC(dev->devfn) & 1)
                return;
+
+       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+       class_rev &= 0xff;
+
+       switch(class_rev) {
+               case 3:         return;
+               default:        break;
+       }
+
        pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
        pci_for_each_dev(findev) {
                if ((findev->vendor == dev->vendor) &&
index 7f5226db9db1a3fa4912203ecded9a3cf0a06d87..45bbe77ac1309674433ed194f15b91eccf5d0b92 100644 (file)
@@ -7,6 +7,8 @@
  *
  *  Copyright (C) 1998 Paul Mackerras.
  *
+ *  Bits from Benjamin Herrenschmidt
+ *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *
- * BenH: I began adding more complete timing setup code, mostly because DMA
- *       won't work on new machines unless timings are setup correctly. This
- *       code was mainly stolen from Cmd646 driver and should be completed to
- *       include real timing calc. instead of hard coded values. The format of
- *       the timing register can be found in Darwin's source code, except for
- *       Keylargo ATA-4 controller.
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #endif
 #include "ide_modes.h"
 
+extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+
 #undef IDE_PMAC_DEBUG
 
-#define IDE_SYSCLK_NS  30
+#define IDE_SYSCLK_NS          30
+#define IDE_SYSCLK_ULTRA_PS    0x1d4c /* (15 * 1000 / 2)*/
 
 struct pmac_ide_hwif {
        ide_ioreg_t                     regbase;
        int                             irq;
        int                             kind;
+       int                             aapl_bus_id;
        struct device_node*             node;
        u32                             timings[2];
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -90,17 +90,27 @@ static pmac_ide_timing mdma_timings[] =
 static pmac_ide_timing udma_timings[] =
 {
     {   0,    114 },   /* Mode 0 */
-    {   0,     73 },   /*      1 */
-    {   0,     54 },   /*      2 */
-    {   0,     39 },   /*      3 */
-    {   0,     25 }    /*      4 */
+    {   0,     75 },   /*      1 */
+    {   0,     55 },   /*      2 */
+    {   100,   45 },   /*      3 */
+    {   100,   25 }    /*      4 */
 };
 
-#define MAX_DCMDS      256     /* allow up to 256 DBDMA commands per xfer */
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS              256
+
+/* Wait 1.5s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS    1500
 
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
 static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
 static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
 static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
 static void pmac_ide_selectproc(ide_drive_t *drive);
 
@@ -156,14 +166,6 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw,
                return;
        }
 
-       /* we check only for -EINVAL meaning that we have found a matching
-          bay but with the wrong device type */ 
-       i = check_media_bay_by_base(data_port, MB_CD);
-       if (i == -EINVAL) {
-               hw->io_ports[IDE_DATA_OFFSET] = 0;
-               return;
-       }
-
        for (i = 0; i < 8; ++i)
                hw->io_ports[i] = data_port + i * 0x10;
        hw->io_ports[8] = data_port + 0x160;
@@ -178,6 +180,7 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw,
 #ifdef CONFIG_PMAC_IDEDMA_AUTO
                ide_hwifs[ix].autodma = 1;
 #endif
+//             ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
        }
 }
 
@@ -214,7 +217,9 @@ pmac_ide_selectproc(ide_drive_t *drive)
 
 /* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
 #define SYSCLK_TICKS(t)                (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_UDMA(t)   (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)
 
+/* Calculate PIO timings */
 static void
 pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
 {
@@ -227,26 +232,31 @@ pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
        if (i < 0)
                return;
                
-       /* The "ata-4" IDE controller of UMA machines is a bit different.
-        * We don't do anything for PIO modes until we know how to do the
-        * calculation.
-        */
-       if (pmac_ide[i].kind == controller_kl_ata4)
-               return;
-               
        pio = ide_get_best_pio_mode(drive, pio, 4, &d);
        accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
-       if (accessTicks < 4)
-               accessTicks = 4;
-       recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
-       if (recTicks < 1)
-               recTicks = 1;
        if (drive->select.all & 0x10)
                timings = &pmac_ide[i].timings[1];
        else
                timings = &pmac_ide[i].timings[0];
        
-       *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);  
+       if (pmac_ide[i].kind == controller_kl_ata4) {
+               /* The "ata-4" IDE controller of Core99 machines */
+               accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000);
+               recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks;
+
+               *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+       } else {
+               /* The old "ata-3" IDE controller */
+               accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+               if (accessTicks < 4)
+                       accessTicks = 4;
+               recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
+               if (recTicks < 1)
+                       recTicks = 1;
+       
+               *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
+       }
+
 #ifdef IDE_PMAC_DEBUG
        printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
                pio,  *timings);
@@ -294,7 +304,7 @@ pmac_ide_probe(void)
        struct device_node *atas;
        struct device_node *p, **pp, *removables, **rp;
        unsigned long base;
-       int irq;
+       int irq, big_delay;
        ide_hwif_t *hwif;
 
        if (_machine != _MACH_Pmac)
@@ -322,9 +332,11 @@ pmac_ide_probe(void)
        }
        *rp = NULL;
        *pp = removables;
+       big_delay = 0;
 
        for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
                struct device_node *tp;
+               int *bidp;
 
                /*
                 * If this node is not under a mac-io or dbdma node,
@@ -378,6 +390,9 @@ pmac_ide_probe(void)
                else
                        pmac_ide[i].kind = controller_ohare;
 
+               bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+               pmac_ide[i].aapl_bus_id =  bidp ? *bidp : 0;
+
                if (np->parent && np->parent->name
                    && strcasecmp(np->parent->name, "media-bay") == 0) {
                        media_bay_set_ide_infos(np->parent,base,irq,i);
@@ -388,42 +403,41 @@ pmac_ide_probe(void)
                         */
                         feature_set(np, FEATURE_IDE0_enable);
                } else {
-                       /* This is necessary to enable IDE when net-booting */
-                       int *bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-                       int bid = bidp ? *bidp : 0;
-                       printk("pmac_ide: enabling IDE bus ID %d\n", bid);
-                       switch(bid) {
+                       /* This is necessary to enable IDE when net-booting */
+                       printk("pmac_ide: enabling IDE bus ID %d\n",
+                               pmac_ide[i].aapl_bus_id);
+                       switch(pmac_ide[i].aapl_bus_id) {
                            case 0:
                                feature_set(np, FEATURE_IDE0_reset);
-                               feature_set(np, FEATURE_IOBUS_enable);
                                mdelay(10);
                                feature_set(np, FEATURE_IDE0_enable);
                                mdelay(10);
                                feature_clear(np, FEATURE_IDE0_reset);
                                break;
                            case 1:
-                               feature_set(np, FEATURE_Mediabay_IDE_reset);
+                               feature_set(np, FEATURE_IDE1_reset);
                                mdelay(10);
-                               feature_set(np, FEATURE_Mediabay_IDE_enable);
+                               feature_set(np, FEATURE_IDE1_enable);
                                mdelay(10);
-                               feature_clear(np, FEATURE_Mediabay_IDE_reset);
+                               feature_clear(np, FEATURE_IDE1_reset);
                                break;
                            case 2:
-                               /* This one exists only for KL, I don't know about any
-                                  enable bit */
+                               /* This one exists only for KL, I don't know
+                                  about any enable bit */
                                feature_set(np, FEATURE_IDE2_reset);
                                mdelay(10);
                                feature_clear(np, FEATURE_IDE2_reset);
                                break;
                        }
-                       mdelay(1000);
+                       big_delay = 1;
                }
 
                hwif = &ide_hwifs[i];
                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_pmac;
-               hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+               hwif->noprobe = (!hwif->io_ports[IDE_DATA_OFFSET]) ||
+                       (check_media_bay_by_base(base, MB_CD) == -EINVAL);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
                if (np->n_addrs >= 2) {
@@ -435,6 +449,8 @@ pmac_ide_probe(void)
                ++i;
        }
        pmac_ide_count = i;
+       if (big_delay)
+               mdelay(IDE_WAKEUP_DELAY_MS);
 
 #ifdef CONFIG_PMAC_PBOOK
        pmu_register_sleep_notifier(&idepmac_sleep_notifier);
@@ -642,6 +658,7 @@ out:
        return result;
 }
 
+/* Calculate MultiWord DMA timings */
 static int
 pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
 {
@@ -652,18 +669,15 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
        int accessTicks, recTicks;
        struct hd_driveid *id = drive->id;
        
-       /* For now, we don't know these values */
-       if (pmac_ide[idx].kind == controller_kl_ata4 && feature != IDE_DMA2_ENABLE)
-               return 0;
-       if (pmac_ide[idx].kind != controller_kl_ata4 && feature == IDE_DMA0_ENABLE)
-               return 0;
-                               
        /* Set feature on drive */
        printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
        if (pmac_ide_do_setfeature(drive, feature)) {
                printk("%s: Failed !\n", drive->name);
                return 0;
        }
+
+       if (!drive->init_speed)
+               drive->init_speed = feature;
        
        /* which drive is it ? */
        if (drive->select.all & 0x10)
@@ -681,7 +695,10 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
 
        /* For ata-4 controller, we don't know the calculation */
        if (pmac_ide[idx].kind == controller_kl_ata4) {
-               *timings = 0x00019465;  /* MDMA2 */
+               accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+               recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
+               *timings = ((*timings) & 0xffe003ff) |
+                       (accessTicks | (recTicks << 5)) << 10;
        } else {
                int halfTick = 0;
                int origAccessTime = accessTime;
@@ -696,7 +713,9 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
                        recTicks = 1;
                cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
 
-               if ((accessTicks > 1) &&
+               /* KeyLargo ata-3 don't support the half-tick stuff */
+               if ((pmac_ide[idx].kind != controller_kl_ata3) &&
+                       (accessTicks > 1) &&
                        ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
                        ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
                                halfTick    = 1;
@@ -708,21 +727,21 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
 #ifdef IDE_PMAC_DEBUG
        printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
                feature & 0xf, *timings);
-#endif 
+#endif
+       drive->current_speed = feature; 
        return 1;
 }
 
+/* Calculate Ultra DMA timings */
 static int
 pmac_ide_udma_enable(ide_drive_t *drive, int idx)
 {
        byte bits = drive->id->dma_ultra & 0x1f;
        byte feature = udma_bits_to_command(bits);
-       u32 timings;
+       int cycleTime, accessTime;
+       int rdyToPauseTicks, cycleTicks;
+       u32 *timings;
        
-       /* We support only those values */
-       if (feature != IDE_UDMA4_ENABLE && feature != IDE_UDMA2_ENABLE)
-               return 0;
-               
        /* Set feature on drive */
        printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
        if (pmac_ide_do_setfeature(drive, feature)) {
@@ -730,23 +749,25 @@ pmac_ide_udma_enable(ide_drive_t *drive, int idx)
                return 0;
        }
 
-       /* Put this channel into UDMA mode.
-        * This value is set by MacOS on the iBook for U/DMA2
-        */
-       switch(feature) {       
-               case IDE_UDMA4_ENABLE:
-                       timings = 0x0cd00065;
-                       break;
-               case IDE_UDMA2_ENABLE:
-                       timings = 0x11100065;
-                       break;
-       }
-       
+       if (!drive->init_speed)
+               drive->init_speed = feature;
+
+       /* which drive is it ? */
        if (drive->select.all & 0x10)
-               pmac_ide[idx].timings[1] = timings;
+               timings = &pmac_ide[idx].timings[1];
        else
-               pmac_ide[idx].timings[0] = timings;
-       
+               timings = &pmac_ide[idx].timings[0];
+
+       cycleTime = udma_timings[feature & 0xf].cycleTime;
+       accessTime = udma_timings[feature & 0xf].accessTime;
+
+       rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+       cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
+
+       *timings = ((*timings) & 0xe00fffff) |
+                       ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+
+       drive->current_speed = feature; 
        return 1;
 }
 
@@ -792,6 +813,12 @@ pmac_ide_dma_onoff(ide_drive_t *drive, int enable)
        return 0;
 }
 
+static int
+pmac_ide_tune_chipset(ide_drive_t *drive, byte speed)
+{
+       return 0;
+}
+
 int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
@@ -813,6 +840,7 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
                pmac_ide_dma_onoff(drive, (func == ide_dma_on));
                break;
        case ide_dma_check:
+               printk("IDE-DMA check !\n");
                if (hwif->autodma)
                        pmac_ide_dma_onoff(drive, 1);
                break;
@@ -837,8 +865,21 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
                return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
        case ide_dma_test_irq:
                return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN;
+
+               /* Let's implement tose just in case someone wants them */
+       case ide_dma_bad_drive:
+       case ide_dma_good_drive:
+               return check_drive_lists(drive, (func == ide_dma_good_drive));
+       case ide_dma_verbose:
+               return report_drive_dmaing(drive);
+       case ide_dma_retune:
+       case ide_dma_lostirq:
+       case ide_dma_timeout:
+               printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
+               return 1;
        default:
-               printk(KERN_ERR "pmac_ide_dmaproc: bad func %d\n", func);
+               printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+               return 1;
        }
        return 0;
 }
@@ -869,8 +910,20 @@ static void idepmac_sleep_disk(int i, unsigned long base)
                }
        }
        feature_set(np, FEATURE_IDE0_reset);
-       feature_clear(np, FEATURE_IOBUS_enable);
        feature_clear(np, FEATURE_IDE0_enable);
+       switch(pmac_ide[i].aapl_bus_id) {
+           case 0:
+               feature_set(np, FEATURE_IDE0_reset);
+               feature_clear(np, FEATURE_IDE0_enable);
+               break;
+           case 1:
+               feature_set(np, FEATURE_IDE1_reset);
+               feature_clear(np, FEATURE_IDE1_enable);
+               break;
+           case 2:
+               feature_set(np, FEATURE_IDE2_reset);
+               break;
+       }
        pmac_ide[i].timings[0] = 0;
        pmac_ide[i].timings[1] = 0;
 }
@@ -881,12 +934,30 @@ static void idepmac_wake_disk(int i, unsigned long base)
        int j;
 
        /* Revive IDE disk and controller */
-       feature_set(np, FEATURE_IOBUS_enable);
-       mdelay(10);
-       feature_set(np, FEATURE_IDE0_enable);
-       mdelay(10);
-       feature_clear(np, FEATURE_IDE0_reset);
-       mdelay(100);
+       switch(pmac_ide[i].aapl_bus_id) {
+           case 0:
+               feature_set(np, FEATURE_IDE0_reset);
+               mdelay(10);
+               feature_set(np, FEATURE_IDE0_enable);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE0_reset);
+               break;
+           case 1:
+               feature_set(np, FEATURE_IDE1_reset);
+               mdelay(10);
+               feature_set(np, FEATURE_IDE1_enable);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE1_reset);
+               break;
+           case 2:
+               /* This one exists only for KL, I don't know
+                  about any enable bit */
+               feature_set(np, FEATURE_IDE2_reset);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE2_reset);
+               break;
+       }
+       mdelay(IDE_WAKEUP_DELAY_MS);
 
        /* Reset timings */
        pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
@@ -940,7 +1011,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
                        /* Disable irq during sleep */
                        disable_irq(pmac_ide[i].irq);
                        ret = check_media_bay_by_base(base, MB_CD);
-                       if (ret == -ENODEV)
+                       if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
                                /* not media bay - put the disk to sleep */
                                idepmac_sleep_disk(i, base);
                }
@@ -953,7 +1024,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
                        hwif = &ide_hwifs[i];
                        /* We don't handle media bay devices this way */
                        ret = check_media_bay_by_base(base, MB_CD);
-                       if (ret == -ENODEV)
+                       if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
                                idepmac_wake_disk(i, base);
                        else if (ret == 0)
                                idepmac_wake_bay(i, base);
index 7c5130e77f5f67ff69b644a996b5a9b67478e47d..83b14b1fd7d3a01d961f6bc2ec6bb9e8e0667dc7 100644 (file)
@@ -56,6 +56,11 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
        ide_input_data(drive, id, SECTOR_WORDS);                /* read 512 bytes of id info */
        ide__sti();     /* local CPU only */
        ide_fix_driveid(id);
+
+       if (id->word156 == 0x4d42) {
+               printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
+       }
+
        if (!drive->forced_lun)
                drive->last_lun = id->last_lun & 0x7;
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
@@ -764,9 +769,10 @@ static void init_gendisk (ide_hwif_t *hwif)
                        char name[64];
 
                        ide_add_generic_settings(hwif->drives + unit);
+                       hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
                        sprintf (name, "host%d/bus%d/target%d/lun%d",
                                 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
-                                hwif->channel, unit, 0);
+                                hwif->channel, unit, hwif->drives[unit].lun);
                        hwif->drives[unit].de =
                                devfs_mk_dir (ide_devfs_handle, name, 0, NULL);
                }
@@ -775,9 +781,9 @@ static void init_gendisk (ide_hwif_t *hwif)
 
 static int hwif_init (ide_hwif_t *hwif)
 {
-       ide_drive_t *drive;
-       void (*rfn)(request_queue_t *);
-       
+       request_queue_t *q;
+       unsigned int unit;
+
        if (!hwif->present)
                return 0;
        if (!hwif->irq) {
@@ -795,39 +801,7 @@ static int hwif_init (ide_hwif_t *hwif)
 #endif /* CONFIG_BLK_DEV_HD */
        
        hwif->present = 0; /* we set it back to 1 if all is ok below */
-       switch (hwif->major) {
-       case IDE0_MAJOR: rfn = &do_ide0_request; break;
-#if MAX_HWIFS > 1
-       case IDE1_MAJOR: rfn = &do_ide1_request; break;
-#endif
-#if MAX_HWIFS > 2
-       case IDE2_MAJOR: rfn = &do_ide2_request; break;
-#endif
-#if MAX_HWIFS > 3
-       case IDE3_MAJOR: rfn = &do_ide3_request; break;
-#endif
-#if MAX_HWIFS > 4
-       case IDE4_MAJOR: rfn = &do_ide4_request; break;
-#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
-#if MAX_HWIFS > 8
-       case IDE8_MAJOR: rfn = &do_ide8_request; break;
-#endif
-#if MAX_HWIFS > 9
-       case IDE9_MAJOR: rfn = &do_ide9_request; break;
-#endif
-       default:
-               printk("%s: request_fn NOT DEFINED\n", hwif->name);
-               return (hwif->present = 0);
-       }
+
        if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
                printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
                return (hwif->present = 0);
@@ -860,19 +834,11 @@ static int hwif_init (ide_hwif_t *hwif)
        read_ahead[hwif->major] = 8;    /* (4kB) */
        hwif->present = 1;      /* success */
 
-       /*
-        * FIXME(eric) - This needs to be tested.  I *think* that this
-        * is correct.   Also, I believe that there is no longer any
-        * reason to have multiple functions (do_ide[0-7]_request)
-        * functions - the queuedata field could be used to indicate
-        * the correct hardware group - either this, or we could add
-        * a new field to request_queue_t to hold this information.
-        */
-       drive = &hwif->drives[0];
-       blk_init_queue(&drive->queue, rfn);
-
-       drive = &hwif->drives[1];
-       blk_init_queue(&drive->queue, rfn);
+       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+               q = &hwif->drives[unit].queue;
+               q->queuedata = hwif->hwgroup;
+               blk_init_queue(q, do_ide_request);
+       }
 
 #if (DEBUG_SPINLOCK > 0)
 {
index 039c0bfd9fbfa7d34e39d288b97aa085c41b8fcc..cb34d354478e3a414c7e80471debb1ed5cd1d75d 100644 (file)
@@ -321,6 +321,7 @@ int drive_is_flashcard (ide_drive_t *drive)
                 || !strncmp(id->model, "Hitachi CV", 10)       /* Hitachi */
                 || !strncmp(id->model, "SunDisk SDCFB", 13)    /* SunDisk */
                 || !strncmp(id->model, "HAGIWARA HPC", 12)     /* Hagiwara */
+                || !strncmp(id->model, "LEXAR ATA_FLASH", 15)  /* Lexar */
                 || !strncmp(id->model, "ATA_FLASH", 9))        /* Simple Tech */
                {
                        return 1;       /* yes, it is a flash memory card */
@@ -767,6 +768,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
                        args[1] = err;
                        args[2] = IN_BYTE(IDE_NSECTOR_REG);
                }
+       } else if (rq->cmd == IDE_DRIVE_TASK) {
+               byte *args = (byte *) rq->buffer;
+               rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+               if (args) {
+                       args[0] = stat;
+                       args[1] = err;
+                       args[2] = IN_BYTE(IDE_NSECTOR_REG);
+                       args[3] = IN_BYTE(IDE_SECTOR_REG);
+                       args[4] = IN_BYTE(IDE_LCYL_REG);
+                       args[5] = IN_BYTE(IDE_HCYL_REG);
+                       args[6] = IN_BYTE(IDE_SELECT_REG);
+               }
        }
        spin_lock_irqsave(&io_request_lock, flags);
        blkdev_dequeue_request(rq);
@@ -876,7 +889,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
        if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
                return ide_stopped;
        /* retry only "normal" I/O: */
-       if (rq->cmd == IDE_DRIVE_CMD) {
+       if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
                rq->errors = 1;
                ide_end_drive_cmd(drive, stat, err);
                return ide_stopped;
@@ -1036,7 +1049,20 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, by
 static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
        byte *args = rq->buffer;
-       if (args) {
+       if (args && rq->cmd == IDE_DRIVE_TASK) {
+
+#ifdef DEBUG
+               printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
+                       drive->name, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+#endif
+               OUT_BYTE(args[1], IDE_FEATURE_REG);
+               OUT_BYTE(args[3], IDE_SECTOR_REG);
+               OUT_BYTE(args[4], IDE_LCYL_REG);
+               OUT_BYTE(args[5], IDE_HCYL_REG);
+               OUT_BYTE(args[6], IDE_SELECT_REG);
+               ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+               return ide_started;
+       } else if (args) {
 #ifdef DEBUG
                printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
                 drive->name, args[0], args[1], args[2], args[3]);
@@ -1116,7 +1142,7 @@ static ide_startstop_t start_request (ide_drive_t *drive)
                return startstop;
        }
        if (!drive->special.all) {
-               if (rq->cmd == IDE_DRIVE_CMD) {
+               if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
                        return execute_drive_cmd(drive, rq);
                }
                if (drive->driver != NULL) {
@@ -1225,7 +1251,7 @@ repeat:
  * the driver.  This makes the driver much more friendlier to shared IRQs
  * than previous designs, while remaining 100% (?) SMP safe and capable.
  */
-static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
 {
        ide_drive_t     *drive;
        ide_hwif_t      *hwif;
@@ -1313,73 +1339,13 @@ request_queue_t *ide_get_queue (kdev_t dev)
        return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
 
-void do_ide0_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[0].hwgroup, 0);
-}
-
-#if MAX_HWIFS > 1
-void do_ide1_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[1].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 1 */
-
-#if MAX_HWIFS > 2
-void do_ide2_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[2].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 2 */
-
-#if MAX_HWIFS > 3
-void do_ide3_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[3].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 3 */
-
-#if MAX_HWIFS > 4
-void do_ide4_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[4].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 4 */
-
-#if MAX_HWIFS > 5
-void do_ide5_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[5].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 5 */
-
-#if MAX_HWIFS > 6
-void do_ide6_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[6].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 6 */
-
-#if MAX_HWIFS > 7
-void do_ide7_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[7].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 7 */
-
-#if MAX_HWIFS > 8
-void do_ide8_request (request_queue_t *q)
-{
-       ide_do_request (ide_hwifs[8].hwgroup, 0);
-}
-#endif /* MAX_HWIFS > 8 */
-
-#if MAX_HWIFS > 9
-void do_ide9_request (request_queue_t *q)
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(request_queue_t *q)
 {
-       ide_do_request (ide_hwifs[9].hwgroup, 0);
+       ide_do_request(q->queuedata, 0);
 }
-#endif /* MAX_HWIFS > 9 */
 
 /*
  * ide_timer_expiry() is our timeout function for all drive operations.
@@ -1656,16 +1622,8 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
  */
 void ide_init_drive_cmd (struct request *rq)
 {
-       rq->buffer = NULL;
+       memset(rq, 0, sizeof(*rq));
        rq->cmd = IDE_DRIVE_CMD;
-       rq->sector = 0;
-       rq->nr_sectors = 0;
-       rq->nr_segments = 0;
-       rq->current_nr_sectors = 0;
-       rq->sem = NULL;
-       rq->bh = NULL;
-       rq->bhtail = NULL;
-       rq->q = NULL;
 }
 
 /*
@@ -2049,8 +2007,10 @@ void ide_unregister (unsigned int index)
                hwgroup->hwif = HWIF(hwgroup->drive);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       if (hwif->dma_base)
+       if (hwif->dma_base) {
                (void) ide_release_dma(hwif);
+               hwif->dma_base = 0;
+       }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
        /*
@@ -2083,6 +2043,7 @@ void ide_unregister (unsigned int index)
        init_hwif_data (index); /* restore hwif data to pristine status */
        hwif->hwgroup           = old_hwif.hwgroup;
        hwif->tuneproc          = old_hwif.tuneproc;
+       hwif->speedproc         = old_hwif.speedproc;
        hwif->selectproc        = old_hwif.selectproc;
        hwif->resetproc         = old_hwif.resetproc;
        hwif->dmaproc           = old_hwif.dmaproc;
@@ -2103,7 +2064,7 @@ void ide_unregister (unsigned int index)
        hwif->pci_devid         = old_hwif.pci_devid;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
        hwif->straight8         = old_hwif.straight8;
-
+       hwif->hwif_data         = old_hwif.hwif_data;
 abort:
        restore_flags(flags);   /* all CPUs */
 }
@@ -2304,24 +2265,24 @@ int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
        return val;
 }
 
-int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags)
+int ide_spin_wait_hwgroup (ide_drive_t *drive)
 {
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        unsigned long timeout = jiffies + (3 * HZ);
 
-       spin_lock_irqsave(&io_request_lock, *flags);
+       spin_lock_irq(&io_request_lock);
        while (hwgroup->busy) {
-               unsigned long lflags;
-               spin_unlock_irqrestore(&io_request_lock, *flags);
-               __save_flags(lflags);   /* local CPU only */
+               unsigned long flags;
+               spin_unlock_irq(&io_request_lock);
+               __save_flags(flags);    /* local CPU only */
                __sti();                /* local CPU only; needed for jiffies */
                if (0 < (signed long)(jiffies - timeout)) {
-                       __restore_flags(lflags);        /* local CPU only */
+                       __restore_flags(flags);
                        printk("%s: channel busy\n", drive->name);
                        return -EBUSY;
                }
-               __restore_flags(lflags);        /* local CPU only */
-               spin_lock_irqsave(&io_request_lock, *flags);
+               __restore_flags(flags); /* local CPU only */
+               spin_lock_irq(&io_request_lock);
        }
        return 0;
 }
@@ -2333,7 +2294,6 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags)
  */
 int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
 {
-       unsigned long flags;
        int i;
        u32 *p;
 
@@ -2345,7 +2305,7 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
                return -EINVAL;
        if (setting->set)
                return setting->set(drive, val);
-       if (ide_spin_wait_hwgroup(drive, &flags))
+       if (ide_spin_wait_hwgroup(drive))
                return -EBUSY;
        switch (setting->data_type) {
                case TYPE_BYTE:
@@ -2363,7 +2323,7 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
                                *p = val;
                        break;
        }
-       spin_unlock_irqrestore(&io_request_lock, flags);
+       spin_unlock_irq(&io_request_lock);
        return 0;
 }
 
@@ -2416,6 +2376,9 @@ void ide_add_generic_settings (ide_drive_t *drive)
        ide_add_setting(drive,  "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   HDIO_GET_UNMASKINTR,    HDIO_SET_UNMASKINTR,    TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL);
        ide_add_setting(drive,  "using_dma",            SETTING_RW,                                     HDIO_GET_DMA,           HDIO_SET_DMA,           TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma);
        ide_add_setting(drive,  "ide_scsi",             SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->scsi,                   NULL);
+       ide_add_setting(drive,  "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      69,                             1,              1,              &drive->init_speed,             NULL);
+       ide_add_setting(drive,  "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      69,                             1,              1,              &drive->current_speed,          NULL);
+       ide_add_setting(drive,  "number",               SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL);
 }
 
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
@@ -2435,6 +2398,16 @@ 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);
 }
 
+int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
+{
+       struct request rq;
+
+       ide_init_drive_cmd(&rq);
+       rq.cmd = IDE_DRIVE_TASK;
+       rq.buffer = buf;
+       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.
@@ -2551,6 +2524,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                case HDIO_DRIVE_CMD:
                {
                        byte args[4], *argbuf = args;
+                       byte xfer_rate = 0;
                        int argsize = 4;
                        if (!capable(CAP_SYS_ADMIN)) return -EACCES;
                        if (NULL == (void *) arg)
@@ -2564,18 +2538,22 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                        return -ENOMEM;
                                memcpy(argbuf, args, 4);
                        }
-                       if (ide_ata66_check(drive, args[0], args[1], args[2]))
-                               goto abort;
+
+                       if (set_transfer(drive, args[0], args[1], args[2])) {
+                               xfer_rate = args[1];
+                               if (ide_ata66_check(drive, args[0], args[1], args[2]))
+                                       goto abort;
+                       }
 
                        err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
 
-                       if (!err && set_transfer(drive, args[0], args[1], args[2])) {
-#if 0
+                       if (!err && xfer_rate) {
                                /* active-retuning-calls future */
-                               if (HWIF(drive)->tune2proc)
-                                       HWIF(drive)->tune2proc(drive, args[1]);
-#endif
+                               if ((HWIF(drive)->speedproc) != NULL)
+                                       HWIF(drive)->speedproc(drive, xfer_rate);
                                ide_driveid_update(drive);
+                       } else {
+                               printk("%s: \n", drive->name);
                        }
                abort:
                        if (copy_to_user((void *)arg, argbuf, argsize))
@@ -2584,6 +2562,18 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                kfree(argbuf);
                        return err;
                }
+               case HDIO_DRIVE_TASK:
+               {
+                       byte args[7], *argbuf = args;
+                       int argsize = 7;
+                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+                       if (copy_from_user(args, (void *)arg, 7))
+                               return -EFAULT;
+                       err = ide_wait_cmd_task(drive, argbuf);
+                       if (copy_to_user((void *)arg, argbuf, argsize))
+                               err = -EFAULT;
+                       return err;
+               }
 
                case HDIO_SCAN_HWIF:
                {
@@ -3512,37 +3502,9 @@ EXPORT_SYMBOL(ide_timer_expiry);
 EXPORT_SYMBOL(ide_intr);
 EXPORT_SYMBOL(ide_fops);
 EXPORT_SYMBOL(ide_get_queue);
-EXPORT_SYMBOL(do_ide0_request);
 EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(ide_devfs_handle);
-#if MAX_HWIFS > 1
-EXPORT_SYMBOL(do_ide1_request);
-#endif /* MAX_HWIFS > 1 */
-#if MAX_HWIFS > 2
-EXPORT_SYMBOL(do_ide2_request);
-#endif /* MAX_HWIFS > 2 */
-#if MAX_HWIFS > 3
-EXPORT_SYMBOL(do_ide3_request);
-#endif /* MAX_HWIFS > 3 */
-#if MAX_HWIFS > 4
-EXPORT_SYMBOL(do_ide4_request);
-#endif /* MAX_HWIFS > 4 */
-#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 */
-#if MAX_HWIFS > 8
-EXPORT_SYMBOL(do_ide8_request);
-#endif /* MAX_HWIFS > 8 */
-#if MAX_HWIFS > 9
-EXPORT_SYMBOL(do_ide9_request);
-#endif /* MAX_HWIFS > 9 */
-
+EXPORT_SYMBOL(do_ide_request);
 /*
  * Driver module
  */
@@ -3567,6 +3529,7 @@ EXPORT_SYMBOL(ide_end_request);
 EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
+EXPORT_SYMBOL(ide_wait_cmd_task);
 EXPORT_SYMBOL(ide_delay_50ms);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
@@ -3652,8 +3615,13 @@ void cleanup_module (void)
 {
        int index;
 
-       for (index = 0; index < MAX_HWIFS; ++index)
+       for (index = 0; index < MAX_HWIFS; ++index) {
                ide_unregister(index);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+               if (ide_hwifs[index].dma_base)
+                       (void) ide_release_dma(&ide_hwifs[index]);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+       }
 
 #ifdef CONFIG_PROC_FS
        proc_ide_destroy();
index b93c6ad1b672c8c4d80f80dc76a1d66bcb58af95..f16d3392143590d67ba598d6d30cce21b10a4ce2 100644 (file)
@@ -262,59 +262,99 @@ static void decode_registers (byte registers, byte value)
 
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-/*   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_chipset_for_pio (ide_drive_t *drive, byte pio)
+static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       byte                    drive_pci, speed;
-       byte                    AP, BP, TA, TB;
 
-       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-       int err;
+       unsigned int            drive_conf;
+       int                     err;
+       byte                    drive_pci, AP, BP, CP, DP;
+       byte                    TA = 0, TB = 0, TC = 0;
 
-       switch (drive_number) {
+       switch (drive->dn) {
                case 0: drive_pci = 0x60; break;
                case 1: drive_pci = 0x64; break;
                case 2: drive_pci = 0x68; break;
                case 3: drive_pci = 0x6c; break;
-               default: return 1;
+               default: return -1;
        }
 
+       if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))      return -1;
+
+       pci_read_config_dword(dev, drive_pci, &drive_conf);
        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);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA
+       if (speed >= XFER_SW_DMA_0) {
+               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);
+               }
+       } else {
+#else
+       {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               if ((AP & 0x0F) || (BP & 0x07)) {
+                       /* clear PIO modes of lower 8421 bits of A Register */
+                       pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+                       pci_read_config_byte(dev, (drive_pci), &AP);
 
-       if ((AP & 0x0F) || (BP & 0x07)) {
-               /* clear PIO modes of lower 8421 bits of A Register */
-               pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
-               pci_read_config_byte(dev, (drive_pci), &AP);
+                       /* clear PIO modes of lower 421 bits of B Register */
+                       pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+                       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
 
-               /* clear PIO modes of lower 421 bits of B Register */
-               pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
-               pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+                       pci_read_config_byte(dev, (drive_pci), &AP);
+                       pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+               }
+       }
 
-               pci_read_config_byte(dev, (drive_pci), &AP);
-               pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+       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);
+
+       switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+               case XFER_UDMA_4:       TB = 0x20; TC = 0x01; break;    /* speed 8 == UDMA mode 4 */
+               case XFER_UDMA_3:       TB = 0x40; TC = 0x02; break;    /* speed 7 == UDMA mode 3 */
+               case XFER_UDMA_2:       TB = 0x20; TC = 0x01; break;    /* speed 6 == UDMA mode 2 */
+               case XFER_UDMA_1:       TB = 0x40; TC = 0x02; break;    /* speed 5 == UDMA mode 1 */
+               case XFER_UDMA_0:       TB = 0x60; TC = 0x03; break;    /* speed 4 == UDMA mode 0 */
+               case XFER_MW_DMA_2:     TB = 0x60; TC = 0x03; break;    /* speed 4 == MDMA mode 2 */
+               case XFER_MW_DMA_1:     TB = 0x60; TC = 0x04; break;    /* speed 3 == MDMA mode 1 */
+               case XFER_MW_DMA_0:     TB = 0x60; TC = 0x05; break;    /* speed 2 == MDMA mode 0 */
+               case XFER_SW_DMA_2:     TB = 0x60; TC = 0x05; break;    /* speed 0 == SDMA mode 2 */
+               case XFER_SW_DMA_1:     TB = 0x80; TC = 0x06; break;    /* speed 1 == SDMA mode 1 */
+               case XFER_SW_DMA_0:     TB = 0xC0; TC = 0x0B; break;    /* speed 0 == SDMA mode 0 */
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               case XFER_PIO_4:        TA = 0x01; TB = 0x04; break;
+               case XFER_PIO_3:        TA = 0x02; TB = 0x06; break;
+               case XFER_PIO_2:        TA = 0x03; TB = 0x08; break;
+               case XFER_PIO_1:        TA = 0x05; TB = 0x0C; break;
+               case XFER_PIO_0:
+               default:                TA = 0x09; TB = 0x13; break;
        }
 
-       pio = (pio == 5) ? 4 : pio;
-       switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
-               case 4:speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
-               case 3:speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
-               case 2:speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
-               case 1:speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
-               case 0:
-               default:speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+        if (speed >= XFER_SW_DMA_0) {
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+               pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+       } else {
+#else
+       {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               pci_write_config_byte(dev, (drive_pci), AP|TA);
+               pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
        }
-       pci_write_config_byte(dev, (drive_pci), AP|TA);
-       pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
 
 #if PDC202XX_DECODE_REGISTER_INFO
        pci_read_config_byte(dev, (drive_pci), &AP);
@@ -333,13 +373,30 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
 #if PDC202XX_DEBUG_DRIVE_INFO
        printk("%s: %s drive%d 0x%08x ",
                drive->name, ide_xfer_verbose(speed),
-               drive_number, drive_conf);
+               drive->dn, drive_conf);
                pci_read_config_dword(dev, drive_pci, &drive_conf);
        printk("0x%08x\n", drive_conf);
 #endif /* PDC202XX_DEBUG_DRIVE_INFO */
        return err;
 }
 
+/*   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_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+       byte speed = 0x00;
+
+       pio = (pio == 5) ? 4 : pio;
+       speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+       return ((int) pdc202xx_tune_chipset(drive, speed));
+}
+
 static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
 {
        (void) config_chipset_for_pio(drive, pio);
@@ -352,15 +409,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        unsigned long high_16   = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
+       unsigned long dma_base  = hwif->dma_base;
+       byte unit               = (drive->select.b.unit & 0x01);
 
-       int                     err;
        unsigned int            drive_conf;
        byte                    drive_pci;
        byte                    test1, test2, speed = -1;
-       byte                    AP, BP, CP, DP, TB, TC;
+       byte                    AP;
        unsigned short          EP;
        byte CLKSPD             = IN_BYTE(high_16 + 0x11);
-       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
        byte udma_66            = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
        byte udma_33            = ultra ? (inb(high_16 + 0x001f) & 1) : 0;
 
@@ -397,9 +454,9 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
                         * check to make sure drive on same channel
                         * is u66 capable
                         */
-                       if (hwif->drives[!(drive_number%2)].id) {
-                               if ((hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0010) ||
-                                   (hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0008)) {
+                       if (hwif->drives[!(drive->dn%2)].id) {
+                               if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
+                                   (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
                                        OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
                                } else {
                                        OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
@@ -410,7 +467,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
                }
        }
 
-       switch(drive_number) {
+       switch(drive->dn) {
                case 0: drive_pci = 0x60;
                        pci_read_config_dword(dev, drive_pci, &drive_conf);
                        if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
@@ -451,101 +508,34 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 
 chipset_is_set:
 
-       if (drive->media != ide_disk)
-               return ide_dma_off_quietly;
+       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 */
+       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 (drive->media == ide_disk)   /* PREFETCH_EN */
+               pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-       if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-               /* speed 8 == UDMA mode 4 == speed 6 plus cable */
-               speed = XFER_UDMA_4; TB = 0x20; TC = 0x01;
-       } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-               /* speed 7 == UDMA mode 3 == speed 5 plus cable */
-               speed = XFER_UDMA_3; TB = 0x40; TC = 0x02;
-       } else if ((id->dma_ultra & 0x0004) && (udma_33)) {
-               /* speed 6 == UDMA mode 2 */
-               speed = XFER_UDMA_2; TB = 0x20; TC = 0x01;
-       } else if ((id->dma_ultra & 0x0002) && (udma_33)) {
-               /* speed 5 == UDMA mode 1 */
-               speed = XFER_UDMA_1; TB = 0x40; TC = 0x02;
-       } else if ((id->dma_ultra & 0x0001) && (udma_33)) {
-               /* speed 4 == UDMA mode 0 */
-               speed = XFER_UDMA_0; TB = 0x60; TC = 0x03;
-       } else if (id->dma_mword & 0x0004) {
-               /* speed 4 == DMA mode 2 multi-word */
-               speed = XFER_MW_DMA_2; TB = 0x60; TC = 0x03;
-       } else if (id->dma_mword & 0x0002) {
-               /* speed 3 == DMA mode 1 multi-word */
-               speed = XFER_MW_DMA_1; TB = 0x60; TC = 0x04;
-       } else if (id->dma_mword & 0x0001) {
-               /* speed 2 == DMA mode 0 multi-word */
-               speed = XFER_MW_DMA_0; TB = 0x60; TC = 0x05;
-       } else if (id->dma_1word & 0x0004) {
-               /* speed 2 == DMA mode 2 single-word */
-               speed = XFER_SW_DMA_2; TB = 0x60; TC = 0x05;
-       } else if (id->dma_1word & 0x0002) {
-               /* speed 1 == DMA mode 1 single-word */
-               speed = XFER_SW_DMA_1; TB = 0x80; TC = 0x06;
-       } else if (id->dma_1word & 0x0001) {
-               /* speed 0 == DMA mode 0 single-word */
-               speed = XFER_SW_DMA_0; TB = 0xC0; TC = 0x0B;
-       } else {
+       if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33))         speed = XFER_UDMA_4;
+       else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33))    speed = XFER_UDMA_3;
+       else if ((id->dma_ultra & 0x0004) && (udma_33))                 speed = XFER_UDMA_2;
+       else if ((id->dma_ultra & 0x0002) && (udma_33))                 speed = XFER_UDMA_1;
+       else if ((id->dma_ultra & 0x0001) && (udma_33))                 speed = XFER_UDMA_0;
+       else if (id->dma_mword & 0x0004)                                speed = XFER_MW_DMA_2;
+       else if (id->dma_mword & 0x0002)                                speed = XFER_MW_DMA_1;
+       else if (id->dma_mword & 0x0001)                                speed = XFER_MW_DMA_0;
+       else if (id->dma_1word & 0x0004)                                speed = XFER_SW_DMA_2;
+       else if (id->dma_1word & 0x0002)                                speed = XFER_SW_DMA_1;
+       else if (id->dma_1word & 0x0001)                                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;
        }
 
-       pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-       pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-
-#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 */
-
-       err = ide_config_drive_speed(drive, speed);
-
-#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 */
+       outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+       (void) pdc202xx_tune_chipset(drive, speed);
 
        return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
                        ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -716,6 +706,7 @@ unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
 void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
        hwif->tuneproc = &pdc202xx_tune_drive;
+       hwif->speedproc = &pdc202xx_tune_chipset;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_base) {
index fafd0533feef7516648f1a3788a42b8fe3b54e95..90af168c351ff2d13154bc5aec72ac70936172e7 100644 (file)
@@ -112,6 +112,7 @@ static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
                        p += sprintf(p, "\n                                Intel PIIX4 Ultra 66 Chipset.\n");
                        break;
                case PCI_DEVICE_ID_INTEL_82801AB_1:
+               case PCI_DEVICE_ID_INTEL_82443MX_1:
                case PCI_DEVICE_ID_INTEL_82371AB:
                        p += sprintf(p, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
                        break;
@@ -258,28 +259,18 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
 }
 
 #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-static int piix_config_drive_for_dma (ide_drive_t *drive)
+static int piix_tune_chipset (ide_drive_t *drive, byte speed)
 {
-       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, reg54;
-       byte                    speed;
-
        byte maslave            = hwif->channel ? 0x42 : 0x40;
-       byte udma_66            = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
-       int ultra66             = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
-                                  (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
-       int ultra               = ((ultra66) ||
-                                  (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
-                                  (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
-       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;
-       int v_flag              = 0x10 << drive_number;
+       int a_speed             = 2 << (drive->dn * 4);
+       int u_flag              = 1 << drive->dn;
+       int v_flag              = 0x10 << drive->dn;
        int u_speed             = 0;
+       int err                 = 0;
+       int                     sitre;
+       short                   reg4042, reg44, reg48, reg4a, reg54;
 
        pci_read_config_word(dev, maslave, &reg4042);
        sitre = (reg4042 & 0x4000) ? 1 : 0;
@@ -288,29 +279,16 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
        pci_read_config_word(dev, 0x4a, &reg4a);
        pci_read_config_word(dev, 0x54, &reg54);
 
-       if ((id->dma_ultra & 0x0010) && (ultra)) {
-               u_speed = 2 << (drive_number * 4);
-               speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-       } else if ((id->dma_ultra & 0x0008) && (ultra)) {
-               u_speed = 1 << (drive_number * 4);
-               speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-       } else if ((id->dma_ultra & 0x0004) && (ultra)) {
-               u_speed = 2 << (drive_number * 4);
-               speed = XFER_UDMA_2;
-       } else if ((id->dma_ultra & 0x0002) && (ultra)) {
-               u_speed = 1 << (drive_number * 4);
-               speed = XFER_UDMA_1;
-       } else if ((id->dma_ultra & 0x0001) && (ultra)) {
-               u_speed = 0 << (drive_number * 4);
-               speed = XFER_UDMA_0;
-       } else if (id->dma_mword & 0x0004) {
-               speed = XFER_MW_DMA_2;
-       } else if (id->dma_mword & 0x0002) {
-               speed = XFER_MW_DMA_1;
-       } else if (id->dma_1word & 0x0004) {
-               speed = XFER_SW_DMA_2;
-        } else {
-               speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+       switch(speed) {
+               case XFER_UDMA_4:
+               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
+               case XFER_UDMA_3:
+               case XFER_UDMA_1:       u_speed = 1 << (drive->dn * 4); break;
+               case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_SW_DMA_2:     break;
+               default:                return -1;
        }
 
        if (speed >= XFER_UDMA_0) {
@@ -328,7 +306,6 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
                        pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
                }
        }
-
        if (speed < XFER_UDMA_0) {
                if (reg48 & u_flag)
                        pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
@@ -340,11 +317,52 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
 
        piix_tune_drive(drive, piix_dma_2_pio(speed));
 
-       (void) ide_config_drive_speed(drive, speed);
-
 #if PIIX_DEBUG_DRIVE_INFO
-       printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number);
+       printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
 #endif /* PIIX_DEBUG_DRIVE_INFO */
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+       err = ide_config_drive_speed(drive, speed);
+       drive->current_speed = speed;
+       return err;
+}
+
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+       struct hd_driveid *id   = drive->id;
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       byte                    speed;
+
+       byte udma_66            = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+       int ultra66             = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
+                                  (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
+       int ultra               = ((ultra66) ||
+                                  (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
+                                  (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
+                                  (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
+
+       if ((id->dma_ultra & 0x0010) && (ultra)) {
+               speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
+       } else if ((id->dma_ultra & 0x0008) && (ultra)) {
+               speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
+       } else if ((id->dma_ultra & 0x0004) && (ultra)) {
+               speed = XFER_UDMA_2;
+       } else if ((id->dma_ultra & 0x0002) && (ultra)) {
+               speed = XFER_UDMA_1;
+       } else if ((id->dma_ultra & 0x0001) && (ultra)) {
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_1word & 0x0004) {
+               speed = XFER_SW_DMA_2;
+        } else {
+               speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+       }
+
+       (void) piix_tune_chipset(drive, speed);
 
        return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
                        ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -413,6 +431,7 @@ void __init ide_init_piix (ide_hwif_t *hwif)
 #ifdef CONFIG_PIIX_TUNING
        hwif->autodma = 1;
        hwif->dmaproc = &piix_dmaproc;
+       hwif->speedproc = &piix_tune_chipset;
 #endif /* CONFIG_PIIX_TUNING */
 #endif /* !CONFIG_BLK_DEV_IDEDMA */
 }
index ad56c295ceeb3492e4629d4381e5b7d5c2f99325..4c00de5042f13ebdabfd5f61e2babfb9de94604b 100644 (file)
@@ -1,12 +1,21 @@
 /*
- *  linux/drivers/ide/qd6580.c         Version 0.02    Feb 09, 1996
+ *  linux/drivers/ide/qd6580.c      Version 0.03    May 13, 2000
  *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ *  Copyright (C) 1996-2000  Linus Torvalds & author (see below)
  */
 
 /*
- * QDI QD6580 EIDE controller fast support by Colten Edwards.
- * No net access, but (maybe) can be reached at pje120@cs.usask.ca
+ *  Version 0.03       Cleaned auto-tune, added probe
+ * 
+ * QDI QD6580 EIDE controller fast support
+ * 
+ * To activate controller support use kernel parameter "ide0=qd6580"
+ * To enable tuning use kernel parameter "ide0=autotune"
+ */
+
+/* 
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
  */
 
 #undef REALLY_SLOW_IO           /* most systems can safely undef this */
 #include "ide_modes.h"
 
 /*
- * Register 0xb3 looks like:
- *     0x4f is fast            mode3 ?
- *     0x3f is medium          mode2 ?
- *     0x2f is slower          mode1 ?
- *     0x1f is slower yet      mode0 ?
- *     0x0f ???                ???
+ * I/O ports are 0xb0 0xb1 0xb2 and 0xb3
+ *            or 0x30 0x31 0x32 and 0x33
+ *     -- this is a dual IDE interface with I/O chips
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ */
+
+/* 
+ * 0xb0: Timer1
  *
- * Don't know whether this sets BOTH drives, or just the first drive.
- * Don't know if there is a separate setting for the second drive.
+ *  
+ * 0xb1: Status
  *
- * Feel free to patch this if you have one of these beasts
- * and can work out the answers!
+ * && 0xf0 is either 0b1010000 or 0b01010000, or else it isn't a qd6580
+ * bit 3 & 2: unknown (useless ?) I have 0 & 1, respectively
+ * bit 1: 1 if qd6580 baseport is 0xb0
+ *        0 if qd6580 baseport is 0x30
+ * bit 0: 1 if ide baseport is 0x1f0
+ *        0 if ide baseport is 0x170
+ *   (? Strange: the Dos driver uses it, and then forces baseport to 0x1f0 ?)
+ * 
+ *        
+ * 0xb2: Timer2
  *
- * I/O ports are 0xb0 0xb2 and 0xb3
+ * 
+ * 0xb3: Control
  *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- *     -- this is apparently a *dual* IDE interface
+ * bits 0-3 are always set 1
+ * bit 6 : if 1, must be set 1
+ * bit 1 : if 1, bit 7 must be set 1
+ * bit 0 : if 1, drives are independant, we can have two different timers for
+ *               the two drives.
+ *         if 0, we have to take the slowest drive into account,
+ *               but we may tune the second hwif ?
  */
 
-static void tune_qd6580 (ide_drive_t *drive, byte pio)
+typedef struct ide_hd_timings_s {
+       int active_time;                /* Active pulse (ns) minimum */
+       int recovery_time;              /* Recovery pulse (ns) minimum */
+} ide_hd_timings_t;
+
+static int basePort;           /* base port address (0x30 or 0xb0) */
+static byte status;                    /* status register of qd6580 */
+static byte control;           /* control register of qd6580 */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+static int bus_clock;          /* Vesa local bus clock (ns) */
+static int tuned=0;                    /* to remember whether we've already been tuned */
+
+/*
+ * tune_drive
+ *
+ * Finds timings for the specified drive, returns it in struc t
+ */
+
+static void tune_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t)
+{
+       ide_pio_data_t d;
+
+       t->active_time   = 0xaf;
+       t->recovery_time = 0x19f; /* worst cases values from the dos driver */
+
+       if (drive->present == 0) {      /* not present : free to give any timing */
+               t->active_time = 0x0;
+               t->recovery_time = 0x0;
+               return;
+       }
+       
+       pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+       if (pio) {
+       
+               switch (pio) {
+                       case 0: break;
+                       case 3: t->active_time = 0x56;
+                                               t->recovery_time = d.cycle_time-0x66;
+                                       break;
+                       case 4: t->active_time = 0x46;
+                                               t->recovery_time = d.cycle_time-0x3d;
+                                       break;
+                       default: if (d.cycle_time >= 0xb4) {
+                                               t->active_time = 0x6e;
+                                               t->recovery_time = d.cycle_time - 0x78;
+                                       } else {
+                                               t->active_time = ide_pio_timings[pio].active_time;
+                                               t->recovery_time = d.cycle_time 
+                                                               -t->active_time
+                                                               -ide_pio_timings[pio].setup_time;
+                                       }
+               }               
+       }       
+       printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time);
+}
+
+/* 
+ * tune_ide
+ *
+ * Tunes the whole ide, ie tunes each drives, and takes the worst timings
+ * to tune qd6580
+ */
+
+static void tune_ide ( ide_hwif_t *hwif, byte pio )
 {
        unsigned long flags;
+       ide_hd_timings_t t[2]={{0,0},{0,0}};
+       
+       byte active_cycle;
+       byte recovery_cycle;
+       byte parameter;
+       int bus_speed = ide_system_bus_speed ();
+       
+       bus_clock = 1000 / bus_speed;
+       
+       save_flags(flags);              /* all CPUs */
+       cli();                                  /* all CPUs */
+       outb( (bus_clock<30) ? 0x0 : 0x0a, basePort + 0x02);
+       outb( 0x40 | ((control & 0x02) ? 0x9f:0x1f), basePort+0x03);
+       restore_flags(flags);   
 
-       pio = ide_get_best_pio_mode(drive, pio, 3, NULL);
+       tune_drive (&hwif->drives[0], pio, &t[0]);
+       tune_drive (&hwif->drives[1], pio, &t[1]);
 
-       save_flags(flags);      /* all CPUs */
-       cli();                  /* all CPUs */
-       outb_p(0x8d,0xb0);
-       outb_p(0x0 ,0xb2);
-       outb_p(((pio+1)<<4)|0x0f,0xb3);
+       t[0].active_time   = IDE_MAX(t[0].active_time,  t[1].active_time);
+       t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time);
+       
+       active_cycle   = 17-IDE_IN(t[0].active_time   / bus_clock + 1, 2, 17);
+       recovery_cycle = 15-IDE_IN(t[0].recovery_time / bus_clock + 1, 2, 15);
+       
+       parameter=active_cycle | (recovery_cycle<<4);
+               
+       printk("%s: tim1=%dns tim2=%dns => %#x\n", hwif->name, t[0].active_time, t[0].recovery_time, parameter);
+       
+       save_flags(flags);              /* all CPUs */
+       cli();                                  /* all CPUs */
+       outb_p(parameter,0xb0);
        inb(0x3f6);
        restore_flags(flags);   /* all CPUs */
+       
+}
+
+/*
+ * tune_qd6580
+ *
+ * tunes the hwif if not tuned
+ */
+
+static void tune_qd6580 (ide_drive_t *drive, byte pio)
+{
+       if (! tuned) {
+               tune_ide(HWIF(drive), pio);
+               tuned = 1;
+       }
+}
+
+/*
+ * testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init testreg(int port)
+{
+       byte savereg;
+       byte readreg;
+       unsigned long flags;
+       
+       save_flags(flags);              /* all CPUs */
+       cli();                                  /* all CPUs */
+       savereg = inb(port);
+       outb_p(0x15,port);              /* safe value */
+       readreg = inb_p(port);
+       outb(savereg,port);
+       restore_flags(flags);   /* all CPUs */
+
+       if (savereg == 0x15) {
+               printk("Outch ! the probe for qd6580 isn't reliable !\n");
+               printk("Please contact samuel.thibault@fnac.net to tell about your hardware\n");
+               printk("Assuming qd6580 is present");
+       }
+
+       return (readreg == 0x15);
 }
 
+/* 
+ * trybase:
+ *
+ * tries to find a qd6580 at the given base and save it if found
+ */
+
+static int __init trybase (int base)
+{
+       unsigned long flags;
+
+       save_flags(flags);              /* all CPUs */
+       cli();                                  /* all CPUs */
+       status = inb(base+0x01);
+       control = inb(base+0x03);
+       restore_flags(flags);   /* all CPUs */
+
+       if (((status & 0xf0) != 0x50) && ((status & 0xf0) != 0xa0)) return(0);
+       if (! ( ((status & 0x02) == 0x0) == (base == 0x30) ) ) return (0);
+
+       /* Seems to be OK, let's use it */
+       
+       basePort = base;
+       return(testreg(base));
+}
+
+/* 
+ * probe:
+ *
+ * probes qd6580 at 0xb0 (the default) or 0x30
+ */
+
+static int __init probe (void)
+{
+       return (trybase(0xb0) ? 1 : trybase(0x30));
+}
+
+
 void __init init_qd6580 (void)
 {
+       if (! probe()) {
+               printk("qd6580: not found\n");
+               return;
+       }
+       
+       printk("qd6580: base=%#x, status=%#x, control=%#x\n", basePort, status, control);
+       
        ide_hwifs[0].chipset = ide_qd6580;
        ide_hwifs[1].chipset = ide_qd6580;
        ide_hwifs[0].tuneproc = &tune_qd6580;
index 581992c63d2c4466aab9c95888e101db80b15ea8..be56a7f2489ac4519a8f1ee696dd19f0afa655db 100644 (file)
@@ -227,9 +227,8 @@ static void config_drive_art_rwp (ide_drive_t *drive)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
 
-       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
        byte reg4bh             = 0;
-       byte rw_prefetch        = (0x11 << drive_number);
+       byte rw_prefetch        = (0x11 << drive->dn);
 
        pci_read_config_byte(dev, 0x4b, &reg4bh);
        if (drive->media != ide_disk)
@@ -248,12 +247,8 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
 
        unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
        unsigned short xfer_pio = drive->id->eide_pio_modes;
-       int drive_number        = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
 
-#if 0
        config_drive_art_rwp(drive);
-#endif
-
        pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
 
        if (xfer_pio> 4)
@@ -281,7 +276,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
  * Cycle time    20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
  */
 
-       switch(drive_number) {
+       switch(drive->dn) {
                case 0:         drive_pci = 0x40; break;
                case 1:         drive_pci = 0x42; break;
                case 2:         drive_pci = 0x44; break;
@@ -329,7 +324,7 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
        return err;
 }
 
-#undef SIS5513_TUNEPROC
+#define SIS5513_TUNEPROC
 
 #ifdef SIS5513_TUNEPROC
 static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
@@ -354,7 +349,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
        unsigned long dma_base  = hwif->dma_base;
        byte unit               = (drive->select.b.unit & 0x01);
        byte speed              = 0x00, unmask = 0xE0, four_two = 0x00;
-       int drive_number        = ((hwif->channel ? 2 : 0) + unit);
        byte udma_66            = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
 
        if (host_dev) {
@@ -370,7 +364,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
                }
        }
 
-       switch(drive_number) {
+       switch(drive->dn) {
                case 0:         drive_pci = 0x40;break;
                case 1:         drive_pci = 0x42;break;
                case 2:         drive_pci = 0x44;break;
@@ -438,7 +432,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
        err = ide_config_drive_speed(drive, speed);
 
 #if SIS5513_DEBUG_DRIVE_INFO
-       printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number);
+       printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
 #endif /* SIS5513_DEBUG_DRIVE_INFO */
 
        return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
index f9d96a86560e05ba223734531d6b3e0a7ba97218..39258362ca8dca70b99cc4e810ecced8a58ef86f 100644 (file)
@@ -115,6 +115,7 @@ static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL;
 
 struct chipset_bus_clock_list_entry via82cxxx_type_one [] = {
                /* speed */     /* 25 */        /* 33 */        /* 37.5 */      /* 41.5 */      
+#ifdef CONFIG_BLK_DEV_IDEDMA
        {       XFER_UDMA_4,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_3,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_2,    0x60,   0x20,   0x60,   0x20,   0x60,   0x21,   0x00,   0x00    },
@@ -124,7 +125,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_one [] = {
        {       XFER_MW_DMA_2,  0x03,   0x20,   0x03,   0x20,   0x03,   0x21,   0x00,   0x00    },
        {       XFER_MW_DMA_1,  0x03,   0x31,   0x03,   0x31,   0x03,   0x32,   0x00,   0x00    },
        {       XFER_MW_DMA_0,  0x03,   0x31,   0x03,   0x31,   0x03,   0x32,   0x00,   0x00    },
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        {       XFER_PIO_4,     0x03,   0x20,   0x03,   0x20,   0x03,   0x21,   0x00,   0x00    },
        {       XFER_PIO_3,     0x03,   0x31,   0x03,   0x31,   0x03,   0x32,   0x00,   0x00    },
        {       XFER_PIO_2,     0x03,   0x65,   0x03,   0x65,   0x03,   0x76,   0x00,   0x00    },
@@ -135,6 +136,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_one [] = {
 
 struct chipset_bus_clock_list_entry via82cxxx_type_two [] = {
                /* speed */     /* 25 */        /* 33 */        /* 37.5 */      /* 41.5 */
+#ifdef CONFIG_BLK_DEV_IDEDMA
        {       XFER_UDMA_4,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_3,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_2,    0xE0,   0x20,   0xE0,   0x20,   0xE1,   0x31,   0xE1,   0x32    },
@@ -144,7 +146,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_two [] = {
        {       XFER_MW_DMA_2,  0x03,   0x20,   0x03,   0x20,   0x03,   0x31,   0x03,   0x32    },
        {       XFER_MW_DMA_1,  0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
        {       XFER_MW_DMA_0,  0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        {       XFER_PIO_4,     0x03,   0x20,   0x03,   0x20,   0x03,   0x31,   0x03,   0x32    },
        {       XFER_PIO_3,     0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
        {       XFER_PIO_2,     0x03,   0x65,   0x03,   0x65,   0x03,   0x87,   0x03,   0xA8    },
@@ -155,6 +157,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_two [] = {
 
 struct chipset_bus_clock_list_entry via82cxxx_type_three [] = {
                /* speed */     /* 25 */        /* 33 */        /* 37.5 */      /* 41.5 */
+#ifdef CONFIG_BLK_DEV_IDEDMA
        {       XFER_UDMA_4,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_3,    0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00    },
        {       XFER_UDMA_2,    0xE0,   0x20,   0xE0,   0x20,   0xE1,   0x31,   0xE1,   0x32    },
@@ -164,7 +167,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_three [] = {
        {       XFER_MW_DMA_2,  0x03,   0x20,   0x03,   0x20,   0x03,   0x31,   0x03,   0x32    },
        {       XFER_MW_DMA_1,  0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
        {       XFER_MW_DMA_0,  0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        {       XFER_PIO_4,     0x03,   0x20,   0x03,   0x20,   0x03,   0x31,   0x03,   0x32    },
        {       XFER_PIO_3,     0x03,   0x31,   0x03,   0x31,   0x03,   0x42,   0x03,   0x53    },
        {       XFER_PIO_2,     0x03,   0x65,   0x03,   0x65,   0x03,   0x87,   0x03,   0xA8    },
@@ -175,6 +178,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_three [] = {
 
 struct chipset_bus_clock_list_entry via82cxxx_type_four [] = {
                /* speed */     /* 25 */        /* 33 */        /* 37.5 */      /* 41.5 */
+#ifdef CONFIG_BLK_DEV_IDEDMA
        {       XFER_UDMA_4,    0x00,   0x00,   0xE0,   0x20,   0xE1,   0x31,   0x00,   0x00    },
        {       XFER_UDMA_3,    0x00,   0x00,   0xE1,   0x20,   0xE2,   0x31,   0x00,   0x00    },
        {       XFER_UDMA_2,    0x00,   0x00,   0xE2,   0x20,   0xE4,   0x31,   0x00,   0x00    },
@@ -184,7 +188,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_four [] = {
        {       XFER_MW_DMA_2,  0x00,   0x00,   0x03,   0x20,   0x03,   0x31,   0x00,   0x00    },
        {       XFER_MW_DMA_1,  0x00,   0x00,   0x03,   0x31,   0x03,   0x42,   0x00,   0x00    },
        {       XFER_MW_DMA_0,  0x00,   0x00,   0x03,   0x31,   0x03,   0x42,   0x00,   0x00    },
-
+#endif /* CONFIG_BLK_DEV_IDEDMA */
        {       XFER_PIO_4,     0x00,   0x00,   0x03,   0x20,   0x03,   0x31,   0x00,   0x00    },
        {       XFER_PIO_3,     0x00,   0x00,   0x03,   0x31,   0x03,   0x42,   0x00,   0x00    },
        {       XFER_PIO_2,     0x00,   0x00,   0x03,   0x65,   0x03,   0x87,   0x00,   0x00    },
@@ -651,8 +655,7 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       byte unit               = (drive->select.b.unit & 0x01);
-       int drive_number        = ((hwif->channel ? 2 : 0) + unit);
+       struct chipset_bus_clock_list_entry * temp_table = NULL;
 
        byte ata2_pci           = 0x00;
        byte ata3_pci           = 0x00;
@@ -662,7 +665,10 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
 
        int bus_speed           = system_bus_clock();
 
-       switch(drive_number) {
+       if (via82cxxx_table == NULL)
+               return -1;
+
+       switch(drive->dn) {
                case 0: ata2_pci = 0x4b; ata3_pci = 0x53; break;
                case 1: ata2_pci = 0x4a; ata3_pci = 0x52; break;
                case 2: ata2_pci = 0x49; ata3_pci = 0x51; break;
@@ -671,16 +677,26 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
                        return -1;
        }
 
+       if ((via82cxxx_table == via82cxxx_type_four) && (speed <= XFER_UDMA_2)) {
+               temp_table = via82cxxx_type_three;
+       } else {
+               temp_table = via82cxxx_table;
+       }
+
        pci_read_config_byte(dev, ata2_pci, &timing);
-       timing = pci_bus_clock_list(speed, bus_speed, via82cxxx_table);
+       timing = pci_bus_clock_list(speed, bus_speed, temp_table);
        pci_write_config_byte(dev, ata2_pci, timing);
 
        pci_read_config_byte(dev, ata3_pci, &ultra);
-       ultra = pci_bus_clock_list_ultra(speed, bus_speed, via82cxxx_table);
+       ultra = pci_bus_clock_list_ultra(speed, bus_speed, temp_table);
        pci_write_config_byte(dev, ata3_pci, ultra);
 
+       if (!drive->init_speed)
+               drive->init_speed = speed;
+
        err = ide_config_drive_speed(drive, speed);
 
+       drive->current_speed = speed;
        return(err);
 }
 
@@ -845,6 +861,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
        struct pci_dev *isa;
        int i, j, ata33, ata66;
 
+       int bus_speed = system_bus_clock();
        byte revision = 0;
 
        for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) {
@@ -873,18 +890,26 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
                        ata33 = 1;
                        ata66 = 0;
 
+                       via82cxxx_table = ApolloISAChipInfo[j].chipset_table;
+
                        if (ApolloISAChipInfo[j].flags & VIA_FLAG_CHECK_REV) {
                                pci_read_config_byte(isa_dev, 0x0d, &revision);
                                ata33 = (revision >= 0x20) ? 1 : 0;
                        } else if (ApolloISAChipInfo[j].flags & VIA_FLAG_ATA_66) {
+                               byte ata66_0 = 0, ata66_1 = 0;
                                ata33 = 0;
                                ata66 = 1;
+                               pci_read_config_byte(dev, 0x50, &ata66_1);
+                               pci_read_config_byte(dev, 0x52, &ata66_0);
+                               if ((ata66_0 & 0x04) || (ata66_1 & 0x04)) {
+                                       via82cxxx_table = (bus_speed == 33 || bus_speed == 37) ?
+                                               via82cxxx_type_four :
+                                               via82cxxx_type_three;
+                               }
                        }
 
                        if (ata33 | ata66)
                                printk(" Chipset Core ATA-%s", ata66 ? "66" : "33");
-
-                       via82cxxx_table = ApolloISAChipInfo[j].chipset_table;
                }
                printk("\n");
        }
@@ -915,6 +940,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
 
 #ifdef CONFIG_VIA82CXXX_TUNING
        hwif->tuneproc = &via82cxxx_tune_drive;
+       hwif->speedproc = &via82cxxx_tune_chipset;
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
        hwif->autodma = 0;
index 466a83dbc41639db9d7dfead2760168f669c79fc..de0946642196eb48872f5b6c74a6dae734d49930 100644 (file)
@@ -95,10 +95,6 @@ extern int bionet_probe(struct net_device *);
 extern int pamsnet_probe(struct net_device *);
 extern int cs89x0_probe(struct net_device *dev);
 extern int ethertap_probe(struct net_device *dev);
-extern int ether1_probe (struct net_device *dev);
-extern int ether3_probe (struct net_device *dev);
-extern int etherh_probe (struct net_device *dev);
-extern int am79c961_probe(struct net_device *dev);
 extern int hplance_probe(struct net_device *dev);
 extern int bagetlance_probe(struct net_device *);
 extern int dec_lance_probe(struct net_device *);
@@ -401,22 +397,6 @@ struct devprobe mips_probes[] __initdata = {
        {NULL, 0},
 };
 
-struct devprobe arm_probes[] __initdata = {
-#ifdef CONFIG_ARM_ETHERH
-       {etherh_probe , 0},
-#endif
-#ifdef CONFIG_ARM_ETHER3
-       {ether3_probe , 0},
-#endif
-#ifdef CONFIG_ARM_ETHER1
-       {ether1_probe , 0},
-#endif
-#ifdef CONFIG_ARM_AM79C961A
-       {am79c961_probe, 0},
-#endif
-       {NULL, 0},
-};
-
 /*
  * Unified ethernet device probe, segmented per architecture and
  * per bus interface. This drives the legacy devices only for now.
@@ -437,8 +417,6 @@ static int __init ethif_probe(struct net_device *dev)
         * The arch specific probes are 1st so that any on-board ethernet
         * will be probed before other ISA/EISA/MCA/PCI bus cards.
         */
-       if (probe_list(dev, arm_probes) == 0)
-               return 0;
        if (probe_list(dev, m68k_probes) == 0)
                return 0;
        if (probe_list(dev, mips_probes) == 0)
index 7d53e1260f93fddc62240f78977d0939d14b7412..29d5d76387950659ac59e066bb5939a6eaf571b3 100644 (file)
@@ -2966,6 +2966,6 @@ static int __init read_eeprom_byte(struct net_device *dev,
 
 /*
  * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
  * End:
  */
index c7e7f2fe57318e5b39b38304ae6cef4b5c6295d1..83012de44910e67cea8da76c934240462b75c9ed 100644 (file)
@@ -3,7 +3,10 @@
  *
  * Derived from various things including skeleton.c
  *
- * R.M.King 1995.
+ * Russell King 1995-2000.
+ *
+ * This is a special driver for the am79c961A Lance chip used in the
+ * Intel (formally Digital Equipment Corp) EBSA110 platform.
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
+#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/ecard.h>
 
 #include "am79c961a.h"
 
-static int am79c961_probe1 (struct net_device *dev);
-static int am79c961_open (struct net_device *dev);
-static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
 static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
 static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
 static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
-static int am79c961_close (struct net_device *dev);
-static struct enet_statistics *am79c961_getstats (struct net_device *dev);
-static void am79c961_setmulticastlist (struct net_device *dev);
-static void am79c961_timeout(struct net_device *dev);
 
 static unsigned int net_debug = NET_DEBUG;
 
-static void
-am79c961_setmulticastlist (struct net_device *dev);
-
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n";
-
-#define FUNC_PROLOGUE \
-       struct dev_priv *priv = (struct dev_priv *)dev->priv
+static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.02\n";
 
 /* --------------------------------------------------------------------------- */
 
@@ -270,109 +262,6 @@ am79c961_init_for_open(struct net_device *dev)
        write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
 }
 
-static int
-am79c961_init(struct net_device *dev)
-{
-       unsigned long flags;
-
-       am79c961_ramtest(dev, 0x66);
-       am79c961_ramtest(dev, 0x99);
-
-       save_flags_cli (flags);
-
-       write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
-       write_rreg (dev->base_addr, CSR0, CSR0_STOP);
-       write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
-
-       restore_flags (flags);
-
-       return 0;
-}
-
-/*
- * This is the real probe routine.
- */
-static int
-am79c961_probe1(struct net_device *dev)
-{
-       static unsigned version_printed = 0;
-       struct dev_priv *priv;
-       int i;
-
-       if (!dev->priv) {
-               dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
-               if (!dev->priv)
-                       return -ENOMEM;
-       }
-
-       priv = (struct dev_priv *) dev->priv;
-       memset (priv, 0, sizeof(struct dev_priv));
-
-       /*
-        * The PNP initialisation should have been done by the ether bootp loader.
-        */
-       inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */
-
-       udelay (5);
-
-       if (inb (dev->base_addr >> 1) != 0x08 ||
-           inb ((dev->base_addr >> 1) + 1) != 00 ||
-           inb ((dev->base_addr >> 1) + 2) != 0x2b) {
-               kfree (dev->priv);
-               dev->priv = NULL;
-               return -ENODEV;
-       }
-
-       /*
-        * Ok, we've found a valid hw ID
-        */
-
-       if (net_debug  &&  version_printed++ == 0)
-               printk (KERN_INFO "%s", version);
-
-       printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq);
-       request_region (dev->base_addr, 0x18, "am79c961");
-
-       /* Retrive and print the ethernet address. */
-       for (i = 0; i < 6; i++) {
-               dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
-               printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
-       }
-
-       if (am79c961_init(dev)) {
-               kfree (dev->priv);
-               dev->priv = NULL;
-               return -ENODEV;
-       }
-
-       dev->open = am79c961_open;
-       dev->stop = am79c961_close;
-       dev->hard_start_xmit = am79c961_sendpacket;
-       dev->get_stats = am79c961_getstats;
-       dev->set_multicast_list = am79c961_setmulticastlist;
-       dev->tx_timeout = am79c961_timeout;
-
-       /* Fill in the fields of the device structure with ethernet values. */
-       ether_setup(dev);
-
-       return 0;
-}
-
-int
-am79c961_probe(struct net_device *dev)
-{
-       static int initialised = 0;
-
-       if (initialised)
-               return -ENODEV;
-       initialised = 1;
-
-       dev->base_addr = 0x220;
-       dev->irq = 3;
-
-       return am79c961_probe1(dev);
-}
-
 /*
  * Open/initialize the board.  This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -408,9 +297,17 @@ am79c961_open(struct net_device *dev)
 static int
 am79c961_close(struct net_device *dev)
 {
+       unsigned long flags;
+
        netif_stop_queue(dev);
 
-       am79c961_init(dev);
+       save_flags_cli (flags);
+
+       write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
+       write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+       write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+
+       restore_flags (flags);
 
        free_irq (dev->irq, dev);
 
@@ -709,3 +606,103 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
 
        netif_wake_queue(dev);
 }
+
+static int
+am79c961_hw_init(struct net_device *dev)
+{
+       unsigned long flags;
+
+       am79c961_ramtest(dev, 0x66);
+       am79c961_ramtest(dev, 0x99);
+
+       save_flags_cli (flags);
+
+       write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
+       write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+       write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+
+       restore_flags (flags);
+
+       return 0;
+}
+
+static void __init am79c961_banner(void)
+{
+       static unsigned version_printed = 0;
+
+       if (net_debug && version_printed++ == 0)
+               printk(KERN_INFO "%s", version);
+}
+
+static int __init am79c961_init(void)
+{
+       struct net_device *dev;
+       struct dev_priv *priv;
+       int i, ret;
+
+       dev = init_etherdev(NULL, sizeof(struct dev_priv));
+       ret = -ENOMEM;
+       if (!dev)
+               goto out;
+
+       priv = (struct dev_priv *) dev->priv;
+
+       /*
+        * Fixed address and IRQ lines here.
+        * The PNP initialisation should have been
+        * done by the ether bootp loader.
+        */
+       dev->base_addr = 0x220;
+       dev->irq = IRQ_EBSA110_ETHERNET;
+
+       /*
+        * Reset the device.
+        */
+       inb((dev->base_addr + NET_RESET) >> 1);
+       udelay(5);
+
+       /*
+        * Check the manufacturer part of the
+        * ether address.
+        */
+       ret = -ENODEV;
+       if (inb(dev->base_addr >> 1) != 0x08 ||
+           inb((dev->base_addr >> 1) + 1) != 00 ||
+           inb((dev->base_addr >> 1) + 2) != 0x2b)
+               goto nodev;
+
+       if (!request_region(dev->base_addr, 0x18, dev->name))
+               goto nodev;
+
+       am79c961_banner();
+       printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ",
+               dev->name, dev->base_addr, dev->irq);
+
+       /* Retrive and print the ethernet address. */
+       for (i = 0; i < 6; i++) {
+               dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff;
+               printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+       }
+
+       if (am79c961_hw_init(dev))
+               goto release;
+
+       dev->open               = am79c961_open;
+       dev->stop               = am79c961_close;
+       dev->hard_start_xmit    = am79c961_sendpacket;
+       dev->get_stats          = am79c961_getstats;
+       dev->set_multicast_list = am79c961_setmulticastlist;
+       dev->tx_timeout         = am79c961_timeout;
+
+       return 0;
+
+release:
+       release_region(dev->base_addr, 0x18);
+nodev:
+       unregister_netdev(dev);
+       kfree(dev);
+out:
+       return ret;
+}
+
+module_init(am79c961_init);
index 7e01e3f83b651cd114723b537ca441b3b3870420..65e85e808db6ed556385d6707de8c254b6b55208 100644 (file)
@@ -34,7 +34,7 @@ extern int abyss_probe(void);
 extern int madgemc_probe(void);
 extern int tms_pci_probe(void);
 
-/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */
+/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
 #define __PAD6 "\0\0\0\0\0\0\0\0\0"
 #define __PAD5 __PAD6 "\0"
 #define __PAD4 __PAD5 "\0"
index 8efaf47f8bd2b1b852d8d3e42e14b16785b4805e..c92e73180dc972f3b99655a2d0171061a86d7123 100644 (file)
@@ -75,7 +75,7 @@ static char * card_names[] = {
        "SiS 900 PCI Fast Ethernet",
        "SiS 7016 PCI Fast Ethernet"
 };
-static struct pci_device_id sis900_pci_tbl [] __devinitdata = {
+static struct pci_device_id sis900_pci_tbl [] __initdata = {
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
index 1e09974c9d4be7baf4dde39bcb561571375fb7a5..0d1fd72e6d4362c96d22f6a95b5a1143fee56dd3 100644 (file)
@@ -1,3 +1,39 @@
+2000-05-15  Gunther Mayer  <gunther.mayer@braunschweig.okersurf.de>
+
+       * parport_pc.c (parport_pc_compat_write_block_pio): Check for
+       timeouts.
+       (parport_pc_ecp_write_block_pio): Likewise.
+       (parport_pc_ecp_read_block_pio): Likewise.
+
+2000-05-02  Gunther Mayer  <gunther.mayer@braunschweig.okersurf.de>
+
+       * parport_pc.c: PCI SYBA patch and verbose PCI detection.
+
+2000-05-02  Gunther Mayer  <gunther.mayer@braunschweig.okersurf.de>
+
+       * parport_pc.c (decode_smsc): Fix SMSC 665/666 identification.
+
+2000-04-28  Tim Waugh  <twaugh@redhat.com>
+
+       * ieee1284.c: Short function descriptions can't be multiline.
+
+       * daisy.c: Short function descriptions can't be multiline.
+
+2000-04-19  Tim Waugh  <twaugh@redhat.com>
+
+       * parport_pc.c (parport_pc_fifo_write_block_dma): Make maxlen
+       calculation a bit clearer.
+
+       * ieee1284.c (parport_negotiate): Turn on data line drivers.
+
+       * ieee1284_ops.c (parport_ieee1284_read_byte): Turn off data line
+       drivers.
+       (parport_ieee1284_write_compat): Turn on data line drivers.
+
+       * daisy.c (assign_addrs): Turn on data line drivers.
+       (cpp_mux): Likewise.
+       (cpp_daisy): Likewise.
+
 2000-04-04  Tim Waugh  <twaugh@redhat.com>
 
        * parport_pc.c: Add support for another PCI card.
index ead3443b4f9558f316f85cd46b3a4004e7c2a850..b99d5a344ed0169be6d594c3f3727023cd531198 100644 (file)
@@ -252,8 +252,7 @@ void parport_close (struct pardevice *dev)
 }
 
 /**
- *     parport_device_num - convert device coordinates into a
- *                          canonical device number
+ *     parport_device_num - convert device coordinates
  *     @parport: parallel port number
  *     @mux: multiplexor port number (-1 for no multiplexor)
  *     @daisy: daisy chain address (-1 for no daisy chain address)
@@ -279,8 +278,7 @@ int parport_device_num (int parport, int mux, int daisy)
 }
 
 /**
- *     parport_device_coords - convert a canonical device number into
- *                             device coordinates
+ *     parport_device_coords - convert canonical device number
  *     @devnum: device number
  *     @parport: pointer to storage for parallel port number
  *     @mux: pointer to storage for multiplexor port number
@@ -325,6 +323,7 @@ static int cpp_daisy (struct parport *port, int cmd)
 {
        unsigned char s;
 
+       parport_data_forward (port);
        parport_write_data (port, 0xaa); udelay (2);
        parport_write_data (port, 0x55); udelay (2);
        parport_write_data (port, 0x00); udelay (2);
@@ -373,6 +372,7 @@ static int cpp_mux (struct parport *port, int cmd)
        unsigned char s;
        int rc;
 
+       parport_data_forward (port);
        parport_write_data (port, 0xaa); udelay (2);
        parport_write_data (port, 0x55); udelay (2);
        parport_write_data (port, 0xf0); udelay (2);
@@ -430,6 +430,7 @@ static int assign_addrs (struct parport *port)
        int thisdev = numdevs;
        char *deviceid;
 
+       parport_data_forward (port);
        parport_write_data (port, 0xaa); udelay (2);
        parport_write_data (port, 0x55); udelay (2);
        parport_write_data (port, 0x00); udelay (2);
@@ -502,8 +503,7 @@ static int assign_addrs (struct parport *port)
    'from' itself is skipped. */
 
 /**
- *     parport_find_device - find a device with a specified
- *                           manufacturer and model string
+ *     parport_find_device - find a specific device
  *     @mfg: required manufacturer string
  *     @mdl: required model string
  *     @from: previous device number found in search, or %NULL for
index f25c50abdeaf0e1cfb73f596f515d84bc28649c2..11f98bea035cf014fe8f972aedfa1416cc2e3b73 100644 (file)
@@ -380,6 +380,7 @@ int parport_negotiate (struct parport *port, int mode)
        udelay(1);
 
        /* Event 0: Set data */
+       parport_data_forward (port);
        parport_write_data (port, m);
        udelay (400); /* Shouldn't need to wait this long. */
 
@@ -734,7 +735,6 @@ ssize_t parport_read (struct parport *port, void *buffer, size_t len)
 
 /**
  *     parport_set_timeout - set the inactivity timeout for a device
- *                           on a port
  *     @dev: device on a port
  *     @inactivity: inactivity timeout (in jiffies)
  *
index a3b76ffbc18a3c812677f6031ac268588b332c95..cf5c5fb03c03fd508791e036b80c2d826b5e8225 100644 (file)
@@ -57,6 +57,7 @@ size_t parport_ieee1284_write_compat (struct parport *port,
 
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
        parport_write_control (port, ctl);
+       parport_data_forward (port);
        while (count < len) {
                long expire = jiffies + dev->timeout;
                long wait = (HZ + 99) / 100;
@@ -268,6 +269,9 @@ size_t parport_ieee1284_read_byte (struct parport *port,
                        break;
                }
 
+               /* Event 14: Place data bus in high impedance state. */
+               parport_data_reverse (port);
+
                /* Event 7: Set nAutoFd low. */
                parport_frob_control (port,
                                      PARPORT_CONTROL_AUTOFD,
index 5c78c1565684c7fffa17b6b043bdafc7aba28437..a759b2d7462e37b61f20d1c8f38b1b488e4ea4d0 100644 (file)
@@ -704,6 +704,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
                                          int flags)
 {
        size_t written;
+       int r;
 
        /* Special case: a timeout of zero means we cannot call schedule(). */
        if (!port->physport->cad->timeout)
@@ -745,9 +746,14 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
                frob_econtrol (port, 0xe0, ECR_PS2 << 5);
        }
 
-       parport_wait_peripheral (port,
-                                PARPORT_STATUS_BUSY,
-                                PARPORT_STATUS_BUSY);
+       r = parport_wait_peripheral (port,
+                                    PARPORT_STATUS_BUSY,
+                                    PARPORT_STATUS_BUSY);
+       if (r)
+               printk (KERN_DEBUG
+                       "%s: BUSY timeout (%d) in compat_write_block_pio\n", 
+                       port->name, r);
+
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
 
        return written;
@@ -760,6 +766,7 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
                                       int flags)
 {
        size_t written;
+       int r;
 
        /* Special case: a timeout of zero means we cannot call schedule(). */
        if (!port->physport->cad->timeout)
@@ -772,9 +779,12 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
                parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 
                /* Event 40: PError goes high. */
-               parport_wait_peripheral (port,
-                                        PARPORT_STATUS_PAPEROUT,
-                                        PARPORT_STATUS_PAPEROUT);
+               r = parport_wait_peripheral (port,
+                                            PARPORT_STATUS_PAPEROUT,
+                                            PARPORT_STATUS_PAPEROUT);
+               if (r)
+                       printk (KERN_DEBUG "%s: PError timeout (%d) "
+                               "in ecp_write_block_pio\n", port->name, r);
        }
 
        /* Set up ECP parallel port mode.*/
@@ -818,18 +828,30 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
                parport_pc_data_reverse (port); /* Must be in PS2 mode */
                udelay (5);
                parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-               parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+               r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+               if (r)
+                       printk (KERN_DEBUG "%s: PE,1 timeout (%d) "
+                               "in ecp_write_block_pio\n", port->name, r);
+
                parport_frob_control (port,
                                      PARPORT_CONTROL_INIT,
                                      PARPORT_CONTROL_INIT);
-               parport_wait_peripheral (port,
-                                        PARPORT_STATUS_PAPEROUT,
-                                        PARPORT_STATUS_PAPEROUT);
+               r = parport_wait_peripheral (port,
+                                            PARPORT_STATUS_PAPEROUT,
+                                            PARPORT_STATUS_PAPEROUT);
+                if (r)
+                        printk (KERN_DEBUG "%s: PE,2 timeout (%d) "
+                               "in ecp_write_block_pio\n", port->name, r);
        }
 
-       parport_wait_peripheral (port,
-                                PARPORT_STATUS_BUSY, 
-                                PARPORT_STATUS_BUSY);
+       r = parport_wait_peripheral (port,
+                                    PARPORT_STATUS_BUSY, 
+                                    PARPORT_STATUS_BUSY);
+       if(r)
+               printk (KERN_DEBUG
+                       "%s: BUSY timeout (%d) in ecp_write_block_pio\n",
+                       port->name, r);
+
        port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
 
        return written;
@@ -840,6 +862,7 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
 {
        size_t left = length;
        size_t fifofull;
+       int r;
        const int fifo = FIFO(port);
        const struct parport_pc_private *priv = port->physport->private_data;
        const int fifo_depth = priv->fifo_depth;
@@ -882,7 +905,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
                                      0);
 
                /* Event 40: PError goes low */
-               parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+               r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+                if (r)
+                        printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) "
+                               "in ecp_read_block_pio\n", port->name, r);
        }
 
        /* Set up ECP FIFO mode.*/
@@ -961,9 +987,14 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
 
        /* Go to forward idle mode to shut the peripheral up. */
        parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-       parport_wait_peripheral (port,
-                                PARPORT_STATUS_PAPEROUT,
-                                PARPORT_STATUS_PAPEROUT);
+       r = parport_wait_peripheral (port,
+                                    PARPORT_STATUS_PAPEROUT,
+                                    PARPORT_STATUS_PAPEROUT);
+       if (r)
+               printk (KERN_DEBUG
+                       "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
+                       port->name, r);
+
        port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
 
        /* Finish up. */
@@ -1218,7 +1249,7 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
 
         if (devid == devrev)
                /* simple heuristics, we happened to read some
-                   non-winbond register */
+                   non-smsc register */
                return;
 
        func=NULL;
@@ -1228,8 +1259,8 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
 
        if      (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
        else if (id==0x6582) type="37c665IR";
-       else if ((id==0x6502) && (key==0x44)) type="37c665GT";
-       else if ((id==0x6502) && (key==0x55)) type="37c666GT";
+       else if (devid==0x65) type="37c665GT";
+       else if (devid==0x66) type="37c666GT";
 
        if(type==NULL)
                 printk("SMSC unknown chip type\n");
@@ -2263,6 +2294,7 @@ enum parport_pc_pci_cards {
        plx_9050,
        afavlab_tk9902,
        timedia_1889,
+       syba_2p_epp,
 };
 
 
@@ -2270,9 +2302,11 @@ enum parport_pc_pci_cards {
  * (but offset by last_sio) */
 static struct parport_pc_pci {
        int numports;
-       struct {
+       struct { /* BAR (base address registers) numbers in the config
+                    space header */
                int lo;
-               int hi; /* -ve if not there */
+               int hi; /* -1 if not there, >6 for offset-method (max
+                           BAR is 6) */
        } addr[4];
 } cards[] __devinitdata = {
        /* siig_1s1p_10x_550 */         { 1, { { 3, 4 }, } },
@@ -2301,6 +2335,9 @@ static struct parport_pc_pci {
        /* plx_9050 */                  { 2, { { 4, -1 }, { 5, -1 }, } },
        /* afavlab_tk9902 */            { 1, { { 0, 1 }, } },
        /* timedia_1889 */              { 1, { { 2, -1 }, } },
+                                       /* SYBA uses fixed offsets in
+                                           a 1K io window */
+       /* syba_2p_epp */               { 2, { { 0, 0x078 }, { 0, 0x178 }, } },
 };
 
 static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
@@ -2360,6 +2397,7 @@ static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 },
        { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, timedia_1889 },
+       { 0x1592, 0x0782, PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp },
        { 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
@@ -2384,9 +2422,16 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
                unsigned long io_lo, io_hi;
                io_lo = pci_resource_start (dev, lo);
                io_hi = 0;
-               if (hi >= 0)
+               if ((hi >= 0) && (hi <= 6))
                        io_hi = pci_resource_start (dev, hi);
+               else if (hi > 6)
+                       io_lo += hi; /* Reinterpret the meaning of
+                                        "hi" as an offset (see SYBA
+                                        def.) */
                /* TODO: test if sharing interrupts works */
+               printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
+                       "I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i].vendor,
+                       parport_pc_pci_tbl[i].device, io_lo, io_hi);
                if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
                                           PARPORT_DMA_NONE, dev))
                        count++;
index 4e42146614bd6a0de319cb3fbfc4f3f2256eaae2..76bfcc3c058098387edc62ee60c60673ab2281d3 100644 (file)
@@ -189,7 +189,7 @@ static char * card_names[] = {
        "Intel 440MX"
 };
 
-static struct pci_device_id i810_pci_tbl [] __devinitdata = {
+static struct pci_device_id i810_pci_tbl [] __initdata = {
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82901,
index aa680aefc98e8f2de5da146316fd4cfcf61d0ca1..a1f462f3b34da4092ef72d387f8689a61df6f3dd 100644 (file)
@@ -147,7 +147,7 @@ static char * card_names[] = {
        "ALi Audio Accelerator"
 };
 
-static struct pci_device_id trident_pci_tbl [] __devinitdata = {
+static struct pci_device_id trident_pci_tbl [] __initdata = {
        {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX},
        {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX,
index 03aa75bf0878a13611742e6a60888c1c7b6e8b55..e4403d9664ab733de7a6b978ae68b7d3a11985a9 100644 (file)
@@ -303,7 +303,7 @@ static void via_chan_pcm_fmt (struct via_info *card,
  */
 
 
-static struct pci_device_id via_pci_tbl[] __devinitdata = {
+static struct pci_device_id via_pci_tbl[] __initdata = {
        { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0, }
 };
index 354c1d6cf924badf3e5b666feab41c6aa943e286..40903a9c299a7523d9660cd582f275a08a6ea50d 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *     audio.c  --  USB Audio Class driver
  *
- *     Copyright (C) 1999
+ *     Copyright (C) 1999, 2000
  *         Alan Cox (alan@lxorguk.ukuu.org.uk)
  *         Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  * 1999-12-20:  Fix bad bug in conversion to per interface probing.
  *             disconnect was called multiple times for the audio device,
  *             leading to a premature freeing of the audio structures
+ * 2000-05-13:  I don't remember who changed the find_format routine,
+ *              but the change was completely broken for the Dallas
+ *              chip. Anyway taking sampling rate into account in find_format
+ *              is bad and should not be done unless there are devices with
+ *              completely broken audio descriptors. Unless someone shows
+ *              me such a descriptor, I will not allow find_format to
+ *              take the sampling rate into account.
+ *              Also, the former find_format made:
+ *              - mpg123 play mono instead of stereo
+ *              - sox completely fail for wav's with sample rates < 44.1kHz
+ *                  for the Dallas chip.
+ *              Also fix a rather long standing problem with applications that
+ *              use "small" writes producing no sound at all.
+ * 2000-05-15:  My fears came true, the Philips camera indeed has pretty stupid
+ *              audio descriptors.
  *
  */
 
@@ -441,9 +456,9 @@ static int dmabuf_init(struct dmabuf *db)
        db->bufsize = nr << PAGE_SHIFT;
        db->ready = 1;
        printk(KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
-              "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d\n",
+              "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x\n",
               bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
-              db->numfrag, db->dmasize, db->bufsize);
+              db->numfrag, db->dmasize, db->bufsize, db->format);
        return 0;
 }
 
@@ -973,6 +988,8 @@ static int usbin_start(struct usb_audiodev *as)
                }
                spin_lock_irqsave(&as->lock, flags);
        }
+       if (u->dma.count <= 0 && !u->dma.mapped)
+               return 0;
        u->flags |= FLG_RUNNING;
        if (!(u->flags & FLG_URB0RUNNING)) {
                urb = &u->durb[0].urb;
@@ -1332,6 +1349,8 @@ static int usbout_start(struct usb_audiodev *as)
                }
                spin_lock_irqsave(&as->lock, flags);
        }
+       if (u->dma.count <= 0 && !u->dma.mapped)
+               return 0;
                u->flags |= FLG_RUNNING;
        if (!(u->flags & FLG_URB0RUNNING)) {
                urb = &u->durb[0].urb;
@@ -1395,30 +1414,39 @@ static int usbout_start(struct usb_audiodev *as)
 
 /* --------------------------------------------------------------------- */
 
-static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate)
+static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
 {
-       unsigned int i;
+       unsigned int g = 0;
+
+       if (srate < afp->sratelo)
+               g += afp->sratelo - srate;
+       if (srate > afp->sratehi)
+               g += srate - afp->sratehi;
+       if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
+               g += 0x100000;
+       if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
+               g += 0x400000;
+       if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
+               g += 0x100000;
+       if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
+               g += 0x400000;
+       return g;
+}
+
+static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
+{
+       unsigned int i, g, gb = ~0;
+       int j = -1; /* default to failure */
 
-       /* first find an exact match, taking both format and sample rate into account,
-          but ignore stereo bit */
+       /* find "best" format (according to format_goodness) */
        for (i = 0; i < nr; i++) {
-               if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi)
-                       return i;
+               g = format_goodness(&afp[i], fmt, srate);
+               if (g >= gb) 
+                       continue;
+               j = i;
+               gb = g;
        }
-               
-       /* second find a match with the same stereo/mono and 8bit/16bit property */
-       for (i = 0; i < nr; i++)
-               if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
-                   !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) && 
-                   rate >= afp[i].sratelo && rate <= afp[i].sratehi)
-                       return i;
-       /* third find a match with the same number of channels */
-       for (i = 0; i < nr; i++)
-               if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) && 
-                   rate >= afp[i].sratelo && rate <= afp[i].sratehi)
-                       return i;
-       /* return failure */
-       return -1;
+               return j;
 }
 
 static int set_format_in(struct usb_audiodev *as)
@@ -1430,9 +1458,9 @@ static int set_format_in(struct usb_audiodev *as)
        struct usbin *u = &as->usbin;
        struct dmabuf *d = &u->dma;
        struct audioformat *fmt;
-       unsigned int fmtnr, ep;
+       unsigned int ep;
        unsigned char data[3];
-       int ret;
+       int fmtnr, ret;
 
        if (u->interface < 0 || u->interface >= config->bNumInterfaces)
                return 0;
@@ -1465,7 +1493,9 @@ static int set_format_in(struct usb_audiodev *as)
                d->srate = fmt->sratelo;
        if (d->srate > fmt->sratehi)
                d->srate = fmt->sratehi;
-printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#if 1
+       printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#endif
        if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) {
                printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
                       dev->devnum, u->interface, fmt->altsetting);
@@ -1517,9 +1547,9 @@ static int set_format_out(struct usb_audiodev *as)
        struct usbout *u = &as->usbout;
        struct dmabuf *d = &u->dma;
        struct audioformat *fmt;
-       unsigned int fmtnr, ep;
+       unsigned int ep;
        unsigned char data[3];
-       int ret;
+       int fmtnr, ret;
 
        if (u->interface < 0 || u->interface >= config->bNumInterfaces)
                return 0;
@@ -1559,7 +1589,9 @@ static int set_format_out(struct usb_audiodev *as)
                d->srate = fmt->sratelo;
        if (d->srate > fmt->sratehi)
                d->srate = fmt->sratehi;
-printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#if 1
+       printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting);
+#endif
        if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
                printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
                       dev->devnum, u->interface, fmt->altsetting);
@@ -1927,6 +1959,7 @@ static int drain_out(struct usb_audiodev *as, int nonblock)
        
        if (as->usbout.dma.mapped || !as->usbout.dma.ready)
                return 0;
+       usbout_start(as);
        add_wait_queue(&as->usbout.dma.wait, &wait);
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
@@ -2033,6 +2066,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
        ssize_t ret = 0;
        unsigned long flags;
        unsigned int ptr;
+       unsigned int start_thr;
        int cnt, err;
 
        if (ppos != &file->f_pos)
@@ -2043,10 +2077,11 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
                return ret;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
        add_wait_queue(&as->usbout.dma.wait, &wait);
        while (count > 0) {
 #if 0
-               printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n",
+               printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
                       count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
                       as->usbout.flags, current->state);
 #endif
@@ -2097,7 +2132,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou
                count -= cnt;
                buffer += cnt;
                ret += cnt;
-               if (usbout_start(as)) {
+               if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
                        if (!ret)
                                ret = -ENODEV;
                        break;
@@ -2525,17 +2560,6 @@ static /*const*/ struct file_operations usb_audio_fops = {
 
 /* --------------------------------------------------------------------- */
 
-/*
- *     TO DO in order to get to the point of building an OSS interface
- *     structure, let alone playing music..
- *
- *     Use kmalloc/kfree for the descriptors we build
- *     Write the descriptor->OSS convertor code
- *     Figure how we deal with mixers
- *     Check alternate configurations. For now assume we will find one
- *     zero bandwidth (idle) config and one or more live one pers interface.
- */
-
 static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum);
 static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
 
@@ -2543,25 +2567,11 @@ static struct usb_driver usb_audio_driver = {
        "audio",
        usb_audio_probe,
        usb_audio_disconnect,
-       /*{ NULL, NULL }, */ LIST_HEAD_INIT(usb_audio_driver.driver_list), 
+       LIST_HEAD_INIT(usb_audio_driver.driver_list), 
        NULL,
        0
 };
 
-
-#if 0
-static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
-{
-#if 0
-       struct usb_audio_device *aud = (struct usb_audio_device *)dev_id;
-
-       printk(KERN_DEBUG "irq on %p\n", aud);
-#endif
-
-       return 1;
-}
-#endif
-
 static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
                             u8 dtype, int iface, int altsetting)
 {
@@ -3559,11 +3569,6 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
                        unregister_sound_mixer(ms->dev_mixer);
                ms->dev_mixer = -1;
        }
-#if 0
-       if(aud->irq_handle)
-               usb_release_irq(dev, aud->irq_handle, aud->irqpipe);
-       aud->irq_handle = NULL;
-#endif
        release(s);
        wake_up(&open_wait);
 }
index 73f39db7ca2210d826fe5e165587825d859eb4c1..35f268fac5b1d3d3b6b19a24bc9ae81856dcb1ae 100644 (file)
@@ -244,6 +244,7 @@ void input_unregister_device(struct input_dev *dev)
 {
        struct input_handle *handle = dev->handle;
        struct input_dev **devptr = &input_dev;
+       struct input_handle *dnext;
 
 /*
  * Kill any pending repeat timers.
@@ -256,9 +257,10 @@ void input_unregister_device(struct input_dev *dev)
  */
 
        while (handle) {
+               dnext = handle->dnext;
                input_unlink_handle(handle);
                handle->handler->disconnect(handle);
-               handle = handle->dnext;
+               handle = dnext;
        }
 
 /*
@@ -309,15 +311,17 @@ void input_unregister_handler(struct input_handler *handler)
 {
        struct input_handler **handlerptr = &input_handler;
        struct input_handle *handle = handler->handle;
+       struct input_handle *hnext;
 
 /*
  * Tell the handler to disconnect from all devices it keeps open.
  */
 
        while (handle) {
+               hnext = handle->hnext;
                input_unlink_handle(handle);
                handler->disconnect(handle);
-               handle = handle->hnext;
+               handle = hnext;
        }
 
 /*
index d64258e8ed0b2dbca6a9853fe679f22005a96d6a..c013a815402939f60eb37d8d1fe0e9825de2701a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * printer.c  Version 0.3
+ * printer.c  Version 0.4
  *
  * Copyright (c) 1999 Michael Gee      <michael@linuxspecific.com>
  * Copyright (c) 1999 Pavel Machek      <pavel@suse.cz>
@@ -13,6 +13,7 @@
  *     v0.1 - thorough cleaning, URBification, almost a rewrite
  *     v0.2 - some more cleanups
  *     v0.3 - cleaner again, waitqueue fixes
+ *     v0.4 - fixes in unidirectional mode
  */
 
 /*
@@ -102,7 +103,7 @@ static void usblp_bulk(struct urb *urb)
                return;
 
        if (urb->status)
-               warn("nonzero read bulk status received: %d", urb->status);
+               warn("nonzero read/write bulk status received: %d", urb->status);
 
        wake_up_interruptible(&usblp->wait);
 }
@@ -172,9 +173,12 @@ static int usblp_open(struct inode *inode, struct file *file)
 
        usblp->writeurb.transfer_buffer_length = 0;
        usblp->writeurb.status = 0;
-       usblp->readcount = 0;
 
-       usb_submit_urb(&usblp->readurb);
+       if (usblp->bidir) {
+               usblp->readcount = 0;
+               usb_submit_urb(&usblp->readurb);
+       }
+
        return 0;
 }
 
@@ -185,7 +189,8 @@ static int usblp_release(struct inode *inode, struct file *file)
        usblp->used = 0;
                        
        if (usblp->dev) {
-               usb_unlink_urb(&usblp->readurb);
+               if (usblp->bidir)
+                       usb_unlink_urb(&usblp->readurb);
                usb_unlink_urb(&usblp->writeurb);
                MOD_DEC_USE_COUNT;
                return 0;
@@ -203,8 +208,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
 {
        struct usblp *usblp = file->private_data;
        poll_wait(file, &usblp->wait, wait);
-       return (usblp->readurb.status  == -EINPROGRESS ? 0 : POLLIN  | POLLRDNORM)
-            | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
+       return ((usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
+                             | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
 }
 
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
@@ -315,7 +320,6 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
        int minor, i, alts = -1, bidir = 0;
        char *buf;
 
-
        for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
 
                interface = &dev->actconfig->interface[ifnum].altsetting[i];
@@ -342,22 +346,21 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
                err("can't set desired altsetting %d on interface %d", alts, ifnum);
 
        epwrite = interface->endpoint + 0;
-       epread = NULL;
-
-       if (bidir) {
-               epread  = interface->endpoint + 1;
-               if ((epread->bEndpointAddress & 0x80) != 0x80) {
-                       epwrite = interface->endpoint + 1;
-                       epread  = interface->endpoint + 0;
+       epread = bidir ? interface->endpoint + 1 : NULL;
 
-                       if ((epread->bEndpointAddress & 0x80) != 0x80)
-                               return NULL;
-               }
+       if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
+               if (interface->bNumEndpoints == 1)
+                       return NULL;
+               epwrite = interface->endpoint + 1;
+               epread = bidir ? interface->endpoint + 0 : NULL;
        }
 
        if ((epwrite->bEndpointAddress & 0x80) == 0x80)
                return NULL;
 
+       if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
+               return NULL;
+
        for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
        if (usblp_table[minor]) {
                err("no more free usblp devices");
@@ -386,10 +389,9 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
        FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
                buf, 0, usblp_bulk, usblp);
 
-       if (bidir) {
+       if (bidir)
                FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
                        buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
-       }
 
        info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
                minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
@@ -408,8 +410,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
 
        usblp->dev = NULL;
 
-       usb_unlink_urb(&usblp->readurb);
        usb_unlink_urb(&usblp->writeurb);
+       if (usblp->bidir)
+               usb_unlink_urb(&usblp->readurb);
 
        kfree(usblp->writeurb.transfer_buffer);
 
index 8a33186128fca0e517decaba366afa67e37d34f0..f2c51f2058cabacb81ca477f38a016e52d44a20b 100644 (file)
@@ -12,7 +12,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Randy Dunlap
  *
- * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
+ * $Id: usb-uhci.c,v 1.231 2000/05/13 15:34:17 acher Exp $
  */
 
 #include <linux/config.h>
@@ -48,7 +48,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.231 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -109,10 +109,10 @@ void clean_descs(uhci_t *s, int force)
 
        while (q != &s->free_desc) {
                qh = list_entry (q, uhci_desc_t, horizontal);
+               q=qh->horizontal.prev;
+
                if ((qh->last_used!=now) || force)
                        delete_qh(s,qh);
-
-               q=qh->horizontal.prev;
        }
 }
 /*-------------------------------------------------------------------*/
@@ -1142,6 +1142,12 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
 
                        if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
                                urb->status = -ENOENT;  // now the urb is really dead
+                       switch (usb_pipetype (pipe)) {
+                       case PIPE_ISOCHRONOUS:
+                       case PIPE_INTERRUPT:
+                               uhci_clean_iso_step2(s, urb_priv);
+                               break;
+                       }
        
                        usb_dec_dev_use (dev);
 #ifdef DEBUG_SLAB
@@ -1149,12 +1155,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
 #else
                        kfree (urb_priv);
 #endif
-                       switch (usb_pipetype (pipe)) {
-                       case PIPE_ISOCHRONOUS:
-                       case PIPE_INTERRUPT:
-                               uhci_clean_iso_step2(s, urb_priv);
-                               break;
-                       }
+
                        list_del (&urb->urb_list);
                }
        }
@@ -1168,7 +1169,9 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
        
        async_dbg("unlink_urb_async called %p",urb);
 
-       if (urb->status == -EINPROGRESS) {
+       if ((urb->status == -EINPROGRESS) ||
+           ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+       {
                ((urb_priv_t*)urb->hcpriv)->started = ~0;
 
                dequeue_urb (s, urb);
@@ -1560,7 +1563,7 @@ _static int uhci_submit_urb (urb_t *urb)
 
        urb->hcpriv = urb_priv;
        INIT_LIST_HEAD (&urb_priv->desc_list);
-       urb_priv->short_control_packet = 0;
+       urb_priv->flags = 0;
        dbg("submit_urb: scheduling %p", urb);
        urb_priv->next_queued_urb = NULL;
        urb_priv->prev_queued_urb = NULL;
@@ -2151,7 +2154,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
           status stage is completed
         */
 
-       if (urb_priv->short_control_packet && 
+       if (urb_priv->flags && 
                ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) 
                goto transfer_finished;
 
@@ -2199,7 +2202,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
                                        dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
                                        //uhci_show_td (desc);
                                        //uhci_show_td (last_desc);
-                                       urb_priv->short_control_packet=1;
+                                       urb_priv->flags = 1; // mark as short control packet
                                        return 0;
                                }
                        }
@@ -2280,35 +2283,43 @@ _static int process_interrupt (uhci_t *s, urb_t *urb)
                if (urb->complete) {
                        //dbg("process_interrupt: calling completion, status %i",status);
                        urb->status = status;
-                       
+                       ((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
+
                        spin_unlock(&s->urb_list_lock);
                        
                        urb->complete ((struct urb *) urb);
                        
                        spin_lock(&s->urb_list_lock);
-                       
-                       urb->status = -EINPROGRESS;
+
+                       ((urb_priv_t*)urb->hcpriv)->flags=0;                                    
                }
+               
+               if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+                           (urb->status != -ENOENT)) {
+
+                       urb->status = -EINPROGRESS;
 
-               // Recycle INT-TD if interval!=0, else mark TD as one-shot
-               if (urb->interval) {
-
-                       desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
-                       if (status==0) {
-                               ((urb_priv_t*)urb->hcpriv)->started=jiffies;
-                               desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-                                     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
-                               usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-                       } else {
-                               desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-                                     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                       // Recycle INT-TD if interval!=0, else mark TD as one-shot
+                       if (urb->interval) {
+                               
+                               desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
+                               if (status==0) {
+                                       ((urb_priv_t*)urb->hcpriv)->started=jiffies;
+                                       desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+                                                                           usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                                       usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+                               } else {
+                                       desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+                                                                            usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                               }
+                               desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+                                       (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+                               mb();
+                       }
+                       else {
+                               uhci_unlink_urb_async(s, urb);
+                               desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
                        }
-                       desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-                               (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-                       mb();
-               }
-               else {
-                       desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
                }
        }
 
@@ -2334,7 +2345,7 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode)
        dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
            urb->number_of_packets,mode,desc->hw.td.status);
 
-       for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) {
+       for (i = 0; p != &urb_priv->desc_list;  i++) {
                desc = list_entry (p, uhci_desc_t, desc_list);
                
                //uhci_show_td(desc);
@@ -2378,8 +2389,9 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode)
                dbg("process_iso: %i: len:%d %08x status:%x",
                     i, urb->iso_frame_desc[i].actual_length, desc->hw.td.status,urb->iso_frame_desc[i].status);
 
-               delete_desc (desc);
                list_del (p);
+               p = p->next;
+               delete_desc (desc);
        }
        
        dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
@@ -2824,7 +2836,6 @@ int __init uhci_init (void)
                if (type != 0)
                        continue;
 
-
                if (pci_enable_device (dev) < 0)
                        continue;
 
index 3c5717d1eb309bd658fa0f3d0e39fde9a99fcfa6..67eb4d210cbf39eafb81f9df3e041e8e9f308900 100644 (file)
@@ -2,7 +2,7 @@
 #define __LINUX_UHCI_H
 
 /*
-   $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
+   $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $
  */
 #define MODNAME "usb-uhci"
 #define UHCI_LATENCY_TIMER 0
@@ -160,7 +160,7 @@ typedef struct {
        uhci_desc_t *bottom_qh;
        uhci_desc_t *next_qh;           // next helper QH
        char use_loop;
-       char short_control_packet;
+       char flags;
 } urb_priv_t, *purb_priv_t;
 
 struct virt_root_hub {
index 2e87c79d7d6e217d07cb16e054243fb42ab5ef28..8a8bea5a0d4efef45f73db84b63265360fadc069 100644 (file)
@@ -1636,3 +1636,5 @@ static void __exit cyberpro_exit(void)
 module_init(cyber2000fb_init);
 #endif
 module_exit(cyberpro_exit);
+
+MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
index eefc038da620bc914d76d82cf5006e54d10f0b5b..c6d6055535817ea8693706e14389adc369f87a85 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Integraphics Cyber2000 frame buffer device
  */
+#include <linux/config.h>
 
 #define cyber2000_outb(dat,reg)        writeb(dat, CyberRegs + reg)
 #define cyber2000_outw(dat,reg)        writew(dat, CyberRegs + reg)
index 9219a138f6ead212bb3ddbf6f5edf14823bdfc55..0693daf69fddf5204b44247def783ed5e7e26cce 100644 (file)
@@ -21,7 +21,7 @@ ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
                nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \
                openpromfs autofs4 ramfs
 
-SUB_DIRS := partitions
+SUB_DIRS :=
 
 ifeq ($(CONFIG_QUOTA),y)
 O_OBJS += dquot.o
@@ -29,6 +29,14 @@ else
 O_OBJS += noquot.o
 endif
 
+ifdef CONFIG_PROC_FS
+SUB_DIRS += proc
+endif
+
+SUB_DIRS += partitions
+
+# Do not add any filesystems before this line
+
 ifeq ($(CONFIG_EXT2_FS),y)
 SUB_DIRS += ext2
 else
@@ -93,10 +101,6 @@ else
   endif
 endif
 
-ifdef CONFIG_PROC_FS
-SUB_DIRS += proc
-endif
-
 ifeq ($(CONFIG_BFS_FS),y)
 SUB_DIRS += bfs
 else
index 49d818e21e71a071a2baa4c6b1b20ec02b192464..ef4af4dfefda4b6f8c3c7fc691d922649d15be91 100644 (file)
@@ -86,6 +86,8 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
        struct user dump;
 #if defined(__alpha__)
 #       define START_DATA(u)   (u.start_data)
+#elif defined(__arm__)
+#      define START_DATA(u)    ((u.u_tsize << PAGE_SHIFT) + u.start_code)
 #elif defined(__sparc__)
 #       define START_DATA(u)    (u.u_tsize)
 #elif defined(__i386__) || defined(__mc68000__)
@@ -217,7 +219,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
        envp = (char **) sp;
        sp -= argc+1;
        argv = (char **) sp;
-#if defined(__i386__) || defined(__mc68000__)
+#if defined(__i386__) || defined(__mc68000__) || defined(__arm__)
        put_user((unsigned long) envp,--sp);
        put_user((unsigned long) argv,--sp);
 #endif
index 1b3ff98b25301c9a8c5a1d7284bd7bc3a730eaf2..6eac456ad6224c0b3cc10399d6d315e47d03c163 100644 (file)
@@ -788,7 +788,7 @@ void d_rehash(struct dentry * entry)
  * Note that we have to be a lot more careful about getting the hash
  * switched - we have to switch the hash value properly even if it
  * then no longer matches the actual (corrupted) string of the target.
- * The has value has to match the hash queue that the dentry is on..
+ * The hash value has to match the hash queue that the dentry is on..
  */
 static inline void switch_names(struct dentry * dentry, struct dentry * target)
 {
index 992bbd6aa8a72f4e6727f92120c4d30f78eb767b..eded5971f2b672470486d3e890156fa680a8b6fa 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -288,6 +288,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
        if (!mpnt) 
                return -ENOMEM; 
        
+       down(&current->mm->mmap_sem);
        {
                mpnt->vm_mm = current->mm;
                mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -311,6 +312,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
                }
                stack_base += PAGE_SIZE;
        }
+       up(&current->mm->mmap_sem);
        
        return 0;
 }
index d7e17e72f8476b61caea4e6099f3d87921a745a7..4edd6b7482dc09685dfcaa737a9ecd8d0ad14828 100644 (file)
@@ -86,6 +86,8 @@ static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree,
        retval.bn->magic = HFS_BNODE_MAGIC;
        retval.bn->tree = tree;
        retval.bn->node = node;
+       hfs_init_waitqueue(&retval.bn->wqueue);
+       hfs_init_waitqueue(&retval.bn->rqueue);
        hfs_bnode_lock(&retval, HFS_LOCK_WRITE);
 
        retval.bn->buf = get_new_node(tree, node);
index 85e3a909b76de57885b31d2e24fb645098df47b7..e2b975fae9656c0ad85abcc39e974d6ec92f5b45 100644 (file)
@@ -60,7 +60,7 @@ typedef struct {
        hfs_byte_t      RExtRec[12];    /* first extent record
                                           for the resource fork */
        hfs_lword_t     Resrv;          /* reserved by Apple */
-} FIL_REC;
+} __attribute__((packed)) FIL_REC;
 
 /* the catalog record for a directory */
 typedef struct {
@@ -74,14 +74,14 @@ typedef struct {
        hfs_dinfo_t     UsrInfo;        /* data used by the Finder */
        hfs_dxinfo_t    FndrInfo;       /* more data used by Finder */
        hfs_byte_t      Resrv[16];      /* reserved by Apple */
-} DIR_REC;
+} __attribute__((packed)) DIR_REC;
 
 /* the catalog record for a thread */
 typedef struct {
        hfs_byte_t              Reserv[8];      /* reserved by Apple */
        hfs_lword_t             ParID;          /* CNID of parent directory */
        struct hfs_name         CName;          /* The name of this entry */
-} THD_REC;
+}  __attribute__((packed)) THD_REC;
 
 /* A catalog tree record */
 struct hfs_cat_rec {
@@ -92,7 +92,7 @@ struct hfs_cat_rec {
                DIR_REC dir;
                THD_REC thd;
        } u;
-};
+} __attribute__((packed));
 
 /*================ File-local variables ================*/
  
index 80e47fc628432cbcb027d231df15882264b16a63..ba62615b03572d39cf14bc26f1e5468ed043814d 100644 (file)
@@ -158,7 +158,7 @@ struct hdr_hdr {
         hfs_byte_t     filler[16];
         hfs_word_t     entries;
         hfs_byte_t     descrs[12*HFS_HDR_MAX];
-};
+}  __attribute__((packed));
 
 /*================ File-local functions ================*/
 
index 3819a685f4809b46ab3c665ab02fe71f094953a8..9552bbb34154dd0c3683e22afb3dc811316ef2fe 100644 (file)
 struct hfs_name {
        hfs_byte_t      Len;
        hfs_byte_t      Name[31];
-};
+} __attribute__((packed));
 
 typedef struct {
        hfs_word_t      v;
@@ -150,21 +150,21 @@ typedef struct {
        hfs_word_t       fdFlags;
        hfs_point_t      fdLocation;
        hfs_word_t       fdFldr;
-} hfs_finfo_t;
+} __attribute__((packed)) hfs_finfo_t;
 
 typedef struct {
        hfs_word_t      fdIconID;
        hfs_byte_t      fdUnused[8];
        hfs_word_t      fdComment;
        hfs_lword_t     fdPutAway;
-} hfs_fxinfo_t;
+} __attribute__((packed)) hfs_fxinfo_t;
 
 typedef struct {
        hfs_rect_t      frRect;
        hfs_word_t      frFlags;
        hfs_point_t     frLocation;
        hfs_word_t      frView;
-} hfs_dinfo_t;
+} __attribute__((packed)) hfs_dinfo_t;
 
 typedef struct {
        hfs_point_t     frScroll;
@@ -172,7 +172,7 @@ typedef struct {
        hfs_word_t      frUnused;
        hfs_word_t      frComment;
        hfs_lword_t     frPutAway;
-} hfs_dxinfo_t;
+} __attribute__((packed)) hfs_dxinfo_t;
 
 union hfs_finder_info {
        struct {
@@ -189,7 +189,7 @@ union hfs_finder_info {
 struct hfs_bkey {
        hfs_byte_t      KeyLen;         /* number of bytes in the key */
        hfs_byte_t      value[1];       /* (KeyLen) bytes of key */
-};
+} __attribute__((packed));
 
 /* Cast to a pointer to a generic bkey */
 #define        HFS_BKEY(X)     (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X)))
@@ -200,7 +200,7 @@ struct hfs_cat_key {
        hfs_byte_t      Resrv1; /* padding */
        hfs_lword_t     ParID;  /* CNID of the parent dir */
        struct hfs_name CName;  /* The filename of the entry */
-};
+} __attribute__((packed));
 
 /* The key used in the extents b-tree: */
 struct hfs_ext_key {
@@ -208,7 +208,7 @@ struct hfs_ext_key {
        hfs_byte_t      FkType; /* HFS_FK_{DATA,RSRC} */
        hfs_lword_t     FNum;   /* The File ID of the file */
        hfs_word_t      FABN;   /* allocation blocks number*/
-};
+} __attribute__((packed));
 
 /*======== Data structures kept in memory ========*/
 
index 97423b350179414778cc57dbb9a7dfc79683ea3b..39d6df4d52d8d36c13a822b25f22bee8a09183e1 100644 (file)
@@ -90,7 +90,7 @@ struct BTHdrRec {
         hfs_byte_t  bthResv2;   /* reserved */
         hfs_lword_t bthAtrb;    /* (F) attributes */
         hfs_lword_t bthResv3[16]; /* Reserved */
-};
+} __attribute__((packed));
 
 /*
  * struct NodeDescriptor
@@ -112,7 +112,7 @@ struct NodeDescriptor {
        hfs_byte_t  ndNHeight;  /* (F) The level of this node (leaves=1) */
        hfs_word_t  ndNRecs;    /* (V) The number of records in this node */
        hfs_word_t  ndResv2;    /* Reserved */
-};
+} __attribute__((packed));
 
 /*
  * typedef hfs_cmpfn
index 386a6ae7936b41760af778639cf5382de775b7e9..b44fdafc8390b9b2fc4d820ca42d8401feb5ad3f 100644 (file)
@@ -71,7 +71,7 @@ struct raw_mdb {
        hfs_byte_t      drXTExtRec[12]; /* extents B-tree's first 3 extents */
        hfs_lword_t     drCTFlSize;     /* bytes in the catalog B-tree */
        hfs_byte_t      drCTExtRec[12]; /* catalog B-tree's first 3 extents */
-};
+} __attribute__((packed));
 
 /*================ Global functions ================*/
 
index 12922c6d7819339add05bf2e1f6c79168761e2cc..2392a0791bec7650ae77a882ae0dd6b2f91d842d 100644 (file)
@@ -77,7 +77,7 @@ struct old_pmap {
                hfs_lword_t     pdSize;
                hfs_lword_t     pdFSID;
        }       pdEntry[42];
-};
+} __attribute__((packed));
 
 /*================ File-local functions ================*/
 
index 1bacb24a7b2f5abc95965536c57726668b58b5f6..64373d6ad05d8685a0ef17d2d4005ce5c98f2814 100644 (file)
@@ -377,7 +377,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
  *
  *     Discard all of the inodes for a given superblock. If the discard
  *     fails because there are busy inodes then a non zero value is returned.
- *     If the discard is successful all the inodes are dicarded.
+ *     If the discard is successful all the inodes have been discarded.
  */
  
 int invalidate_inodes(struct super_block * sb)
@@ -470,7 +470,7 @@ int shrink_icache_memory(int priority, int gfp_mask)
 /*
  * Called with the inode lock held.
  * NOTE: we are not increasing the inode-refcount, you must call __iget()
- * by hand after calling find_inode now! This simplify iunique and won't
+ * by hand after calling find_inode now! This simplifies iunique and won't
  * add any additional branch in the common code.
  */
 static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
index 376eed9cc4ab5062027219690ef74cd789554d53..cc3025ee32681eecf32b4207b34d1618244db4db 100644 (file)
@@ -233,11 +233,21 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
        struct rpc_clnt *clnt;
        struct nlm_args *argp = &req->a_args;
        struct nlm_res  *resp = &req->a_res;
+       struct file     *filp = argp->lock.fl.fl_file;
+       struct rpc_message msg;
        int             status;
 
        dprintk("lockd: call procedure %s on %s\n",
                        nlm_procname(proc), host->h_name);
 
+       msg.rpc_proc = proc;
+       msg.rpc_argp = argp;
+       msg.rpc_resp = resp;
+       if (filp)
+               msg.rpc_cred = nfs_file_cred(filp);
+       else
+               msg.rpc_cred = NULL;
+
        do {
                if (host->h_reclaiming && !argp->reclaim) {
                        interruptible_sleep_on(&host->h_gracewait);
@@ -249,7 +259,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
                        return -ENOLCK;
 
                /* Perform the RPC call. If an error occurs, try again */
-               if ((status = rpc_call(clnt, proc, argp, resp, 0)) < 0) {
+               if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
                        dprintk("lockd: rpc_call returned error %d\n", -status);
                        switch (status) {
                        case -EPROTONOSUPPORT:
@@ -330,11 +340,31 @@ int
 nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
 {
        struct nlm_host *host = req->a_host;
-       int status;
+       struct rpc_clnt *clnt;
+       struct nlm_args *argp = &req->a_args;
+       struct nlm_res  *resp = &req->a_res;
+       struct file     *file = argp->lock.fl.fl_file;
+       struct rpc_message msg;
+       int             status;
 
+       dprintk("lockd: call procedure %s on %s (async)\n",
+                       nlm_procname(proc), host->h_name);
+
+       /* If we have no RPC client yet, create one. */
+       if ((clnt = nlm_bind_host(host)) == NULL)
+               return -ENOLCK;
+
+        /* bootstrap and kick off the async RPC call */
+       msg.rpc_proc = proc;
+       msg.rpc_argp = argp;
+       msg.rpc_resp =resp;
+       if (file)
+               msg.rpc_cred = nfs_file_cred(file);
+       else
+               msg.rpc_cred = NULL;
        /* Increment host refcount */
        nlm_get_host(host);
-       status = nlmsvc_async_call(req, proc, callback);
+        status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
        if (status < 0)
                nlm_release_host(host);
        return status;
index 97a9d27efddfc9af866bd1a0a222148194f42b03..279fcc3c19c0b50614a7474c2f08a8ef35d07efa 100644 (file)
@@ -533,8 +533,10 @@ callback:
        nlmsvc_insert_block(block, jiffies + 30 * HZ);
 
        /* Call the client */
-       nlmclnt_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
-                                               nlmsvc_grant_callback);
+       nlm_get_host(block->b_call.a_host);
+       if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
+                                               nlmsvc_grant_callback) < 0)
+               nlm_release_host(block->b_call.a_host);
        up(&file->f_sema);
 }
 
index 2d2ee4a0297505171ff81eb2cf8c411af90cda08..20840acbadefd1e6e7234191f6f13df47391bccb 100644 (file)
@@ -71,6 +71,70 @@ struct inode_operations nfs_dir_inode_operations = {
 };
 
 typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
+typedef struct {
+       struct file     *file;
+       struct page     *page;
+       unsigned long   page_index;
+       unsigned        page_offset;
+       u64             target;
+       struct nfs_entry *entry;
+       decode_dirent_t decode;
+       int             plus;
+       int             error;
+} nfs_readdir_descriptor_t;
+
+/* Now we cache directories properly, by stuffing the dirent
+ * data directly in the page cache.
+ *
+ * Inode invalidation due to refresh etc. takes care of
+ * _everything_, no sloppy entry flushing logic, no extraneous
+ * copying, network direct to page cache, the way it was meant
+ * to be.
+ *
+ * NOTE: Dirent information verification is done always by the
+ *      page-in of the RPC reply, nowhere else, this simplies
+ *      things substantially.
+ */
+static
+int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
+{
+       struct dentry   *dir = desc->file->f_dentry;
+       struct inode    *inode = dir->d_inode;
+       void            *buffer = (void *)kmap(page);
+       int             plus = NFS_USE_READDIRPLUS(inode);
+       int             error;
+
+       dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
+
+ again:
+       error = NFS_PROTO(inode)->readdir(dir, desc->entry->cookie, buffer,
+                                         NFS_SERVER(inode)->dtsize, plus);
+       /* We requested READDIRPLUS, but the server doesn't grok it */
+       if (desc->plus && error == -ENOTSUPP) {
+               NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+               plus = 0;
+               goto again;
+       }
+       if (error < 0)
+               goto error;
+       SetPageUptodate(page);
+       kunmap(page);
+       /* Ensure consistent page alignment of the data.
+        * Note: assumes we have exclusive access to this mapping either
+        *       throught inode->i_sem or some other mechanism.
+        */
+       if (page->index == 0)
+               invalidate_inode_pages(inode);
+       UnlockPage(page);
+       return 0;
+ error:
+       SetPageError(page);
+       kunmap(page);
+       UnlockPage(page);
+       invalidate_inode_pages(inode);
+       desc->error = error;
+       return -EIO;
+}
 
 /*
  * Given a pointer to a buffer that has already been filled by a call
@@ -81,309 +145,217 @@ typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
  * read.
  */
 static inline
-long find_dirent(struct page *page, loff_t offset,
-                struct nfs_entry *entry,
-                decode_dirent_t decode, int plus, int use_cookie)
+int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
 {
-       u8              *p = (u8 *)kmap(page),
-                       *start = p;
-       unsigned long   base = page_offset(page),
-                       pg_offset = 0;
-       int             loop_count = 0;
+       struct nfs_entry *entry = desc->entry;
+       char            *start = (char *)kmap(page),
+                       *p = start;
+       int             loop_count = 0,
+                       status = 0;
 
-       if (!p)
-               return -EIO;
        for(;;) {
-               p = (u8*)decode((__u32*)p, entry, plus);
-               if (IS_ERR(p))
+               p = (char *)desc->decode((u32*)p, entry, desc->plus);
+               if (IS_ERR(p)) {
+                       status = PTR_ERR(p);
                        break;
-               pg_offset = p - start;
-               entry->prev = entry->offset;
-               entry->offset = base + pg_offset;
-               if ((use_cookie ? entry->cookie : entry->offset) > offset)
+               }
+               desc->page_offset = p - start;
+               dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie);
+               if (entry->prev_cookie == desc->target)
                        break;
                if (loop_count++ > 200) {
                        loop_count = 0;
                        schedule();
                }
        }
-
        kunmap(page);
-       return (IS_ERR(p)) ?  PTR_ERR(p) : (long)pg_offset;
+       dfprintk(VFS, "NFS: find_dirent() returns %d\n", status);
+       return status;
 }
 
 /*
  * Find the given page, and call find_dirent() in order to try to
  * return the next entry.
- *
- * Returns -EIO if the page is not available, or up to date.
  */
 static inline
-long find_dirent_page(struct inode *inode, loff_t offset,
-                     struct nfs_entry *entry)
+int find_dirent_page(nfs_readdir_descriptor_t *desc)
 {
-       decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
+       struct inode    *inode = desc->file->f_dentry->d_inode;
        struct page     *page;
-       unsigned long   index = entry->offset >> PAGE_CACHE_SHIFT;
-       long            status = -EIO;
-       int             plus = NFS_USE_READDIRPLUS(inode),
-                       use_cookie = NFS_MONOTONE_COOKIES(inode);
-
-       dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK);
-
-       if (entry->page)
-               page_cache_release(entry->page);
+       unsigned long   index = desc->page_index;
+       int             status;
 
-       page = find_get_page(&inode->i_data, index);
+       dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index);
 
-       if (page && Page_Uptodate(page))
-               status = find_dirent(page, offset, entry, decode, plus, use_cookie);
-
-       /* NB: on successful return we will be holding the page */
-       if (status < 0) {
-               entry->page = NULL;
-               if (page)
-                       page_cache_release(page);
-       } else
-               entry->page = page;
+       if (desc->page) {
+               page_cache_release(desc->page);
+               desc->page = NULL;
+       }
 
-       dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status);
+       page = read_cache_page(&inode->i_data, index,
+                              (filler_t *)nfs_readdir_filler, desc);
+       if (IS_ERR(page)) {
+               status = PTR_ERR(page);
+               goto out;
+       }
+       if (!Page_Uptodate(page))
+               goto read_error;
+
+       /* NOTE: Someone else may have changed the READDIRPLUS flag */
+       desc->plus = NFS_USE_READDIRPLUS(inode);
+       status = find_dirent(desc, page);
+       if (status >= 0)
+               desc->page = page;
+       else
+               page_cache_release(page);
+ out:
+       dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status);
        return status;
+ read_error:
+       page_cache_release(page);
+       return -EIO;
 }
 
-
 /*
  * Recurse through the page cache pages, and return a
  * filled nfs_entry structure of the next directory entry if possible.
  *
- * The target for the search is position 'offset'.
- * The latter may either be an offset into the page cache, or (better)
- * a cookie depending on whether we're interested in strictly following
- * the RFC wrt. not assuming monotonicity of cookies or not.
- *
- * For most systems, the latter is more reliable since it naturally
- * copes with holes in the directory.
+ * The target for the search is 'desc->target'.
  */
 static inline
-long search_cached_dirent_pages(struct inode *inode, loff_t offset,
-                               struct nfs_entry *entry)
+int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
 {
-       long            res = 0;
+       int             res = 0;
        int             loop_count = 0;
 
-       dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset);
+       dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target);
        for (;;) {
-               res = find_dirent_page(inode, offset, entry);
-               if (res == -EAGAIN) {
-                       /* Align to beginning of next page */
-                       entry->offset &= PAGE_CACHE_MASK;
-                       entry->offset += PAGE_CACHE_SIZE;
-               }
+               res = find_dirent_page(desc);
                if (res != -EAGAIN)
                        break;
+               /* Align to beginning of next page */
+               desc->page_offset = 0;
+               desc->page_index ++;
                if (loop_count++ > 200) {
                        loop_count = 0;
                        schedule();
                }
        }
-       if (res < 0 && entry->page) {
-               page_cache_release(entry->page);
-               entry->page = NULL;
-       }
-       dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res);
+       dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res);
        return res;
 }
 
-
-/* Now we cache directories properly, by stuffing the dirent
- * data directly in the page cache.
- *
- * Inode invalidation due to refresh etc. takes care of
- * _everything_, no sloppy entry flushing logic, no extraneous
- * copying, network direct to page cache, the way it was meant
- * to be.
- *
- * NOTE: Dirent information verification is done always by the
- *      page-in of the RPC reply, nowhere else, this simplies
- *      things substantially.
- */
-static inline
-long try_to_get_dirent_page(struct file *file, struct inode *inode,
-                           struct nfs_entry *entry)
-{
-       struct dentry   *dir = file->f_dentry;
-       struct page     *page;
-       __u32           *p;
-       unsigned long   index = entry->offset >> PAGE_CACHE_SHIFT;
-       long            res = 0;
-       unsigned int    dtsize = NFS_SERVER(inode)->dtsize;
-       int             plus = NFS_USE_READDIRPLUS(inode);
-
-       dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ index %ld\n", index);
-
-       page = grab_cache_page(&inode->i_data, index);
-
-       if (!page) {
-               res = -ENOMEM;
-               goto out;
-       }
-
-       if (Page_Uptodate(page)) {
-               dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n");
-               goto unlock_out;
-       }
-
-       p = (__u32 *)kmap(page);
-
-       if (dtsize > PAGE_CACHE_SIZE)
-               dtsize = PAGE_CACHE_SIZE;
-       res = NFS_PROTO(inode)->readdir(dir, entry->cookie, p, dtsize, plus);
-
-       kunmap(page);
-
-       if (res < 0)
-               goto error;
-       if (PageError(page))
-               ClearPageError(page);
-       SetPageUptodate(page);
-
- unlock_out:
-       UnlockPage(page);
-       page_cache_release(page);
- out:
-       dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res);
-       return res;
- error:
-       SetPageError(page);
-       goto unlock_out;
-}
-
-/* Recover from a revalidation flush.  The case here is that
- * the inode for the directory got invalidated somehow, and
- * all of our cached information is lost.  In order to get
- * a correct cookie for the current readdir request from the
- * user, we must (re-)fetch all the older readdir page cache
- * entries.
- *
- * Returns < 0 if some error occurs.
+/*
+ * Once we've found the start of the dirent within a page: fill 'er up...
  */
-static inline
-long refetch_to_readdir(struct file *file, struct inode *inode,
-                       loff_t off, struct nfs_entry *entry)
+static 
+int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
+                  filldir_t filldir)
 {
-       struct nfs_entry        my_dirent,
-                               *dirent = &my_dirent;
-       long                    res;
-       int                     plus = NFS_USE_READDIRPLUS(inode),
-                               use_cookie = NFS_MONOTONE_COOKIES(inode),
-                               loop_count = 0;
-
-       dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off);
-       *dirent = *entry;
-       entry->page = NULL;
-
-       for (res = 0;res >= 0;) {
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
-               }
+       struct file     *file = desc->file;
+       struct nfs_entry *entry = desc->entry;
+       char            *start = (char *)kmap(desc->page),
+                       *p = start + desc->page_offset;
+       unsigned long   fileid;
+       int             loop_count = 0,
+                       res = 0;
 
-               /* Search for last cookie in page cache */
-               res = search_cached_dirent_pages(inode, off, dirent);
+       dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target);
 
-               if (res >= 0) {
-                       /* Cookie was found */
-                       if ((use_cookie?dirent->cookie:dirent->offset) > off) {
-                               *entry = *dirent;
-                               dirent->page = NULL;
-                               break;
+       for(;;) {
+               /* Note: entry->prev_cookie contains the cookie for
+                *       retrieving the current dirent on the server */
+               fileid = nfs_fileid_to_ino_t(entry->ino);
+               res = filldir(dirent, entry->name, entry->len, 
+                             entry->prev_cookie, fileid);
+               if (res < 0)
+                       break;
+               file->f_pos = desc->target = entry->cookie;
+               p = (char *)desc->decode((u32 *)p, entry, desc->plus);
+               if (IS_ERR(p)) {
+                       if (PTR_ERR(p) == -EAGAIN) {
+                               desc->page_offset = 0;
+                               desc->page_index ++;
                        }
-                       continue;
-               }
-
-               if (dirent->page)
-                       page_cache_release(dirent->page);
-               dirent->page = NULL;
-
-               if (res != -EIO) {
-                       *entry = *dirent;
                        break;
                }
-
-               /* Read in a new page */
-               res = try_to_get_dirent_page(file, inode, dirent);
-               if (res == -EBADCOOKIE) {
-                       memset(dirent, 0, sizeof(*dirent));
-                       nfs_zap_caches(inode);
-                       res = 0;
-               }
-               /* We requested READDIRPLUS, but the server doesn't grok it */
-               if (plus && res == -ENOTSUPP) {
-                       NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
-                       memset(dirent, 0, sizeof(*dirent));
-                       nfs_zap_caches(inode);
-                       plus = 0;
-                       res = 0;
+               desc->page_offset = p - start;
+               if (loop_count++ > 200) {
+                       loop_count = 0;
+                       schedule();
                }
        }
-       if (dirent->page)
-               page_cache_release(dirent->page);
+       kunmap(desc->page);
+       page_cache_release(desc->page);
+       desc->page = NULL;
 
-       dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res);
+       dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res);
        return res;
 }
 
 /*
- * Once we've found the start of the dirent within a page: fill 'er up...
+ * If we cannot find a cookie in our cache, we suspect that this is
+ * because it points to a deleted file, so we ask the server to return
+ * whatever it thinks is the next entry. We then feed this to filldir.
+ * If all goes well, we should then be able to find our way round the
+ * cache on the next call to readdir_search_pagecache();
+ *
+ * NOTE: we cannot add the anonymous page to the pagecache because
+ *      the data it contains might not be page aligned. Besides,
+ *      we should already have a complete representation of the
+ *      directory in the page cache by the time we get here.
  */
-static
-int nfs_do_filldir(struct file *file, struct inode *inode,
-                  struct nfs_entry *entry, void *dirent, filldir_t filldir)
+static inline
+int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
+                    filldir_t filldir)
 {
-       decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent;
-       struct page     *page = entry->page;
-       __u8            *p,
-                       *start;
-       unsigned long   base = page_offset(page),
-                       offset = entry->offset,
-                       pg_offset,
-                       fileid;
-       int             plus = NFS_USE_READDIRPLUS(inode),
-                       use_cookie = NFS_MONOTONE_COOKIES(inode),
-                       loop_count = 0,
-                       res = 0;
-
-       dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset);
-       pg_offset = offset & ~PAGE_CACHE_MASK;
-       start = (u8*)kmap(page);
-       p = start + pg_offset;
+       struct dentry   *dir = desc->file->f_dentry;
+       struct inode    *inode = dir->d_inode;
+       struct page     *page = NULL;
+       u32             *p;
+       int             status = -EIO;
+
+       dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target);
+       if (desc->page) {
+               page_cache_release(desc->page);
+               desc->page = NULL;
+       }
 
-       for(;;) {
-               /* Note: entry->prev contains the offset of the start of the
-                *       current dirent */
-               fileid = nfs_fileid_to_ino_t(entry->ino);
-               if (use_cookie)
-                       res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid);
+       page = page_cache_alloc();
+       if (!page) {
+               status = -ENOMEM;
+               goto out;
+       }
+       p = (u32 *)kmap(page);
+       status = NFS_PROTO(inode)->readdir(dir, desc->target, p,
+                                          NFS_SERVER(inode)->dtsize, 0);
+       if (status >= 0) {
+               p = desc->decode(p, desc->entry, 0);
+               if (IS_ERR(p))
+                       status = PTR_ERR(p);
                else
-                       res = filldir(dirent, entry->name, entry->len, entry->prev, fileid);
-               if (res < 0)
-                       break;
-               file->f_pos = (use_cookie) ? entry->cookie : entry->offset;
-               p = (u8*)decode((__u32*)p, entry, plus);
-               if (!p || IS_ERR(p))
-                       break;
-               pg_offset = p - start;
-               entry->prev = entry->offset;
-               entry->offset = base + pg_offset;
-               if (loop_count++ > 200) {
-                       loop_count = 0;
-                       schedule();
-               }
+                       desc->entry->prev_cookie = desc->target;
        }
        kunmap(page);
-
-       dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res);
-       return res;
+       if (status < 0)
+               goto out_release;
+
+       desc->page_index = 0;
+       desc->page_offset = 0;
+       desc->page = page;
+       status = nfs_do_filldir(desc, dirent, filldir);
+
+       /* Reset read descriptor so it searches the page cache from
+        * the start upon the next call to readdir_search_pagecache() */
+       desc->page_index = 0;
+       desc->page_offset = 0;
+       memset(desc->entry, 0, sizeof(*desc->entry));
+ out:
+       dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status);
+       return status;
+ out_release:
+       page_cache_release(page);
+       goto out;
 }
 
 /* The file offset position is now represented as a true offset into the
@@ -393,10 +365,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
        struct dentry   *dentry = filp->f_dentry;
        struct inode    *inode = dentry->d_inode;
-       struct page     *page;
-       struct nfs_entry my_entry,
-                       *entry = &my_entry;
-       loff_t          offset;
+       nfs_readdir_descriptor_t my_desc,
+                       *desc = &my_desc;
+       struct nfs_entry my_entry;
        long            res;
 
        res = nfs_revalidate(dentry);
@@ -409,36 +380,41 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
         * read from the last dirent to revalidate f_pos
         * itself.
         */
-       memset(entry, 0, sizeof(*entry));
+       memset(desc, 0, sizeof(*desc));
+       memset(&my_entry, 0, sizeof(my_entry));
 
-       offset = filp->f_pos;
+       desc->file = filp;
+       desc->target = filp->f_pos;
+       desc->entry = &my_entry;
+       desc->decode = NFS_PROTO(inode)->decode_dirent;
 
-       while(!entry->eof) {
-               res = search_cached_dirent_pages(inode, offset, entry);
-
-               if (res < 0) {
-                       if (entry->eof)
-                               break;
-                       res = refetch_to_readdir(filp, inode, offset, entry);
-                       if (res < 0)
+       while(!desc->entry->eof) {
+               res = readdir_search_pagecache(desc);
+               if (res == -EBADCOOKIE) {
+                       /* This means either end of directory */
+                       if (desc->entry->cookie == desc->target) {
+                               res = 0;
                                break;
+                       }
+                       /* Or that the server has 'lost' a cookie */
+                       res = uncached_readdir(desc, dirent, filldir);
+                       if (res >= 0)
+                               continue;
                }
+               if (res < 0)
+                       break;
 
-               page = entry->page;
-               if (!page)
-                       printk(KERN_ERR "NFS: Missing page...\n");
-               res = nfs_do_filldir(filp, inode, entry, dirent, filldir);
-               page_cache_release(page);
-               entry->page = NULL;
+               res = nfs_do_filldir(desc, dirent, filldir);
                if (res < 0) {
                        res = 0;
                        break;
                }
-               offset = filp->f_pos;
        }
-       if (entry->page)
-               page_cache_release(entry->page);
-       if (res < 0 && res != -EBADCOOKIE)
+       if (desc->page)
+               page_cache_release(desc->page);
+       if (desc->error < 0)
+               return desc->error;
+       if (res < 0)
                return res;
        return 0;
 }
index 2d71aa7b5c83b5ff3dd0de3799edfa8b047e23ba..5b1092846a45e6c4cbd1e00c8f6e4fb66f01d495 100644 (file)
@@ -895,11 +895,20 @@ nfs_revalidate(struct dentry *dentry)
  */
 int nfs_open(struct inode *inode, struct file *filp)
 {
+       struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+       struct rpc_cred *cred = rpcauth_lookupcred(auth, 0);
+
+       filp->private_data = cred;
        return 0;
 }
 
 int nfs_release(struct inode *inode, struct file *filp)
 {
+       struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+       struct rpc_cred *cred = nfs_file_cred(filp);
+
+       if (cred)
+               rpcauth_releasecred(auth, cred);
        return 0;
 }
 
index 1dd1553ba1388507fe943d1ea28b5a70a370863b..a8b61c2e7ef19b817dea51cf193a3789d4a76b3d 100644 (file)
@@ -485,13 +485,6 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
                        break;
                }
        }
-       p++; /* EOF flag */
-
-       if (p > end) {
-               printk(KERN_NOTICE
-                       "NFS: short packet in readdir reply!\n");
-               return -errno_NFSERR_IO;
-       }
        return nr;
 }
 
index 67de662a6b1064cbd9efa0f8021e000dd1466c14..4502e46018a0a16ed1e9e0a8b22abd2f0eac09fc 100644 (file)
@@ -138,14 +138,16 @@ nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen)
 }
 
 static int
-nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
               loff_t offset, unsigned int count, void *buffer, int *eofp)
 {
+       struct dentry           *dentry = file->f_dentry;
+       struct rpc_cred         *cred = nfs_file_cred(file);
        struct nfs_readargs     arg = { NFS_FH(dentry), offset, count, 1,
                                        {{buffer, count}, {0,0}, {0,0}, {0,0},
                                         {0,0}, {0,0}, {0,0}, {0,0}} };
        struct nfs_readres      res = { fattr, count, 0 };
-       struct rpc_message      msg = { NFS3PROC_READ, &arg, &res, NULL };
+       struct rpc_message      msg = { NFS3PROC_READ, &arg, &res, cred };
        int                     status;
 
        dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
@@ -157,16 +159,18 @@ nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
 }
 
 static int
-nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags,
                loff_t offset, unsigned int count,
                void *buffer, struct nfs_writeverf *verf)
 {
+       struct dentry           *dentry = file->f_dentry;
+       struct rpc_cred         *cred = nfs_file_cred(file);
        struct nfs_writeargs    arg = { NFS_FH(dentry), offset, count,
                                        NFS_FILE_SYNC, 1,
                                        {{buffer, count}, {0,0}, {0,0}, {0,0},
                                         {0,0}, {0,0}, {0,0}, {0,0}} };
        struct nfs_writeres     res = { fattr, verf, 0 };
-       struct rpc_message      msg = { NFS3PROC_WRITE, &arg, &res, NULL };
+       struct rpc_message      msg = { NFS3PROC_WRITE, &arg, &res, cred };
        int                     status, rpcflags = 0;
 
        dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
index d6d5322174f6ad953b95121d2bb124460cc5dc14..8cfe862f43f942555e8aeaa2b8ad8e0805109fe8 100644 (file)
@@ -122,14 +122,16 @@ nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz)
 }
 
 static int
-nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
+nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags,
              loff_t offset, unsigned int count, void *buffer, int *eofp)
 {
+       struct dentry           *dentry = file->f_dentry;
+       struct rpc_cred         *cred = nfs_file_cred(file);
        struct nfs_readargs     arg = { NFS_FH(dentry), offset, count, 1,
                                       {{ buffer, count }, {0,0}, {0,0}, {0,0},
                                        {0,0}, {0,0}, {0,0}, {0,0}} };
        struct nfs_readres      res = { fattr, count, 0};
-       struct rpc_message      msg = { NFSPROC_READ, &arg, &res, NULL };
+       struct rpc_message      msg = { NFSPROC_READ, &arg, &res, cred };
        int                     status;
 
        dprintk("NFS call  read %d @ %Ld\n", count, (long long)offset);
@@ -142,16 +144,18 @@ nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags,
 }
 
 static int
-nfs_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int how,
+nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how,
               loff_t offset, unsigned int count,
               void *buffer, struct nfs_writeverf *verf)
 {
+       struct dentry           *dentry = file->f_dentry;
+       struct rpc_cred         *cred = nfs_file_cred(file);
        struct nfs_writeargs    arg = {NFS_FH(dentry), offset, count,
                                        NFS_FILE_SYNC, 1,
                                        {{buffer, count}, {0,0}, {0,0}, {0,0},
                                         {0,0}, {0,0}, {0,0}, {0,0}}};
        struct nfs_writeres     res = {fattr, verf, count};
-       struct rpc_message      msg = { NFSPROC_WRITE, &arg, &res, NULL };
+       struct rpc_message      msg = { NFSPROC_WRITE, &arg, &res, cred };
        int                     status, flags = 0;
 
        dprintk("NFS call  write %d @ %Ld\n", count, (long long)offset);
index 1c70ae58df7cae0adddb42eb432e3b7578ffb21e..b15f50e6150682fd30d2c34fbc6bd883448ea359 100644 (file)
@@ -83,8 +83,9 @@ static void nfs_readdata_release(struct rpc_task *task)
  * Read a page synchronously.
  */
 static int
-nfs_readpage_sync(struct dentry *dentry, struct page *page)
+nfs_readpage_sync(struct file *file, struct page *page)
 {
+       struct dentry   *dentry = file->f_dentry;
        struct inode    *inode = dentry->d_inode;
        struct nfs_fattr fattr;
        loff_t          offset = page_offset(page);
@@ -112,7 +113,7 @@ nfs_readpage_sync(struct dentry *dentry, struct page *page)
                        (long long)offset, rsize, buffer);
 
                lock_kernel();
-               result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset,
+               result = NFS_PROTO(inode)->read(file, &fattr, flags, offset,
                                                rsize, buffer, &eof);
                unlock_kernel();
                nfs_refresh_inode(inode, &fattr);
@@ -195,9 +196,9 @@ nfs_mark_request_read(struct nfs_page *req)
 }
 
 static int
-nfs_readpage_async(struct dentry *dentry, struct page *page)
+nfs_readpage_async(struct file *file, struct page *page)
 {
-       struct inode    *inode = dentry->d_inode;
+       struct inode    *inode = file->f_dentry->d_inode;
        struct nfs_page *req, *new = NULL;
        int             result;
 
@@ -227,7 +228,7 @@ nfs_readpage_async(struct dentry *dentry, struct page *page)
                }
 
                result = -ENOMEM;
-               new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE);
+               new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE);
                if (!new)
                        break;
        }
@@ -462,20 +463,16 @@ nfs_readpage_result(struct rpc_task *task)
 /*
  * Read a page over NFS.
  * We read the page synchronously in the following cases:
- *  -  The file is a swap file. Swap-ins are always sync operations,
- *     so there's no need bothering to make async reads 100% fail-safe.
  *  -  The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
  *     around this by creating several consecutive read requests, but
  *     that's hardly worth it.
  *  -  The error flag is set for this page. This happens only when a
  *     previous async read operation failed.
- *  -  The server is congested.
  */
 int
 nfs_readpage(struct file *file, struct page *page)
 {
-       struct dentry *dentry = file->f_dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_dentry->d_inode;
        int             error;
 
        dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
@@ -493,11 +490,11 @@ nfs_readpage(struct file *file, struct page *page)
 
        error = -1;
        if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
-               error = nfs_readpage_async(dentry, page);
+               error = nfs_readpage_async(file, page);
        if (error >= 0)
                goto out;
 
-       error = nfs_readpage_sync(dentry, page);
+       error = nfs_readpage_sync(file, page);
        if (error < 0 && IS_SWAPFILE(inode))
                printk("Aiee.. nfs swap-in of page failed!\n");
 out:
index 52af85acb456699d3d90ad10aba2b0df25992e32..464776ac3c685ab6b9f053908f0a9095f05f67a3 100644 (file)
@@ -89,8 +89,7 @@ struct nfs_write_data {
 /*
  * Local function declarations
  */
-static struct nfs_page * nfs_update_request(struct file*, struct dentry *,
-                                           struct page *page,
+static struct nfs_page * nfs_update_request(struct file*, struct page *page,
                                            unsigned int, unsigned int);
 static void    nfs_strategy(struct inode *inode);
 static void    nfs_writeback_done(struct rpc_task *);
@@ -168,9 +167,10 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct dentry *dentry, struct page *page,
+nfs_writepage_sync(struct file *file, struct page *page,
                   unsigned int offset, unsigned int count)
 {
+       struct dentry   *dentry = file->f_dentry;
        struct inode    *inode = dentry->d_inode;
        loff_t          base;
        unsigned int    wsize = NFS_SERVER(inode)->wsize;
@@ -193,7 +193,7 @@ nfs_writepage_sync(struct dentry *dentry, struct page *page,
                if (count < wsize && !IS_SWAPFILE(inode))
                        wsize = count;
 
-               result = NFS_PROTO(inode)->write(dentry, &fattr, flags,
+               result = NFS_PROTO(inode)->write(file, &fattr, flags,
                                                 base, wsize, buffer, &verf);
                nfs_write_attributes(inode, &fattr);
 
@@ -229,18 +229,18 @@ io_error:
 }
 
 static int
-nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
+nfs_writepage_async(struct file *file, struct page *page,
                    unsigned int offset, unsigned int count)
 {
        struct nfs_page *req;
        int             status;
 
-       req = nfs_update_request(file, dentry, page, offset, count);
+       req = nfs_update_request(file, page, offset, count);
        status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
        if (status < 0)
                goto out;
        nfs_release_request(req);
-       nfs_strategy(dentry->d_inode);
+       nfs_strategy(file->f_dentry->d_inode);
  out:
        return status;
 }
@@ -251,8 +251,7 @@ nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
 int
 nfs_writepage(struct file *file, struct page *page)
 {
-       struct dentry *dentry = file->f_dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_dentry->d_inode;
        unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
        unsigned offset = PAGE_CACHE_SIZE;
        int err;
@@ -267,11 +266,11 @@ nfs_writepage(struct file *file, struct page *page)
                return -EIO;
 do_it:
        if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
-               err = nfs_writepage_async(file, dentry, page, 0, offset);
+               err = nfs_writepage_async(file, page, 0, offset);
                if (err >= 0)
                        goto out_ok;
        }
-       err = nfs_writepage_sync(dentry, page, 0, offset); 
+       err = nfs_writepage_sync(file, page, 0, offset); 
        if ( err == offset)
                goto out_ok;
        return err; 
@@ -476,10 +475,12 @@ nfs_mark_request_commit(struct nfs_page *req)
  * Page must be locked by the caller. This makes sure we never create
  * two different requests for the same page, and avoids possible deadlock
  * when we reach the hard limit on the number of dirty pages.
+ * It should be safe to sleep here.
  */
-struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct page *page,
                                    unsigned int offset, unsigned int count)
 {
+       struct dentry           *dentry = file->f_dentry;
        struct inode            *inode = dentry->d_inode;
        struct nfs_reqlist      *cache = NFS_REQUESTLIST(inode);
        struct nfs_page         *req = NULL;
@@ -531,8 +532,10 @@ struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
        page_cache_get(page);
        req->wb_offset  = offset;
        req->wb_bytes   = count;
-       req->wb_dentry  = dget(dentry);
-       req->wb_cred    = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+       req->wb_file    = file;
+       get_file(file);
+       req->wb_dentry  = dentry;
+       req->wb_cred    = nfs_file_cred(file);
        req->wb_count   = 1;
 
        /* register request's existence */
@@ -573,12 +576,7 @@ nfs_release_request(struct nfs_page *req)
        if (NFS_WBACK_BUSY(req))
                printk(KERN_ERR "NFS: Request released while still locked!\n");
 
-       rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
-       lock_kernel();
-       if (req->wb_file)
-               fput(req->wb_file);
-       dput(req->wb_dentry);
-       unlock_kernel();
+       fput(req->wb_file);
        page_cache_release(page);
        nfs_page_free(req);
        /* wake up anyone waiting to allocate a request */
@@ -789,10 +787,6 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
                if (prev) {
                        if (req->wb_file != prev->wb_file)
                                break;
-                       if (req->wb_dentry != prev->wb_dentry)
-                               break;
-                       if (req->wb_cred != prev->wb_cred)
-                               break;
                        if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
                                break;
 
@@ -818,10 +812,10 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
  * Note: Should always be called with the Page Lock held!
  */
 static struct nfs_page *
-nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
+nfs_update_request(struct file* file, struct page *page,
                   unsigned int offset, unsigned int bytes)
 {
-       struct inode            *inode = dentry->d_inode;
+       struct inode            *inode = file->f_dentry->d_inode;
        struct nfs_page         *req, *new = NULL;
        unsigned long           rqend, end;
 
@@ -856,21 +850,14 @@ nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
                }
                spin_unlock(&nfs_wreq_lock);
 
-
-               /* Create the request. It's safe to sleep in this call because
-                * we only get here if the page is locked.
-                *
+               /*
                 * If we're over the soft limit, flush out old requests
                 */
-               if (file && nfs_nr_requests >= MAX_REQUEST_SOFT)
+               if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
                        nfs_wb_file(inode, file);
-               new = nfs_create_request(dentry, page, offset, bytes);
+               new = nfs_create_request(file, page, offset, bytes);
                if (!new)
                        return ERR_PTR(-ENOMEM);
-               if (file) {
-                       new->wb_file = file;
-                       get_file(file);
-               }
                /* If the region is locked, adjust the timeout */
                if (region_locked(inode, new))
                        new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
@@ -1006,7 +993,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
         * page synchronously.
         */
        if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
-               return nfs_writepage_sync(dentry, page, offset, count);
+               return nfs_writepage_sync(file, page, offset, count);
 
        /*
         * Try to find an NFS request corresponding to this page
@@ -1015,7 +1002,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign
         * it out now.
         */
        do {
-               req = nfs_update_request(file, dentry, page, offset, count);
+               req = nfs_update_request(file, page, offset, count);
                status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
                if (status != -EBUSY)
                        break;
index 13b5ca946db7a59d411215180bc38fd8f1a47693..d053ad1be1e408e5bf21f22a47a64eed8654985d 100644 (file)
@@ -134,6 +134,9 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
                case IDE0_MAJOR:
                        maj = "hd";
                        break;
+               case MD_MAJOR:
+                       unit -= 'a'-'0';
+                       break;
        }
        if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
                unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
index 13ec76b020194f2735bd938c61994694c7499817..01db469dac988510864fe1669afc0f882397cce9 100644 (file)
@@ -315,13 +315,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
        size_t elf_buflen;
        int num_vma;
 
-       /* XXX we need to somehow lock vmlist between here
-        * and after elf_kcore_store_hdr() returns.
-        * For now assume that num_vma does not change (TA)
-        */
+       read_lock(&vmlist_lock);
        proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
-       if (buflen == 0 || *fpos >= size)
+       if (buflen == 0 || *fpos >= size) {
+               read_unlock(&vmlist_lock);
                return 0;
+       }
 
        /* trim buflen to not go beyond EOF */
        if (buflen > size - *fpos)
@@ -335,10 +334,13 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
                if (buflen < tsz)
                        tsz = buflen;
                elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
-               if (!elf_buf)
+               if (!elf_buf) {
+                       read_unlock(&vmlist_lock);
                        return -ENOMEM;
+               }
                memset(elf_buf, 0, elf_buflen);
                elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen);
+               read_unlock(&vmlist_lock);
                if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
                        kfree(elf_buf);
                        return -EFAULT;
@@ -352,7 +354,8 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
                /* leave now if filled buffer already */
                if (buflen == 0)
                        return acc;
-       }
+       } else
+               read_unlock(&vmlist_lock);
 
        /* where page 0 not mapped, write zeros into buffer */
 #if defined (__i386__) || defined (__mc68000__)
index b32b1fc6cd5fd1c82955bf58493c59d9f916e090..b5761f2c9e0976cecf46d9e50000153c62baf20e 100644 (file)
@@ -76,7 +76,7 @@ LIST_HEAD(super_blocks);
  *     Once the reference is obtained we can drop the spinlock.
  */
 
-static struct file_system_type *file_systems = NULL;
+static struct file_system_type *file_systems;
 static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED;
 
 /* WARNING: This can be used only if we _already_ own a reference */
index 9dcfa9480e8436e5cebd0fe965d31d8a140f49a9..134729f34af59920d8b9ef8f372d1f6d27644436 100644 (file)
@@ -44,19 +44,8 @@ static int isa_irq = -1;
 static inline int fixup_irq(unsigned int irq)
 {
 #ifdef CONFIG_HOST_FOOTBRIDGE
-       if (irq == isa_irq) {
+       if (irq == isa_irq)
                irq = *(unsigned char *)PCIIACK_BASE;
-
-               /*
-                * The NetWinder appears to randomly give wrong interrupt
-                * numbers from time to time.  When it does, map them to
-                * the unused IRQ 13
-                */
-               if (irq >= NR_IRQS) {
-                       printk(KERN_ERR "Strange interrupt %d?\n", irq);
-                       irq = _ISA_IRQ(13);
-               }
-       }
 #endif
 
        return irq;
diff --git a/include/asm-arm/arch-l7200/dma.h b/include/asm-arm/arch-l7200/dma.h
new file mode 100644 (file)
index 0000000..be68279
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
+ */
+#define MAX_DMA_ADDRESS                0xd0000000
+#define MAX_DMA_CHANNELS       8
+
+#define DMA_0                  0
+#define DMA_1                  1
+#define DMA_2                  2
+#define DMA_3                  3
+#define DMA_S0                 4
+#define DMA_S1                 5
+#define DMA_VIRTUAL_FLOPPY     6
+#define DMA_VIRTUAL_SOUND      7
+
+#define DMA_FLOPPY             DMA_VIRTUAL_FLOPPY
+
+#endif
diff --git a/include/asm-arm/arch-l7200/hardware.h b/include/asm-arm/arch-l7200/hardware.h
new file mode 100644 (file)
index 0000000..d800cbc
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * linux/include/asm-arm/arch-l7200/hardware.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * This file contains the hardware definitions for the 
+ * LinkUp Systems L7200 SOC development board.
+ *
+ * Changelog:
+ *   02-01-2000         RS     Created L7200 version, derived from rpc code
+ *   03-21-2000        SJH     Cleaned up file
+ *   04-21-2000         RS     Changed mapping of I/O in virtual space
+ *   04-25-2000        SJH     Removed unused symbols and such
+ *   05-05-2000        SJH     Complete rewrite
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/* Hardware addresses of major areas.
+ *  *_START is the physical address
+ *  *_SIZE  is the size of the region
+ *  *_BASE  is the virtual address
+ */
+#define RAM_START              0xf0000000
+#define RAM_SIZE               0x02000000
+#define RAM_BASE               0xc0000000
+
+#define IO_START               0x80000000      /* I/O */
+#define IO_SIZE                        0x01000000
+#define IO_BASE                        0xd0000000
+
+#define IO_START_2             0x90000000      /* I/O */
+#define IO_SIZE_2              0x01000000
+#define IO_BASE_2              0xd1000000
+
+#define ISA_START              0x20000000      /* ISA */
+#define ISA_SIZE               0x20000000
+#define ISA_BASE               0xe0000000
+
+#define FLUSH_BASE_PHYS                0x40000000      /* ROM */
+#define FLUSH_BASE             0xdf000000
+
+#define PARAMS_BASE            (PAGE_OFFSET + 0x0100)
+#define Z_PARAMS_BASE          (RAM_START + PARAMS_OFFSET)
+
+#define PCIO_BASE              IO_BASE
+
+#endif
diff --git a/include/asm-arm/arch-l7200/ide.h b/include/asm-arm/arch-l7200/ide.h
new file mode 100644 (file)
index 0000000..0cfcf3a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * linux/include/asm-arm/arch-l7200/ide.h
+ *
+ * Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *  29-03-2000 SJH     Created file placeholder
+ */
+#include <asm/irq.h>
+
+/*
+ * 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)
+{
+}
+
+/*
+ * This registers the standard ports for this architecture with the IDE
+ * driver.
+ */
+static __inline__ void
+ide_init_default_hwifs(void)
+{
+}
diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h
new file mode 100644 (file)
index 0000000..787b621
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * linux/include/asm-arm/arch-l7200/io.h
+ *
+ * Copyright (C) 2000 Steven Hill (sjhill@cotw.com)
+ *
+ * Modifications:
+ *  21-03-2000 SJH     Created from linux/include/asm-arm/arch-nexuspci/io.h
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <asm/arch/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We use two different types of addressing - PC style addresses, and ARM
+ * addresses.  PC style accesses the PC hardware with the normal PC IO
+ * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
+ * and are translated to the start of IO.  Note that all addresses are
+ * shifted left!
+ */
+#define __PORT_PCIO(x) (!((x) & 0x80000000))
+
+/*
+ * Dynamic IO functions.
+ */
+
+extern __inline__ void __outb (unsigned int value, unsigned int port)
+{
+       unsigned long temp;
+       __asm__ __volatile__(
+       "tst    %2, #0x80000000\n\t"
+       "mov    %0, %4\n\t"
+       "addeq  %0, %0, %3\n\t"
+       "strb   %1, [%0, %2, lsl #2]    @ outb"
+       : "=&r" (temp)
+       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+       : "cc");
+}
+
+extern __inline__ void __outw (unsigned int value, unsigned int port)
+{
+       unsigned long temp;
+       __asm__ __volatile__(
+       "tst    %2, #0x80000000\n\t"
+       "mov    %0, %4\n\t"
+       "addeq  %0, %0, %3\n\t"
+       "str    %1, [%0, %2, lsl #2]    @ outw"
+       : "=&r" (temp)
+       : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+       : "cc");
+}
+
+extern __inline__ void __outl (unsigned int value, unsigned int port)
+{
+       unsigned long temp;
+       __asm__ __volatile__(
+       "tst    %2, #0x80000000\n\t"
+       "mov    %0, %4\n\t"
+       "addeq  %0, %0, %3\n\t"
+       "str    %1, [%0, %2, lsl #2]    @ outl"
+       : "=&r" (temp)
+       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+       : "cc");
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr)                                      \
+extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)               \
+{                                                                              \
+       unsigned long temp, value;                                              \
+       __asm__ __volatile__(                                                   \
+       "tst    %2, #0x80000000\n\t"                                            \
+       "mov    %0, %4\n\t"                                                     \
+       "addeq  %0, %0, %3\n\t"                                                 \
+       "ldr" ##instr## "       %1, [%0, %2, lsl #2]    @ in"###fnsuffix        \
+       : "=&r" (temp), "=r" (value)                                            \
+       : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)                \
+       : "cc");                                                                \
+       return (unsigned sz)value;                                              \
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)                    \
+{                                                                              \
+       if (__PORT_PCIO(port))                                                  \
+               return (unsigned int)(PCIO_BASE + (port << 2));                 \
+       else                                                                    \
+               return (unsigned int)(IO_BASE + (port << 2));                   \
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr)  \
+       DECLARE_DYN_IN(sz,fnsuffix,instr)
+
+DECLARE_IO(char,b,"b")
+DECLARE_IO(short,w,"")
+DECLARE_IO(int,l,"")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)                                                    \
+({                                                                             \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "strb   %0, [%1, %2]    @ outbc"                                \
+               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));          \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "strb   %0, [%1, %2]    @ outbc"                                \
+               : : "r" (value), "r" (IO_BASE), "r" ((port) << 2));             \
+})
+
+#define __inbc(port)                                                           \
+({                                                                             \
+       unsigned char result;                                                   \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "ldrb   %0, [%1, %2]    @ inbc"                                 \
+               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "ldrb   %0, [%1, %2]    @ inbc"                                 \
+               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
+       result;                                                                 \
+})
+
+#define __outwc(value,port)                                                    \
+({                                                                             \
+       unsigned long v = value;                                                \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]    @ outwc"                                \
+               : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));        \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]    @ outwc"                                \
+               : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));           \
+})
+
+#define __inwc(port)                                                           \
+({                                                                             \
+       unsigned short result;                                                  \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "ldr    %0, [%1, %2]    @ inwc"                                 \
+               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "ldr    %0, [%1, %2]    @ inwc"                                 \
+               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
+       result & 0xffff;                                                        \
+})
+
+#define __outlc(value,port)                                                    \
+({                                                                             \
+       unsigned long v = value;                                                \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]    @ outlc"                                \
+               : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2));              \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "str    %0, [%1, %2]    @ outlc"                                \
+               : : "r" (v), "r" (IO_BASE), "r" ((port) << 2));                 \
+})
+
+#define __inlc(port)                                                           \
+({                                                                             \
+       unsigned long result;                                                   \
+       if (__PORT_PCIO((port)))                                                \
+               __asm__ __volatile__(                                           \
+               "ldr    %0, [%1, %2]    @ inlc"                                 \
+               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
+       else                                                                    \
+               __asm__ __volatile__(                                           \
+               "ldr    %0, [%1, %2]    @ inlc"                                 \
+               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
+       result;                                                                 \
+})
+
+#define __ioaddrc(port)                                                                \
+       (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
+
+#define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
+#define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
+#define inl(p)         (__builtin_constant_p((p)) ? __inlc(p)    : __inl(p))
+#define outb(v,p)      (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
+#define outw(v,p)      (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
+#define outl(v,p)      (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
+#define __ioaddr(p)    (__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
+
+/*
+ * Translated address IO functions
+ *
+ * IO address has already been translated to a virtual address
+ */
+#define outb_t(v,p)    (*(volatile unsigned char *)(p) = (v))
+#define inb_t(p)       (*(volatile unsigned char *)(p))
+#define outw_t(v,p)    (*(volatile unsigned int *)(p) = (v))
+#define inw_t(p)       (*(volatile unsigned int *)(p))
+#define outl_t(v,p)    (*(volatile unsigned long *)(p) = (v))
+#define inl_t(p)       (*(volatile unsigned long *)(p))
+
+#endif
diff --git a/include/asm-arm/arch-l7200/irq.h b/include/asm-arm/arch-l7200/irq.h
new file mode 100644 (file)
index 0000000..58b6166
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * include/asm-arm/arch-l7200/irq.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.ne
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *   01-02-2000        RS      Created l7200 version, derived from ebsa110 code
+ *   04-15-2000 RS      Made dependent on hardware.h
+ *   05-05-2000 SJH     Complete rewrite
+ */
+
+/*
+ * IRQ base register
+ */
+#define        IRQ_BASE        (IO_BASE_2 + 0x1000)
+
+/* 
+ * Normal IRQ registers
+ */
+#define IRQ_STATUS     (*(volatile unsigned long *) (IRQ_BASE + 0x000))
+#define IRQ_RAWSTATUS  (*(volatile unsigned long *) (IRQ_BASE + 0x004))
+#define IRQ_ENABLE     (*(volatile unsigned long *) (IRQ_BASE + 0x008))
+#define IRQ_ENABLECLEAR        (*(volatile unsigned long *) (IRQ_BASE + 0x00c))
+#define IRQ_SOFT       (*(volatile unsigned long *) (IRQ_BASE + 0x010))
+#define IRQ_SOURCESEL  (*(volatile unsigned long *) (IRQ_BASE + 0x018))
+
+/* 
+ * Fast IRQ registers
+ */
+#define FIQ_STATUS     (*(volatile unsigned long *) (IRQ_BASE + 0x100))
+#define FIQ_RAWSTATUS  (*(volatile unsigned long *) (IRQ_BASE + 0x104))
+#define FIQ_ENABLE     (*(volatile unsigned long *) (IRQ_BASE + 0x108))
+#define FIQ_ENABLECLEAR        (*(volatile unsigned long *) (IRQ_BASE + 0x10c))
+#define FIQ_SOFT       (*(volatile unsigned long *) (IRQ_BASE + 0x110))
+#define FIQ_SOURCESEL  (*(volatile unsigned long *) (IRQ_BASE + 0x118))
+
+#define fixup_irq(x) (x)
+
+static void l7200_mask_irq(unsigned int irq)
+{
+       IRQ_ENABLECLEAR = 1 << irq;
+}
+
+static void l7200_unmask_irq(unsigned int irq)
+{
+       IRQ_ENABLE = 1 << irq;
+}
+static __inline__ void irq_init_irq(void)
+{
+       int irq;
+
+       IRQ_ENABLECLEAR = 0xffffffff;   /* clear all interrupt enables */
+       FIQ_ENABLECLEAR = 0xffffffff;   /* clear all fast interrupt enables */
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               irq_desc[irq].valid     = 1;
+               irq_desc[irq].probe_ok  = 1;
+               irq_desc[irq].mask_ack  = l7200_mask_irq;
+               irq_desc[irq].mask      = l7200_mask_irq;
+               irq_desc[irq].unmask    = l7200_unmask_irq;
+       }
+
+       init_FIQ();
+}
diff --git a/include/asm-arm/arch-l7200/irqs.h b/include/asm-arm/arch-l7200/irqs.h
new file mode 100644 (file)
index 0000000..175efa1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * include/asm-arm/arch-l7200/irqs.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *   01-02-2000 RS     Create l7200 version
+ *   03-28-2000 SJH    Removed unused interrupt
+ */
+
+#define NR_IRQS          32
+
+#define IRQ_STWDOG        0   /* Watchdog timer */
+#define IRQ_PROG          1   /* Programmable interrupt */
+#define IRQ_DEBUG_RX      2   /* Comm Rx debug */
+#define IRQ_DEBUG_TX      3   /* Comm Tx debug */
+#define IRQ_GCTC1         4   /* Timer 1 */
+#define IRQ_GCTC2         5   /* Timer 2 */
+#define IRQ_DMA           6   /* DMA controller */
+#define IRQ_CLCD          7   /* Color LCD controller */
+#define IRQ_SM_RX         8   /* Smart card */
+#define IRQ_SM_TX         9   /* Smart cart */
+#define IRQ_SM_RST       10   /* Smart card */
+#define IRQ_SIB          11   /* Serial Interface Bus */
+#define IRQ_MMC          12   /* MultiMediaCard */
+#define IRQ_SSP1         13   /* Synchronous Serial Port 1 */
+#define IRQ_SSP2         14   /* Synchronous Serial Port 1 */
+#define IRQ_SPI          15   /* SPI slave */
+#define IRQ_UART_1       16   /* UART 1 */
+#define IRQ_UART_2       17   /* UART 2 */
+#define IRQ_IRDA         18   /* IRDA */
+#define IRQ_RTC_TICK     19   /* Real Time Clock tick */
+#define IRQ_RTC_ALARM    20   /* Real Time Clock alarm */
+#define IRQ_GPIO         21   /* General Purpose IO */
+#define IRQ_GPIO_DMA     22   /* General Purpose IO, DMA */
+#define IRQ_M2M          23   /* Memory to memory DMA  */
+#define IRQ_RESERVED     24   /* RESERVED, don't use */
+#define IRQ_INTF         25   /* External active low interrupt */
+#define IRQ_INT0         26   /* External active low interrupt */
+#define IRQ_INT1         27   /* External active low interrupt */
+#define IRQ_INT2         28   /* External active low interrupt */
+#define IRQ_INT3         29   /* External active low interrupt */
+#define IRQ_BAT_LO       30   /* Low batery or external power */
+#define IRQ_MEDIA_CHG    31   /* Media change interrupt */
diff --git a/include/asm-arm/arch-l7200/memory.h b/include/asm-arm/arch-l7200/memory.h
new file mode 100644 (file)
index 0000000..f2aaabd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-arm/arch-l7200/memory.h
+ *
+ * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *
+ * Changelog:
+ *  03-13-2000 SJH     Created
+ *  04-13-2000  RS      Changed bus macros for new addr
+ *  05-03-2000  SJH     Removed bus macros and fixed virt_to_phys macro
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE       (0xc0000000UL)
+#define TASK_SIZE_26    (0x04000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET     (0xc0000000UL)
+
+/*
+ * Physical DRAM offset on the L7200 SDB.
+ */
+#define PHYS_OFFSET     (0xf0000000UL)
+
+/*
+ * The DRAM is contiguous.
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/include/asm-arm/arch-l7200/param.h b/include/asm-arm/arch-l7200/param.h
new file mode 100644 (file)
index 0000000..5cd0bcc
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/include/asm-arm/arch-l7200/param.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * This file contains the hardware definitions for the
+ * LinkUp Systems L7200 SOC development board.
+ *
+ * Changelog:
+ *   04-21-2000 RS      Created L7200 version
+ *   04-25-2000 SJH     Cleaned up file
+ *   05-03-2000 SJH     Change comments and rate
+ */
+#ifndef __ASM_ARCH_PARAM_H
+#define __ASM_ARCH_PARAM_H
+
+/*
+ * See 'time.h' for how the RTC HZ rate is set
+ */
+#define HZ 128
+
+#endif
diff --git a/include/asm-arm/arch-l7200/processor.h b/include/asm-arm/arch-l7200/processor.h
new file mode 100644 (file)
index 0000000..ee4b4b2
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * linux/include/asm-arm/arch-l7200/processor.h
+ *
+ * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *  03-21-2000 SJH     Created
+ *  05-03-2000 SJH     Comment cleaning
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+#endif
diff --git a/include/asm-arm/arch-l7200/serial_l7200.h b/include/asm-arm/arch-l7200/serial_l7200.h
new file mode 100644 (file)
index 0000000..238c595
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * linux/include/asm-arm/arch-l7200/serial_l7200.h
+ *
+ * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *  05-09-2000 SJH     Created
+ */
+#ifndef __ASM_ARCH_SERIAL_L7200_H
+#define __ASM_ARCH_SERIAL_L7200_H
+
+#include <asm/arch/memory.h>
+
+/*
+ * This assumes you have a 3.6864 MHz clock for your UART.
+ */
+#define BASE_BAUD 3686400
+
+/*
+ * UART base register addresses
+ */
+#define UART1_BASE     (IO_BASE + 0x00044000)
+#define UART2_BASE     (IO_BASE + 0x00045000)
+
+/*
+ * UART register offsets
+ */
+#define UARTDR                 0x00    /* Tx/Rx data */
+#define RXSTAT                 0x04    /* Rx status */
+#define H_UBRLCR               0x08    /* mode register high */
+#define M_UBRLCR               0x0C    /* mode reg mid (MSB of buad)*/
+#define L_UBRLCR               0x10    /* mode reg low (LSB of baud)*/
+#define UARTCON                        0x14    /* control register */
+#define UARTFLG                        0x18    /* flag register */
+#define UARTINTSTAT            0x1C    /* FIFO IRQ status register */
+#define UARTINTMASK            0x20    /* FIFO IRQ mask register */
+
+/*
+ * UART baud rate register values
+ */
+#define BR_110                 0x827
+#define BR_1200                        0x06e
+#define BR_2400                        0x05f
+#define BR_4800                        0x02f
+#define BR_9600                        0x017
+#define BR_14400               0x00f
+#define BR_19200               0x00b
+#define BR_38400               0x005
+#define BR_57600               0x003
+#define BR_76800               0x002
+#define BR_115200              0x001
+
+/*
+ * Receiver status register (RXSTAT) mask values
+ */
+#define RXSTAT_NO_ERR          0x00    /* No error */
+#define RXSTAT_FRM_ERR         0x01    /* Framing error */
+#define RXSTAT_PAR_ERR         0x02    /* Parity error */
+#define RXSTAT_OVR_ERR         0x04    /* Overrun error */
+
+/*
+ * High byte of UART bit rate and line control register (H_UBRLCR) values
+ */
+#define UBRLCR_BRK             0x01    /* generate break on tx */
+#define UBRLCR_PEN             0x02    /* enable parity */
+#define UBRLCR_PDIS            0x00    /* disable parity */
+#define UBRLCR_EVEN            0x04    /* 1= even parity,0 = odd parity */
+#define UBRLCR_STP2            0x08    /* transmit 2 stop bits */
+#define UBRLCR_FIFO            0x10    /* enable FIFO */
+#define UBRLCR_LEN5            0x60    /* word length5 */
+#define UBRLCR_LEN6            0x40    /* word length6 */
+#define UBRLCR_LEN7            0x20    /* word length7 */
+#define UBRLCR_LEN8            0x00    /* word length8 */
+
+/*
+ * UART control register (UARTCON) values
+ */
+#define UARTCON_UARTEN         0x01    /* Enable UART */
+#define UARTCON_DMAONERR       0x08    /* Mask RxDmaRq when errors occur */
+
+/*
+ * UART flag register (UARTFLG) mask values
+ */
+#define UARTFLG_UTXFF          0x20    /* Transmit FIFO full */
+#define UARTFLG_URXFE          0x10    /* Receiver FIFO empty */
+#define UARTFLG_UBUSY          0x08    /* Transmitter busy */
+#define UARTFLG_DCD            0x04    /* Data carrier detect */
+#define UARTFLG_DSR            0x02    /* Data set ready */
+#define UARTFLG_CTS            0x01    /* Clear to send */
+
+/*
+ * UART interrupt status/clear registers (UARTINTSTAT/CLR) values
+ */
+#define UART_TXINT             0x01    /* TX interrupt */
+#define UART_RXINT             0x02    /* RX interrupt */
+#define UART_RXERRINT          0x04    /* RX error interrupt */
+#define UART_MSINT             0x08    /* Modem Status interrupt */
+#define UART_UDINT             0x10    /* UART Disabled interrupt */
+#define UART_ALLIRQS           0x1f    /* All interrupts */
+
+#endif
diff --git a/include/asm-arm/arch-l7200/system.h b/include/asm-arm/arch-l7200/system.h
new file mode 100644 (file)
index 0000000..c3bbe37
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * linux/include/asm-arm/arch-l7200/system.h
+ *
+ * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ *
+ * Changelog
+ *  03-21-2000  SJH    Created
+ *  04-26-2000  SJH    Fixed functions
+ *  05-03-2000  SJH    Removed usage of obsolete 'iomd.h'
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+extern __inline__ void arch_idle(void)
+{
+        while (!current->need_resched && !hlt_counter)
+               { };
+/*                outb(0, IOMD_SUSMODE);*/
+}
+
+#define arch_power_off()       do { } while (0)
+
+extern inline void arch_reset(char mode)
+{
+       if (mode == 's') {
+               cpu_reset(0);
+       }
+}
+
+#endif
diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h
new file mode 100644 (file)
index 0000000..077735e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * linux/include/asm-arm/arch-l7200/time.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *   01-02-2000        RS      Created l7200 version, derived from rpc code
+ *   05-03-2000        SJH     Complete rewrite
+ */
+#ifndef _ASM_ARCH_TIME_H
+#define _ASM_ARCH_TIME_H
+
+#include <asm/arch/irqs.h>
+
+/*
+ * RTC base register address
+ */
+#define RTC_BASE       (IO_BASE_2 + 0x2000)
+
+/*
+ * RTC registers
+ */
+#define RTC_RTCDR      (*(volatile unsigned char *) (RTC_BASE + 0x000))
+#define RTC_RTCMR      (*(volatile unsigned char *) (RTC_BASE + 0x004))
+#define RTC_RTCS       (*(volatile unsigned char *) (RTC_BASE + 0x008))
+#define RTC_RTCC       (*(volatile unsigned char *) (RTC_BASE + 0x008))
+#define RTC_RTCDV      (*(volatile unsigned char *) (RTC_BASE + 0x00c))
+#define RTC_RTCCR      (*(volatile unsigned char *) (RTC_BASE + 0x010))
+
+/*
+ * RTCCR register values
+ */
+#define RTC_RATE_32    0x00      /* 32 Hz tick */
+#define RTC_RATE_64    0x10      /* 64 Hz tick */
+#define RTC_RATE_128   0x20      /* 128 Hz tick */
+#define RTC_RATE_256   0x30      /* 256 Hz tick */
+#define RTC_EN_ALARM   0x01      /* Enable alarm */
+#define RTC_EN_TIC     0x04      /* Enable counter */
+#define RTC_EN_STWDOG  0x08      /* Enable watchdog */
+
+/*
+ * Handler for timer interrupt
+ */
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       do_timer(regs);
+       do_profile(regs);
+       RTC_RTCC = 0;                           /* Clear interrupt */
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ void setup_timer(void)
+{
+       xtime.tv_sec = RTC_RTCDR;
+
+       RTC_RTCC = 0;                           /* Clear interrupt */
+
+       timer_irq.handler = timer_interrupt;
+
+       setup_arm_irq(IRQ_RTC_TICK, &timer_irq);
+
+       RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC;  /* Set rate and enable timer */
+}
+
+#endif
diff --git a/include/asm-arm/arch-l7200/timex.h b/include/asm-arm/arch-l7200/timex.h
new file mode 100644 (file)
index 0000000..3c32026
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * linux/include/asm-arm/arch-l7200/timex.h
+ *
+ * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net)
+ *                    Steve Hill (sjhill@cotw.com)
+ *
+ * 04-21-2000  RS Created file
+ * 05-03-2000 SJH Tick rate was wrong
+ *
+ */
+
+/*
+ * On the ARM720T, clock ticks are set to 128 Hz.
+ *
+ * NOTE: The actual RTC value is set in 'time.h' which
+ *       must be changed when choosing a different tick
+ *       rate. The value of HZ in 'param.h' must also
+ *       be changed to match below.
+ */
+#define CLOCK_TICK_RATE                128
diff --git a/include/asm-arm/arch-l7200/uncompress.h b/include/asm-arm/arch-l7200/uncompress.h
new file mode 100644 (file)
index 0000000..d2e5645
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * linux/include/asm-arm/arch-l7200/uncompress.h
+ *
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ */
+
+static __inline__ void putc(char c)
+{
+}
+
+static void puts(const char *s)
+{
+}
+
+static __inline__ void arch_decomp_setup(void)
+{
+}
+
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-l7200/vmalloc.h b/include/asm-arm/arch-l7200/vmalloc.h
new file mode 100644 (file)
index 0000000..04fa07e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-l7200/vmalloc.h
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET   (8*1024*1024)
+#define VMALLOC_START    (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
index 77a36a2a480af319d1b57d6d42a100646dbe5fdf..c12ed91e31f4c313dcd605625938e4d2265f23e8 100644 (file)
@@ -5,23 +5,27 @@
 #include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
+extern unsigned int local_bh_count[NR_CPUS];
+
+#define local_irq_count(cpu)   (local_irq_count[(cpu)])
+#define local_bh_count(cpu)    (local_bh_count[(cpu)])
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
 #define in_interrupt() ({ const int __cpu = smp_processor_id(); \
-       (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+       (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
 
-#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
 
 #ifndef CONFIG_SMP
 
-#define hardirq_trylock(cpu)   (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)   (local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)   do { } while (0)
 
-#define hardirq_enter(cpu)     (local_irq_count[cpu]++)
-#define hardirq_exit(cpu)      (local_irq_count[cpu]--)
+#define irq_enter(cpu,irq)     (local_irq_count(cpu)++)
+#define irq_exit(cpu,irq)      (local_irq_count(cpu)--)
 
 #define synchronize_irq()      do { } while (0)
 
diff --git a/include/asm-arm/proc-armo/semaphore.h b/include/asm-arm/proc-armo/semaphore.h
deleted file mode 100644 (file)
index 6926fad..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/locks.h
- *
- * Copyright (C) 2000 Russell King
- *
- * Interrupt safe locking assembler.
- */
-#ifndef __ASM_PROC_LOCKS_H
-#define __ASM_PROC_LOCKS_H
-
-#define __down_op(ptr,fail)                    \
-       ({                                      \
-       __asm__ __volatile__ (                  \
-       "@ atomic down operation\n"             \
-"      mov     r0, pc\n"                       \
-"      orr     lr, r0, #0x08000000\n"          \
-"      teqp    lr, #0\n"                       \
-"      ldr     lr, [%0]\n"                     \
-"      and     r0, r0, #0x0c000003\n"          \
-"      subs    lr, lr, #1\n"                   \
-"      str     lr, [%0]\n"                     \
-"      orrmi   r0, r0, #0x80000000     @ set N\n" \
-"      teqp    r0, #0\n"                       \
-"      movmi   r0, %0\n"                       \
-       blmi    " SYMBOL_NAME_STR(fail)         \
-       :                                       \
-       : "r" (ptr)                             \
-       : "r0", "lr", "cc");                    \
-       })
-
-#define __down_op_ret(ptr,fail)                        \
-       ({                                      \
-               unsigned int result;            \
-       __asm__ __volatile__ (                  \
-"      @ down_op_ret\n"                        \
-"      mov     r0, pc\n"                       \
-"      orr     lr, r0, #0x08000000\n"          \
-"      teqp    lr, #0\n"                       \
-"      ldr     lr, [%1]\m"                     \
-"      and     r0, r0, #0x0c000003\n"          \
-"      subs    lr, lr, #1\n"                   \
-"      str     lr, [%1]\n"                     \
-"      orrmi   r0, r0, #0x80000000     @ set N\n" \
-"      teqp    r0, #0\n"                       \
-"      movmi   r0, %1\n"                       \
-"      movpl   r0, #0\n"                       \
-"      blmi    " SYMBOL_NAME_STR(fail) "\n"    \
-"      mov     %0, r0"                         \
-       : "=&r" (result)                        \
-       : "r" (ptr)                             \
-       : "r0", "lr", "cc");                    \
-       result;                                 \
-       })
-
-#define __up_op(ptr,wake)                      \
-       ({                                      \
-       __asm__ __volatile__ (                  \
-       "@ up_op\n"                             \
-       mov     r0, pc\n"                       \
-       orr     lr, r0, #0x08000000\n"          \
-       teqp    lr, #0\n"                       \
-       ldr     lr, [%0]\n"                     \
-       and     r0, r0, #0x0c000003\n"          \
-       adds    lr, lr, #1\n"                   \
-       str     lr, [%0]\n"                     \
-       orrle   r0, r0, #0x80000000     @ set N\n" \
-       teqp    r0, #0\n"                       \
-       movmi   r0, %0\n"                       \
-       blmi    " SYMBOL_NAME_STR(wake)         \
-       :                                       \
-       : "r" (ptr)                             \
-       : "r0", "lr", "cc");                    \
-       })
-
-#endif
index c1cfded3e4d836227c6706448ef852c81a79d3b6..0a0391faee7ea895f330a0e72cf129cd5228f327 100644 (file)
        ({                                      \
        __asm__ __volatile__(                   \
        "@ down_op\n"                           \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%0]\n"                     \
 "      subs    lr, lr, %1\n"                   \
 "      str     lr, [%0]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      movmi   r0, %0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      movmi   ip, %0\n"                       \
 "      blmi    " SYMBOL_NAME_STR(fail)         \
        :                                       \
        : "r" (ptr), "I" (1)                    \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        })
 
 #define __down_op_ret(ptr,fail)                        \
                unsigned int ret;               \
        __asm__ __volatile__(                   \
        "@ down_op_ret\n"                       \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%1]\n"                     \
 "      subs    lr, lr, %2\n"                   \
 "      str     lr, [%1]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      movmi   r0, %1\n"                       \
-"      movpl   r0, #0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      movmi   ip, %1\n"                       \
+"      movpl   ip, #0\n"                       \
 "      blmi    " SYMBOL_NAME_STR(fail) "\n"    \
-"      mov     %0, r0"                         \
+"      mov     %0, ip"                         \
        : "=&r" (ret)                           \
        : "r" (ptr), "I" (1)                    \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        ret;                                    \
        })
 
        ({                                      \
        __asm__ __volatile__(                   \
        "@ up_op\n"                             \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%0]\n"                     \
 "      adds    lr, lr, %1\n"                   \
 "      str     lr, [%0]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      movle   r0, %0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      movle   ip, %0\n"                       \
 "      blle    " SYMBOL_NAME_STR(wake)         \
        :                                       \
        : "r" (ptr), "I" (1)                    \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        })
 
 /*
        ({                                      \
        __asm__ __volatile__(                   \
        "@ down_op_write\n"                     \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%0]\n"                     \
 "      subs    lr, lr, %1\n"                   \
 "      str     lr, [%0]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      movne   r0, %0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      movne   ip, %0\n"                       \
 "      blne    " SYMBOL_NAME_STR(fail)         \
        :                                       \
        : "r" (ptr), "I" (RW_LOCK_BIAS)         \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        })
 
 #define __up_op_write(ptr,wake)                        \
        ({                                      \
        __asm__ __volatile__(                   \
        "@ up_op_read\n"                        \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%0]\n"                     \
 "      adds    lr, lr, %1\n"                   \
 "      str     lr, [%0]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      movcs   r0, %0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      movcs   ip, %0\n"                       \
 "      blcs    " SYMBOL_NAME_STR(wake)         \
        :                                       \
        : "r" (ptr), "I" (RW_LOCK_BIAS)         \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        })
 
 #define __down_op_read(ptr,fail)               \
        ({                                      \
        __asm__ __volatile__(                   \
        "@ up_op_read\n"                        \
-"      mrs     r0, cpsr\n"                     \
-"      orr     lr, r0, #128\n"                 \
+"      mrs     ip, cpsr\n"                     \
+"      orr     lr, ip, #128\n"                 \
 "      msr     cpsr_c, lr\n"                   \
 "      ldr     lr, [%0]\n"                     \
 "      adds    lr, lr, %1\n"                   \
 "      str     lr, [%0]\n"                     \
-"      msr     cpsr_c, r0\n"                   \
-"      moveq   r0, %0\n"                       \
+"      msr     cpsr_c, ip\n"                   \
+"      moveq   ip, %0\n"                       \
 "      bleq    " SYMBOL_NAME_STR(wake)         \
        :                                       \
        : "r" (ptr), "I" (1)                    \
-       : "r0", "lr", "cc");                    \
+       : "ip", "lr", "cc");                    \
        })
 
 #endif
index f987548131379663997e7addcf2f2a7fab38a4e1..01e0d73d1062fb748b852b04e5f68b2251f0a938 100644 (file)
@@ -4,14 +4,12 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int local_bh_count[NR_CPUS];
-
-#define cpu_bh_disable(cpu)    do { local_bh_count[(cpu)]++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count[(cpu)]--; } while (0)
+#define cpu_bh_disable(cpu)    do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count(cpu)--; } while (0)
 
 #define local_bh_disable()     cpu_bh_disable(smp_processor_id())
 #define local_bh_enable()      cpu_bh_enable(smp_processor_id())
 
-#define in_softirq()           (local_bh_count[smp_processor_id()] != 0)
+#define in_softirq()           (local_bh_count(smp_processor_id()) != 0)
 
 #endif /* __ASM_SOFTIRQ_H */
index dfe4cd9aca1e460c4ecec4b6bde68941b09c5def..2a8ab162412fe70a9b78ab65cee951edd918e3fe 100644 (file)
@@ -13,12 +13,17 @@ extern char * strrchr(const char * s, int c);
 extern char * strchr(const char * s, int c);
 
 #define __HAVE_ARCH_MEMCPY
+extern void * memcpy(void *, const void *, __kernel_size_t);
+
 #define __HAVE_ARCH_MEMMOVE
+extern void * memmove(void *, const void *, __kernel_size_t);
+
 #define __HAVE_ARCH_MEMCHR
-extern void * memchr(const void *cs, int c, size_t count);
+extern void * memchr(const void *, int, __kernel_size_t);
 
 #define __HAVE_ARCH_MEMZERO
 #define __HAVE_ARCH_MEMSET
+extern void * memset(void *, int, __kernel_size_t);
 
 extern void __memzero(void *ptr, __kernel_size_t n);
 
@@ -36,4 +41,3 @@ extern void __memzero(void *ptr, __kernel_size_t n);
 #define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); })
 
 #endif
index ca6da3e13207e783202643007899d91d266d2ce4..9755af1ab0e533e2888c90a3415e1e7ed5c81304 100644 (file)
@@ -65,7 +65,7 @@
 #define __NR_mpx                       (__NR_SYSCALL_BASE+ 56)
 #define __NR_setpgid                   (__NR_SYSCALL_BASE+ 57)
 #define __NR_ulimit                    (__NR_SYSCALL_BASE+ 58)
-#define __NR_oldolduname               (__NR_SYSCALL_BASE+ 59)
+
 #define __NR_umask                     (__NR_SYSCALL_BASE+ 60)
 #define __NR_chroot                    (__NR_SYSCALL_BASE+ 61)
 #define __NR_ustat                     (__NR_SYSCALL_BASE+ 62)
 #define __NR_stat                      (__NR_SYSCALL_BASE+106)
 #define __NR_lstat                     (__NR_SYSCALL_BASE+107)
 #define __NR_fstat                     (__NR_SYSCALL_BASE+108)
-#define __NR_olduname                  (__NR_SYSCALL_BASE+109)
+
 #define __NR_iopl                      (__NR_SYSCALL_BASE+110)
 #define __NR_vhangup                   (__NR_SYSCALL_BASE+111)
 #define __NR_idle                      (__NR_SYSCALL_BASE+112)
index a7fa5e56f26145c93def41f7e75d76954c97e855..98fe1ec3d286e6fbc88b1061388a90157774e29c 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <linux/config.h>
 
-#include <linux/config.h>
-
 extern __inline__ void
 __delay(unsigned long loops)
 {
index 59d6681dec7bca59e216db1a1ee0ac3700443718..cba4ccf0dcf830d120df9d890b8de432e62197e0 100644 (file)
@@ -10,8 +10,6 @@
 #ifndef _ASM_HARDIRQ_H
 #define _ASM_HARDIRQ_H
 
-#include <linux/config.h>
-
 #include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/irq.h>
index a91913bcc72b1daa2141ccf2cfaefd6d23ea1a8a..c9600661eb902e0bfad4439cf187bad7eac5c16b 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <linux/config.h>
 
-#include <linux/config.h>
-
 /* TLB flushing:
  *
  *  - flush_tlb_all() flushes all processes TLB entries
index ab996d0b292c6adf9c4ea1bfb618c3b5cc314569..d6fb7526dffa2c19ddd211fa616605e2b187ad68 100644 (file)
@@ -16,8 +16,6 @@
 
 #include <asm/isadep.h>
 
-#include <linux/config.h>
-
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
index 4c05d3cc146d8d9f890c89f71a11efd53ae872de..2913275ab688d411b3b2cabcbb3979b7e5b4007f 100644 (file)
@@ -13,8 +13,6 @@
 
 #include <linux/config.h>
 
-#include <linux/config.h>
-
 extern __inline__ void
 __delay(unsigned long loops)
 {
index df2f47f6c425e815c5a7430398b850c9e3574c28..e1caa024a71c768375f21a337ba7ce81ccd767ca 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#include <linux/config.h>
 #include <asm/io.h>                    /* need byte IO */
 #include <linux/spinlock.h>            /* And spinlocks */
 #include <linux/delay.h>
index 4db514c487d2ca9a0e65c69ce8522ac965e9a698..74d3e29982e4df3fcb6665ba5990c7486f57d668 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <linux/config.h>
 
-#include <linux/config.h>
-
 /* TLB flushing:
  *
  *  - flush_tlb_all() flushes all processes TLB entries
index 7245e27b08886e4c1079f59d7ba765677e6de28a..1932672e7c8aa85f2a295aa15e8e6fe4a7702abf 100644 (file)
@@ -20,7 +20,6 @@
  */
 #define current_text_addr() ({ __label__ _l; _l: &&_l;})
 
-#include <linux/config.h>
 #if !defined (_LANGUAGE_ASSEMBLY)
 #include <asm/cachectl.h>
 #include <asm/mipsregs.h>
index 225adb30c932c6415406df4e0667ab51e30793ce..706d8fbd104aaf6312126ce9e6d5375c2de356f2 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef _ASM_SN_ADDRS_H
 #define _ASM_SN_ADDRS_H
 
+#include <linux/config.h>
 #if _LANGUAGE_C
 #include <linux/types.h>
 #endif /* _LANGUAGE_C */
index f9115805ef69261e1a2bca9dce5d130f0aa3bf98..76004336a241537c15daf221dc8d9cc7486bcab7 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _ASM_SGI_SN_AGENT_H
 #define _ASM_SGI_SN_AGENT_H
 
+#include <linux/config.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 //#include <asm/sn/io.h>
index 33a8f2202ff86818fe41c5ec500abb1c5f0ba3f4..79f4020c0ea1d63d3ef201ec24e0b4dc5ae012a9 100644 (file)
@@ -1,17 +1,12 @@
-/**************************************************************************
- *                                                                        *
- *               Copyright (C) 1992-1997, Silicon Graphics, Inc.          *
- *                                                                        *
- *  These coded instructions, statements, and computer programs  contain  *
- *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
- *  are protected by Federal copyright law.  They  may  not be disclosed  *
- *  to  third  parties  or copied or duplicated in any form, in whole or  *
- *  in part, without the prior written consent of Silicon Graphics, Inc.  *
- *                                                                        *
- **************************************************************************/
-
-#ifndef __SYS_SN_INTR_H__
-#define __SYS_SN_INTR_H__
+/*
+ * 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.
+ *
+ * Copyright (C) 1992 - 1997 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_SN_INTR_H
+#define __ASM_SN_INTR_H
 
 /* Number of interrupt levels associated with each interrupt register. */
 #define N_INTPEND_BITS         64
 #define NI_BRDCAST_ERR_B 40
 #define NI_BRDCAST_ERR_A 39
 
-#endif /* __SYS_SN_INTR_H__ */
+#endif /* __ASM_SN_INTR_H */
index 63d3e6ebc1802d604ee459b42dd9c0a4d0e531d4..a22b0a4bfad655d9200869c43d2e674d7e9fe409 100644 (file)
@@ -1,17 +1,12 @@
-/**************************************************************************
- *                                                                        *
- *               Copyright (C) 1992-1997, Silicon Graphics, Inc.          *
- *                                                                        *
- *  These coded instructions, statements, and computer programs  contain  *
- *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
- *  are protected by Federal copyright law.  They  may  not be disclosed  *
- *  to  third  parties  or copied or duplicated in any form, in whole or  *
- *  in part, without the prior written consent of Silicon Graphics, Inc.  *
- *                                                                        *
- **************************************************************************/
-
-#ifndef __SYS_SN_INTR_PUBLIC_H__
-#define __SYS_SN_INTR_PUBLIC_H__
+/* 
+ * 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.
+ *
+ * Copyright (C) 1992 - 1997 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_SN_INTR_PUBLIC_H
+#define __ASM_SN_INTR_PUBLIC_H
 
 
 /* REMEMBER: If you change these, the whole world needs to be recompiled.
@@ -55,5 +50,4 @@ typedef struct hub_intmasks_s {
 } hub_intmasks_t;
 
 #endif /* _LANGUAGE_C */
-#endif /* __SYS_SN_INTR_PUBLIC_H__ */
-
+#endif /* __ASM_SN_INTR_PUBLIC_H */
index 4c95ae1d86f2bc4d7828072008b04b7193f92787..b0f7a215193cbb326f5b07e93a031e8e239a5f1d 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef _ASM_SN_IO_H
 #define _ASM_SN_IO_H
 
+#include <linux/config.h>
 #if !defined(CONFIG_SGI_IO)
 #include <asm/sn/sn0/addrs.h>
 
index 46433db7f04e7c35cb9a3b5d2f85096e1b12ab89..3f042a9830c3c553f4aac9a0763f85f891c0ad7a 100644 (file)
  *      that offsets of existing fields do not change.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/types.h>
+#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35)
+#include <asm/sn/agent.h>
+#include <asm/arc/types.h>
+#include <asm/arc/hinv.h>
+#endif /* !CONFIG_SGI_IP27 || !CONFIG_SGI_IP35 */
 #if defined(CONFIG_SGI_IP27)
 #include <asm/sn/sn0/addrs.h>
 //#include <sys/SN/router.h>
 // XXX Stolen from <sys/SN/router.h>:
 #define MAX_ROUTER_PORTS (6)    /* Max. number of ports on a router */
 #include <asm/sn/sn0/sn0_fru.h>
-#include <asm/sn/agent.h>
 //#include <sys/graph.h>
-#include <asm/arc/types.h>
-#include <asm/arc/hinv.h>
 //#include <sys/xtalk/xbow.h>
-#if defined(CONFIG_SGI_IO)
-// The hack file has to be before vector and after sn0_fru....
-#include <asm/hack.h>
-#include <asm/sn/vector.h>
-#include <asm/xtalk/xtalk.h>
-#endif  /* CONFIG_SGI_IO */
 #elif defined(CONFIG_SGI_IP35)
-#include <asm/hack.h>
 #include <asm/sn/sn1/addrs.h>
-#include <asm/sn/vector.h>
 #include <sys/sn/router.h>
-#include <asm/sn/agent.h>
 #include <sys/graph.h>
-#include <asm/arc/types.h>
-#include <asm/arc/hinv.h>
 #include <asm/xtalk/xbow.h>
-#include <asm/xtalk/xtalk.h>
 #endif  /* !CONFIG_SGI_IP27 && !CONFIG_SGI_IP35 */
+#if (defined(CONFIG_SGI_IP27) && defined(CONFIG_SGI_IO)) || \
+     defined(CONFIG_SGI_IP35)
+// The hack file has to be before vector and after sn0_fru....
+#include <asm/hack.h>
+#include <asm/sn/vector.h>
+#include <asm/xtalk/xtalk.h>
+#endif  /* !(CONFIG_SGI_IP27 && CONFIG_SGI_IO) || !CONFIG_SGI_IP35 */
 
 #define KLCFGINFO_MAGIC        0xbeedbabe
 
index 67d650905e25768093f09f3b99ac2a3528abe565..3ca24005693a899f9e0b31d6730838557296dfc7 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _ASM_SN_KLDIR_H
 #define _ASM_SN_KLDIR_H
 
+#include <linux/config.h>
 #if defined(CONFIG_SGI_IO)
 #include <asm/hack.h>
 #endif
index 580cde744e90e4c47c9415c041efbfa7010450f0..b1ea725e068a2c15a3eb23cafdec93750749a1df 100644 (file)
@@ -1,17 +1,12 @@
-/**************************************************************************
- *                                                                        *
- *               Copyright (C) 1992-1997, Silicon Graphics, Inc.          *
- *                                                                        *
- *  These coded instructions, statements, and computer programs  contain  *
- *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
- *  are protected by Federal copyright law.  They  may  not be disclosed  *
- *  to  third  parties  or copied or duplicated in any form, in whole or  *
- *  in part, without the prior written consent of Silicon Graphics, Inc.  *
- *                                                                        *
- **************************************************************************/
-
-#ifndef __SYS_SN_NMI_H__
-#define __SYS_SN_NMI_H__
+/* 
+ * 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.
+ *
+ * Copyright (C) 1992 - 1997 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_SN_NMI_H
+#define __ASM_SN_NMI_H
 
 #ident "$Revision: 1.1 $"
 
@@ -127,5 +122,4 @@ struct reg_struct {
 #define CACHE_ERR_OFF  0x128
 #define NMISR_OFF      0x130
 
-
-#endif /* __SYS_SN_NMI_H__ */
+#endif /* __ASM_SN_NMI_H */
index d5506a3480d301a34b3976d4c7cb7559d3ac9b50..8fea036b99c96ba66eefc9ae2bc8848fc9f7bb41 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef _PPC_BITOPS_H
 #define _PPC_BITOPS_H
 
-#include <linux/config.h>
-#include <asm/system.h>
 #include <asm/byteorder.h>
 
 extern void set_bit(int nr, volatile void *addr);
@@ -278,3 +276,4 @@ found_middle:
 #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
 
 #endif /* _PPC_BITOPS_H */
+
index c479f87d2026cd6caa522161ce028ef49110fa8c..5f500d5c3338d4835c68741a0a8134a539992279 100644 (file)
@@ -124,6 +124,14 @@ typedef struct cpm_buf_desc {
 #define BD_SC_OV       ((ushort)0x0002)        /* Overrun */
 #define BD_SC_CD       ((ushort)0x0001)        /* ?? */
 
+/* Function code bits, usually generic to devices.
+*/
+#define CPMFCR_GBL     ((u_char)0x20)  /* Set memory snooping */
+#define CPMFCR_EB      ((u_char)0x10)  /* Set big endian byte order */
+#define CPMFCR_TC2     ((u_char)0x04)  /* Transfer code 2 value */
+#define CPMFCR_DTB     ((u_char)0x02)  /* Use local bus for data when set */
+#define CPMFCR_BDB     ((u_char)0x01)  /* Use local bus for BD when set */
+
 /* Parameter RAM offsets from the base.
 */
 #define PROFF_SCC1             ((uint)0x8000)
@@ -184,13 +192,6 @@ typedef struct smc_uart {
        uint    smc_stmp;       /* SDMA Temp */
 } smc_uart_t;
 
-/* Function code bits.
-*/
-#define SMC_GBL        ((u_char)0x20)  /* Set memory snooping */
-#define SMC_EB ((u_char)0x10)  /* Set big endian byte order */
-#define SMC_TC2        ((u_char)0x04)  /* Transfer code 2 value */
-#define SMC_DTB        ((u_char)0x02)  /* Use local bus when set */
-
 /* SMC uart mode register (Internal memory map).
 */
 #define        SMCMR_REN       ((ushort)0x0001)
@@ -337,10 +338,6 @@ typedef struct scc_param {
        uint    scc_tcrc;       /* Internal */
 } sccp_t;
 
-/* Function code bits.
-*/
-#define SCC_EB ((u_char)0x10)  /* Set big endian byte order */
-
 /* CPM Ethernet through SCC1.
  */
 typedef struct scc_enet {
index 106e57c1af5f9327ba28159d588a21dbf94efad8..a25f6015e9eabec860dfd32483ae27e8c5ab173d 100644 (file)
        __argprep __prep; \
        __argprep
 
+#define __chrp __attribute__ ((__section__ (".text.chrp")))
+#define __chrpdata __attribute__ ((__section__ (".data.chrp")))
+#define __chrpfunc(__argchrp) \
+       __argchrp __chrp; \
+       __argchrp
+
 #define __apus __attribute__ ((__section__ (".text.apus")))
 #define __apusdata __attribute__ ((__section__ (".data.apus")))
 #define __apusfunc(__argapus) \
index e069f8b152b0220929b678d29cb62235cb70f5a7..a4f6b0a4bfb92f1e75aa2b79b25c39cdd4291d92 100644 (file)
@@ -1,4 +1,7 @@
 #include <linux/config.h>
+#ifndef __ASSEMBLY__
+#include <asm/system.h> /* for xmon definition */
+#endif /* ndef __ASSEMBLY__ */
 
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
index e0158a215ad7e5a815b7869a2a371f986f8877ee..d912a6b5fed2649156f0658a7e8d1a500f8dc550 100644 (file)
 
 extern int strcasecmp(const char *, const char *);
 extern int strncasecmp(const char *, const char *, int);
+extern char * strcpy(char *,const char *);
+extern char * strncpy(char *,const char *, __kernel_size_t);
+extern __kernel_size_t strlen(const char *);
+extern int strcmp(const char *,const char *);
+extern char * strcat(char *, const char *);
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
+extern void * memchr(const void *,int,__kernel_size_t);
 
 #endif
index e28f6bfff8b75377a52a2888c84adbaaad30f46e..84a7a01f489c96e7dd354f19da11dec22067b0aa 100644 (file)
@@ -181,6 +181,8 @@ struct hd_geometry {
 #define HDIO_GET_DMA           0x030b  /* get use-dma flag */
 #define HDIO_GET_NICE          0x030c  /* get nice flags */
 #define HDIO_GET_IDENTITY      0x030d  /* get IDE identification info */
+#define HDIO_DRIVE_CMD_AEB     0x031e
+#define HDIO_DRIVE_TASK                0x031e
 #define HDIO_DRIVE_CMD         0x031f  /* execute a special drive command */
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
@@ -207,7 +209,6 @@ struct hd_big_geometry {
 #define HDIO_GETGEO_BIG                0x0330  /* */
 #define HDIO_GETGEO_BIG_RAW    0x0331  /* */
 
-
 #define __NEW_HD_DRIVE_ID
 /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
 struct hd_driveid {
@@ -272,7 +273,7 @@ struct hd_driveid {
        unsigned short  CurAPMvalues;   /* current APM values */
        unsigned short  word92;         /* reserved (word 92) */
        unsigned short  hw_config;      /* hardware config */
-       unsigned short  words94_125[31];/* reserved words 94-125 */
+       unsigned short  words94_125[32];/* reserved words 94-125 */
        unsigned short  last_lun;       /* reserved (word 126) */
        unsigned short  word127;        /* reserved (word 127) */
        unsigned short  dlf;            /* device lock function
@@ -293,8 +294,10 @@ struct hd_driveid {
                                         * 1    read-look-ahead
                                         * 0    write cache
                                         */
-       unsigned short  words130_159[30];/* reserved vendor words 130-159 */
-       unsigned short  words160_255[96];/* reserved words 160-255 */
+       unsigned short  words130_155[26];/* reserved vendor words 130-155 */
+       unsigned short  word156;
+       unsigned short  words157_159[3];/* reserved vendor words 157-159 */
+       unsigned short  words160_255[95];/* reserved words 160-255 */
 };
 
 /*
index 509b591d283543587f662b3135fb016fb01efcbb..7974a47fe58257d2fb3308443f025f1413383bbf 100644 (file)
 #ifndef _LINUX_HDSMART_H
 #define _LINUX_HDSMART_H
 
+#define OFFLINE_FULL_SCAN              0
+#define SHORT_SELF_TEST                        1
+#define EXTEND_SELF_TEST               2
+#define SHORT_CAPTIVE_SELF_TEST                129
+#define EXTEND_CAPTIVE_SELF_TEST       130
+
 /* smart_attribute is the vendor specific in SFF-8035 spec */
-struct ata_smart_attribute {
-       unsigned char                           id;
-       unsigned short                          status_flag;
-       unsigned char                           normalized;
-       unsigned char                           worse_normal;
-       unsigned char                           raw[6];
-       unsigned char                           reserv;
-} __attribute__ ((packed));
+typedef struct ata_smart_attribute_s {
+       unsigned char                   id;
+       unsigned short                  status_flag;
+       unsigned char                   normalized;
+       unsigned char                   worse_normal;
+       unsigned char                   raw[6];
+       unsigned char                   reserv;
+} __attribute__ ((packed)) ata_smart_attribute_t;
 
 /* smart_values is format of the read drive Atrribute command */
-struct ata_smart_values {
-       unsigned short                          revnumber;
-       struct ata_smart_attribute              vendor_attributes [30];
-        unsigned char                          offline_data_collection_status;
-        unsigned char                          self_test_exec_status;
-       unsigned short                          total_time_to_complete_off_line;
-       unsigned char                           vendor_specific_366;
-       unsigned char                           offline_data_collection_capability;
-       unsigned short                          smart_capability;
-       unsigned char                           errorlog_capability;
-       unsigned char                           vendor_specific_371;
-       unsigned char                           short_test_completion_time;
-       unsigned char                           extend_test_completion_time;
-       unsigned char                           reserved_374_385 [12];
-       unsigned char                           vendor_specific_386_509 [125];
-       unsigned char                           chksum;
-} __attribute__ ((packed));
+typedef struct ata_smart_values_s {
+       unsigned short                  revnumber;
+       ata_smart_attribute_t           vendor_attributes [30];
+        unsigned char                  offline_data_collection_status;
+        unsigned char                  self_test_exec_status;
+       unsigned short                  total_time_to_complete_off_line;
+       unsigned char                   vendor_specific_366;
+       unsigned char                   offline_data_collection_capability;
+       unsigned short                  smart_capability;
+       unsigned char                   errorlog_capability;
+       unsigned char                   vendor_specific_371;
+       unsigned char                   short_test_completion_time;
+       unsigned char                   extend_test_completion_time;
+       unsigned char                   reserved_374_385 [12];
+       unsigned char                   vendor_specific_386_509 [125];
+       unsigned char                   chksum;
+} __attribute__ ((packed)) ata_smart_values_t;
 
 /* Smart Threshold data structures */
 /* Vendor attribute of SMART Threshold */
-struct ata_smart_threshold_entry {
-       unsigned char                           id;
-       unsigned char                           normalized_threshold;
-       unsigned char                           reserved[10];
-} __attribute__ ((packed));
+typedef struct ata_smart_threshold_entry_s {
+       unsigned char                   id;
+       unsigned char                   normalized_threshold;
+       unsigned char                   reserved[10];
+} __attribute__ ((packed)) ata_smart_threshold_entry_t;
 
 /* Format of Read SMART THreshold Command */
-struct ata_smart_thresholds {
-       unsigned short                          revnumber;
-       struct ata_smart_threshold_entry        thres_entries[30];
-       unsigned char                           reserved[149];
-       unsigned char                           chksum;
-} __attribute__ ((packed));
-
-struct ata_smart_errorlog_command_struct {
-       unsigned char                           devicecontrolreg;
-       unsigned char                           featuresreg;
-       unsigned char                           sector_count;
-       unsigned char                           sector_number;
-       unsigned char                           cylinder_low;
-       unsigned char                           cylinder_high;
-       unsigned char                           drive_head;
-       unsigned char                           commandreg;
-       unsigned int                            timestamp;
-} __attribute__ ((packed));
-
-struct ata_smart_errorlog_error_struct {
-       unsigned char                           error_condition;
-       unsigned char                           extended_error[14];
-       unsigned char                           state;
-       unsigned short                          timestamp;
-} __attribute__ ((packed));
-
-struct ata_smart_errorlog_struct {
-       struct ata_smart_errorlog_command_struct        commands[6];
-       struct ata_smart_errorlog_error_struct          error_struct;
-}  __attribute__ ((packed));
-
-struct ata_smart_errorlog {
-       unsigned char                           revnumber;
-       unsigned char                           error_log_pointer;
-       struct ata_smart_errorlog_struct        errorlog_struct[5];
-       unsigned short                          ata_error_count;
-       unsigned short                          non_fatal_count;
-       unsigned short                          drive_timeout_count;
-       unsigned char                           reserved[53];
-} __attribute__ ((packed));
-
-struct ata_smart_selftestlog_struct {
-       unsigned char                           selftestnumber;
-       unsigned char                           selfteststatus;
-       unsigned short                          timestamp;
-       unsigned char                           selftestfailurecheckpoint;
-       unsigned int                            lbafirstfailure;
-       unsigned char                           vendorspecific[15];
-} __attribute__ ((packed));
-
-struct ata_smart_selftestlog {
-       unsigned short                          revnumber;
-       struct ata_smart_selftestlog_struct     selftest_struct[21];
-       unsigned char                           vendorspecific[2];
-       unsigned char                           mostrecenttest;
-       unsigned char                           resevered[2];
-       unsigned char                           chksum;
-} __attribute__ ((packed));
-
-#if !defined(__KERNEL__) || defined(_IDE_DISK_C)
-/* smartctl version number */
-#define VERSION_MAJOR                          1
-#define VERSION_MINOR                          2
-
-/* Number of ata device to scan */
-int numdevices;
-
-/* how often SMART is checks in seconds */
-int checktime = 1800;
-
-typedef struct atadevices_s {
-       int                                     fd;
-       char                                    devicename[14];
-       int                                     selftest;
-       struct hd_driveid                       drive;
-       struct ata_smart_values                 smartval;
-       struct ata_smart_thresholds             smartthres;
-} atadevices_t;
-
-#endif /* !defined(__KERNEL__) || defined(_IDE_DISK_C) */
+typedef struct ata_smart_thresholds_s {
+       unsigned short                  revnumber;
+       ata_smart_threshold_entry_t     thres_entries[30];
+       unsigned char                   reserved[149];
+       unsigned char                   chksum;
+} __attribute__ ((packed)) ata_smart_thresholds_t;
+
+typedef struct ata_smart_errorlog_command_struct_s {
+       unsigned char                   devicecontrolreg;
+       unsigned char                   featuresreg;
+       unsigned char                   sector_count;
+       unsigned char                   sector_number;
+       unsigned char                   cylinder_low;
+       unsigned char                   cylinder_high;
+       unsigned char                   drive_head;
+       unsigned char                   commandreg;
+       unsigned int                    timestamp;
+} __attribute__ ((packed)) ata_smart_errorlog_command_struct_t;
+
+typedef struct ata_smart_errorlog_error_struct_s {
+       unsigned char                   error_condition;
+       unsigned char                   extended_error[14];
+       unsigned char                   state;
+       unsigned short                  timestamp;
+} __attribute__ ((packed)) ata_smart_errorlog_error_struct_t;
+
+typedef struct ata_smart_errorlog_struct_s {
+       ata_smart_errorlog_command_struct_t     commands[6];
+       ata_smart_errorlog_error_struct_t       error_struct;
+} __attribute__ ((packed)) ata_smart_errorlog_struct_t;
+
+typedef struct ata_smart_errorlog_s {
+       unsigned char                   revnumber;
+       unsigned char                   error_log_pointer;
+       ata_smart_errorlog_struct_t     errorlog_struct[5];
+       unsigned short                  ata_error_count;
+       unsigned short                  non_fatal_count;
+       unsigned short                  drive_timeout_count;
+       unsigned char                   reserved[53];
+       unsigned char                   chksum;
+} __attribute__ ((packed)) ata_smart_errorlog_t;
+
+typedef struct ata_smart_selftestlog_struct_s {
+       unsigned char                   selftestnumber;
+       unsigned char                   selfteststatus;
+       unsigned short                  timestamp;
+       unsigned char                   selftestfailurecheckpoint;
+       unsigned int                    lbafirstfailure;
+       unsigned char                   vendorspecific[15];
+} __attribute__ ((packed)) ata_smart_selftestlog_struct_t;
+
+typedef struct ata_smart_selftestlog_s {
+       unsigned short                  revnumber;
+       ata_smart_selftestlog_struct_t  selftest_struct[21];
+       unsigned char                   vendorspecific[2];
+       unsigned char                   mostrecenttest;
+       unsigned char                   resevered[2];
+       unsigned char                   chksum;
+} __attribute__ ((packed)) ata_smart_selftestlog_t;
 
 #endif /* _LINUX_HDSMART_H */
index ea395aaa86f8984ea62dfc0b0b2d04f36182d5db..8804c9777f91853a37eb4983e7ac98175f604468 100644 (file)
@@ -63,6 +63,12 @@ void cmd640_dump_regs (void);
  */
 #define IDE_DRIVE_CMD          99      /* (magic) undef to reduce kernel size*/
 
+/*
+ * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
+ */
+#define IDE_DRIVE_TASK         98
+#define IDE_DRIVE_CMD_AEB      98
+
 /*
  *  "No user-serviceable parts" beyond this point  :)
  *****************************************************************************/
@@ -302,6 +308,10 @@ typedef struct ide_drive_s {
        char            driver_req[10]; /* requests specific driver */
        int             last_lun;       /* last logical unit */
        int             forced_lun;     /* if hdxlun was given at boot */
+       int             lun;            /* logical unit */
+       byte            init_speed;     /* transfer rate set at boot */
+       byte            current_speed;  /* current transfer rate set */
+       byte            dn;             /* now wide spread use */
 } ide_drive_t;
 
 /*
@@ -336,7 +346,8 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
  * 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);
+typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
+typedef int (ide_speedproc_t) (ide_drive_t *, byte);
 
 /*
  * This is used to provide support for strange interfaces
@@ -374,6 +385,7 @@ typedef struct hwif_s {
        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_speedproc_t *speedproc;     /* routine to retune DMA modes for drives */
        ide_selectproc_t *selectproc;   /* tweaks hardware to select drive */
        ide_resetproc_t *resetproc;     /* routine to reset controller after a disk reset */
        ide_dmaproc_t   *dmaproc;       /* dma read/write/abort routine */
@@ -409,6 +421,7 @@ typedef struct hwif_s {
        unsigned long   last_time;      /* time when previous rq was done */
 #endif
        byte            straight8;      /* Alan's straight 8 check */
+       void            *hwif_data;     /* extra hwif data */
 } ide_hwif_t;
 
 /*
@@ -728,14 +741,16 @@ 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);
+int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
 
 void ide_delay_50ms (void);
 int system_bus_clock(void);
 
+byte ide_auto_reduce_xfer (ide_drive_t *drive);
 int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature);
+int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
 int ide_config_drive_speed (ide_drive_t *drive, byte speed);
-int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature);
+int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -769,37 +784,10 @@ request_queue_t *ide_get_queue (kdev_t dev);
  */
 int drive_is_flashcard (ide_drive_t *drive);
 
-int  ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags);
+int ide_spin_wait_hwgroup (ide_drive_t *drive);
 void ide_timer_expiry (unsigned long data);
 void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
-void do_ide0_request (request_queue_t * q);
-#if MAX_HWIFS > 1
-void do_ide1_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 2
-void do_ide2_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 3
-void do_ide3_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 4
-void do_ide4_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 5
-void do_ide5_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 6
-void do_ide6_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 7
-void do_ide7_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 8
-void do_ide8_request (request_queue_t * q);
-#endif
-#if MAX_HWIFS > 9
-void do_ide9_request (request_queue_t * q);
-#endif
+void do_ide_request (request_queue_t * q);
 void ide_init_subdrivers (void);
 
 #ifndef _IDE_C
index 61f672a3c0429bf660e7372146516b4ddd1675f3..311bdd66d64e1f43f77c62253fe560e256268abf 100644 (file)
@@ -70,6 +70,7 @@ typedef struct zone_struct {
 typedef struct zonelist_struct {
        zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited
        int gfp_mask;
+       atomic_t free_before_allocate;
 } zonelist_t;
 
 #define NR_GFPINDEX            0x100
index 0c84b76c4c794b94871429f226c99514b7622c3f..ddd0563a5588ca68c5c624d2453dcebcd5d01541 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pagemap.h>
 
 #include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/auth.h>
 
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
@@ -98,7 +99,6 @@ do { \
 
 /* Inode Flags */
 #define NFS_USE_READDIRPLUS(inode)     ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
-#define NFS_MONOTONE_COOKIES(inode)    ((NFS_SERVER(inode)->flags & NFS_NONMONOTONE_COOKIES) ? 0 : 1)
 
 /*
  * These are the default flags for swap requests
@@ -155,6 +155,17 @@ extern struct inode_operations nfs_file_inode_operations;
 extern struct file_operations nfs_file_operations;
 extern struct address_space_operations nfs_file_aops;
 
+static __inline__ struct rpc_cred *
+nfs_file_cred(struct file *file)
+{
+       struct rpc_cred *cred = (struct rpc_cred *)(file->private_data);
+#ifdef RPC_DEBUG
+       if (cred && cred->cr_magic != RPCAUTH_CRED_MAGIC)
+               BUG();
+#endif
+       return cred;
+}
+
 /*
  * linux/fs/nfs/dir.c
  */
index 8e11ef368f6997fd195480d2191accd87e02d907..7b7df5b06f2039bc489e5692a43bca7913e7ca8f 100644 (file)
@@ -54,11 +54,4 @@ struct nfs_mount_data {
 #define NFS_MOUNT_NONLM                0x0200  /* 3 */
 #define NFS_MOUNT_FLAGMASK     0xFFFF
 
-/*
- * Private flags - not to be set by mount program
- */
-#ifdef __KERNEL__
-#define NFS_NONMONOTONE_COOKIES        0x00010000
-#endif /* __KERNEL__ */
 #endif
index 475fced7c0d977bddba84115a5026be645b8d7cf..5f6572b22216638539d9152feb4620a7dd4da386 100644 (file)
@@ -40,7 +40,7 @@ struct nfs_page {
 
 #define NFS_WBACK_BUSY(req)    ((req)->wb_flags & PG_BUSY)
 
-extern struct nfs_page *nfs_create_request(struct dentry *dentry,
+extern struct nfs_page *nfs_create_request(struct file *file,
                                            struct page *page,
                                            unsigned int offset,
                                            unsigned int count);
index eca3e1b2d570508632cb5940755ad7b927cee367..1e6147c355dda39bb8b97296bb06a742ceee9670 100644 (file)
@@ -106,7 +106,6 @@ struct nfs_writeres {
  * Argument struct for decode_entry function
  */
 struct nfs_entry {
-       struct page *           page;
        __u64                   ino;
        __u64                   cookie,
                                prev_cookie;
@@ -115,8 +114,6 @@ struct nfs_entry {
        int                     eof;
        struct nfs_fh           fh;
        struct nfs_fattr        fattr;
-       unsigned long           offset,
-                               prev;
 };
 
 /*
@@ -326,10 +323,10 @@ struct nfs_rpc_ops {
                            struct nfs_fh *, struct nfs_fattr *);
        int     (*access)  (struct dentry *, int , int);
        int     (*readlink)(struct dentry *, void *, unsigned int);
-       int     (*read)    (struct dentry *, struct nfs_fattr *,
+       int     (*read)    (struct file *, struct nfs_fattr *,
                            int, loff_t, unsigned int,
                            void *buffer, int *eofp);
-       int     (*write)   (struct dentry *, struct nfs_fattr *,
+       int     (*write)   (struct file *, struct nfs_fattr *,
                            int, loff_t, unsigned int,
                            void *buffer, struct nfs_writeverf *verfp);
        int     (*commit)  (struct dentry *, struct nfs_fattr *,
index b65681331c9b999a71632ef2db63cc8e1191ddfb..b7a9f8fbe8abfcb11235d0941c4a087db26c398b 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82443BX_0  0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1  0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2  0x7192
+#define PCI_DEVICE_ID_INTEL_82440MX_1  0x7194
+#define PCI_DEVICE_ID_INTEL_82443MX_0  0x7198
+#define PCI_DEVICE_ID_INTEL_82443MX_1  0x7199
+#define PCI_DEVICE_ID_INTEL_82443MX_2  0x719a
+#define PCI_DEVICE_ID_INTEL_82443MX_3  0x719b
+#define PCI_DEVICE_ID_INTEL_82372FB_0  0x7600
 #define PCI_DEVICE_ID_INTEL_82372FB_1  0x7601
+#define PCI_DEVICE_ID_INTEL_82372FB_2  0x7602
+#define PCI_DEVICE_ID_INTEL_82372FB_3  0x7603
 #define PCI_DEVICE_ID_INTEL_82454GX    0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX    0x84ca
index d106c881abb58768bc8a97514145878cbf3c594d..242be9730f1b618739a2f192f7e415128247dd3a 100644 (file)
@@ -25,6 +25,9 @@ struct rpc_cred {
        unsigned long           cr_expire;      /* when to gc */
        unsigned short          cr_count;       /* ref count */
        unsigned short          cr_flags;       /* various flags */
+#ifdef RPC_DEBUG
+       unsigned long           cr_magic;       /* 0x0f4aa4f0 */
+#endif
 
        uid_t                   cr_uid;
 
@@ -34,6 +37,8 @@ struct rpc_cred {
 #define RPCAUTH_CRED_UPTODATE  0x0002
 #define RPCAUTH_CRED_DEAD      0x0004
 
+#define RPCAUTH_CRED_MAGIC     0x0f4aa4f0
+
 /*
  * Client authentication handle
  */
index 612ce337d41be6a0c812382dd5642696d168ad1f..fefe0681d132c928c50f516828c2db7bcce1f126 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
 
 #include <asm/pgtable.h>
 
@@ -24,6 +25,11 @@ long vread(char *buf, char *addr, unsigned long count);
 void vmfree_area_pages(unsigned long address, unsigned long size);
 int vmalloc_area_pages(unsigned long address, unsigned long size);
 
+/* vmlist_lock is a read-write spinlock that protects vmlist 
+ * Used in mm/vmalloc.c (get_vm_area() and vfree()) and fs/proc/kcore.c.
+ */
+extern rwlock_t vmlist_lock;
 extern struct vm_struct * vmlist;
 #endif
 
index 6d8f5dae61af701e3ad3fc795b33ff6694ea3b08..6ac1f0e88fe47ce31db3c6ae48144310cc6c3320 100644 (file)
@@ -27,7 +27,7 @@
 extern int printk(const char *fmt, ...);
 #define WQ_BUG() do { \
        printk("wq bug, forcing oops.\n"); \
-       *(int*)0 = 0; \
+       BUG(); \
 } while (0)
 
 #define CHECK_MAGIC(x) if (x != (long)&(x)) \
index 6cb645c1f4d0f5d7e64e0793b421e5fc0e2ad847..04180c8e93401e777c1c9f4c75d791bc413cc3c0 100644 (file)
@@ -405,9 +405,18 @@ static int __init debug_kernel(char *str)
        return 1;
 }
 
+static int __init quiet_kernel(char *str)
+{
+       if (*str)
+               return 0;
+       console_loglevel = 4;
+       return 1;
+}
+
 __setup("ro", readonly);
 __setup("rw", readwrite);
 __setup("debug", debug_kernel);
+__setup("quiet", quiet_kernel);
 
 /*
  * This is a simple kernel command line parsing function: it parses
index 8771f73d11aece8d2257dbeb615c7b2ecc21b75f..29819efbb021d1cd8bed2b735b6ff55bfa2a956a 100644 (file)
@@ -159,25 +159,19 @@ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
 void* ipc_alloc(int size)
 {
        void* out;
-       if(size > PAGE_SIZE) {
-               lock_kernel();
+       if(size > PAGE_SIZE)
                out = vmalloc(size);
-               unlock_kernel();
-       } else {
+       else
                out = kmalloc(size, GFP_KERNEL);
-       }
        return out;
 }
 
 void ipc_free(void* ptr, int size)
 {
-       if(size > PAGE_SIZE) {
-               lock_kernel();
+       if(size > PAGE_SIZE)
                vfree(ptr);
-               unlock_kernel();
-       } else {
+       else
                kfree(ptr);
-       }
 }
 
 /* 
index 4060c802ac9b4138ba1aaea30d0be77c1cdb6fc5..3f3b5fc16fd89521b3436e3549f6decb7bdc1fe7 100644 (file)
@@ -23,7 +23,7 @@ struct exec_domain default_exec_domain = {
 };
 
 static struct exec_domain *exec_domains = &default_exec_domain;
-static spinlock_t exec_domains_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t exec_domains_lock = RW_LOCK_UNLOCKED;
 
 static asmlinkage void no_lcall7(int segment, struct pt_regs * regs)
 {
@@ -48,15 +48,15 @@ static struct exec_domain *lookup_exec_domain(unsigned long personality)
        unsigned long pers = personality & PER_MASK;
        struct exec_domain *it;
 
-       spin_lock(&exec_domains_lock);
+       read_lock(&exec_domains_lock);
        for (it=exec_domains; it; it=it->next)
                if (pers >= it->pers_low && pers <= it->pers_high) {
                        if (!try_inc_mod_count(it->module))
                                continue;
-                       spin_unlock(&exec_domains_lock);
+                       read_unlock(&exec_domains_lock);
                        return it;
                }
-       spin_unlock(&exec_domains_lock);
+       read_unlock(&exec_domains_lock);
 
        /* Should never get this far. */
        printk(KERN_ERR "No execution domain for personality 0x%02lx\n", pers);
@@ -71,15 +71,15 @@ int register_exec_domain(struct exec_domain *it)
                return -EINVAL;
        if (it->next)
                return -EBUSY;
-       spin_lock(&exec_domains_lock);
+       write_lock(&exec_domains_lock);
        for (tmp=exec_domains; tmp; tmp=tmp->next)
                if (tmp == it) {
-                       spin_unlock(&exec_domains_lock);
+                       write_unlock(&exec_domains_lock);
                        return -EBUSY;
                }
        it->next = exec_domains;
        exec_domains = it;
-       spin_unlock(&exec_domains_lock);
+       write_unlock(&exec_domains_lock);
        return 0;
 }
 
@@ -88,17 +88,17 @@ int unregister_exec_domain(struct exec_domain *it)
        struct exec_domain ** tmp;
 
        tmp = &exec_domains;
-       spin_lock(&exec_domains_lock);
+       write_lock(&exec_domains_lock);
        while (*tmp) {
                if (it == *tmp) {
                        *tmp = it->next;
                        it->next = NULL;
-                       spin_unlock(&exec_domains_lock);
+                       write_unlock(&exec_domains_lock);
                        return 0;
                }
                tmp = &(*tmp)->next;
        }
-       spin_unlock(&exec_domains_lock);
+       write_unlock(&exec_domains_lock);
        return -EINVAL;
 }
 
@@ -148,11 +148,11 @@ int get_exec_domain_list(char * page)
        int len = 0;
        struct exec_domain * e;
 
-       spin_lock(&exec_domains_lock);
+       read_lock(&exec_domains_lock);
        for (e=exec_domains; e && len < PAGE_SIZE - 80; e=e->next)
                len += sprintf(page+len, "%d-%d\t%-16s\t[%s]\n",
                        e->pers_low, e->pers_high, e->name,
                        e->module ? e->module->name : "kernel");
-       spin_unlock(&exec_domains_lock);
+       read_unlock(&exec_domains_lock);
        return len;
 }
index 11e03521eb5d52623cdf1c0aaf6f430617d9a05d..7c9dbc6954139a11655e36221443872227c27558 100644 (file)
@@ -60,7 +60,7 @@ struct page * prepare_highmem_swapout(struct page * page)
         * ok, we can just forget about our highmem page since 
         * we stored its data into the new regular_page.
         */
-       __free_page(page);
+       page_cache_release(page);
        new_page = mem_map + MAP_NR(regular_page);
        LockPage(new_page);
        return new_page;
@@ -78,7 +78,7 @@ struct page * replace_with_highmem(struct page * page)
        if (!highpage)
                return page;
        if (!PageHighMem(highpage)) {
-               __free_page(highpage);
+               page_cache_release(highpage);
                return page;
        }
 
@@ -94,7 +94,7 @@ struct page * replace_with_highmem(struct page * page)
         * We can just forget the old page since 
         * we stored its data into the new highmem-page.
         */
-       __free_page(page);
+       page_cache_release(page);
 
        return highpage;
 }
index e5a54892590c037bfa48e4b7f75e647c676b478e..de7dc07f8c91d1ff5da065fabc5d6dabc5382596 100644 (file)
@@ -156,7 +156,7 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
        unsigned long address = vma->vm_start;
        unsigned long end = vma->vm_end;
        unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
-       
+
        src_pgd = pgd_offset(src, address)-1;
        dst_pgd = pgd_offset(dst, address)-1;
        
@@ -878,7 +878,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
                new_page = old_page;
        }
        spin_unlock(&mm->page_table_lock);
-       __free_page(new_page);
+       page_cache_release(new_page);
        return 1;       /* Minor fault */
 
 bad_wp_page:
@@ -1022,7 +1022,7 @@ void swapin_readahead(swp_entry_t entry)
                /* Ok, do the async read-ahead now */
                new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
                if (new_page != NULL)
-                       __free_page(new_page);
+                       page_cache_release(new_page);
                swap_free(SWP_ENTRY(SWP_TYPE(entry), offset));
        }
        return;
index 926364499a505eae267beecacddb886b71359d92..8961addd543fb04360790e2d7ea1a7a8527f7446 100644 (file)
@@ -243,6 +243,9 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
                        if (page)
                                return page;
                }
+               /* Somebody else is freeing pages? */
+               if (atomic_read(&zonelist->free_before_allocate))
+                       try_to_free_pages(zonelist->gfp_mask);
        }
 
        /*
@@ -270,7 +273,11 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
         */
        if (!(current->flags & PF_MEMALLOC)) {
                int gfp_mask = zonelist->gfp_mask;
-               if (!try_to_free_pages(gfp_mask)) {
+               int result;
+               atomic_inc(&zonelist->free_before_allocate);
+               result = try_to_free_pages(gfp_mask);
+               atomic_dec(&zonelist->free_before_allocate);
+               if (!result) {
                        if (!(gfp_mask & __GFP_HIGH))
                                goto fail;
                }
@@ -414,6 +421,7 @@ static inline void build_zonelists(pg_data_t *pgdat)
                zonelist = pgdat->node_zonelists + i;
                memset(zonelist, 0, sizeof(*zonelist));
 
+               atomic_set(&zonelist->free_before_allocate, 0);
                zonelist->gfp_mask = i;
                j = 0;
                k = ZONE_NORMAL;
index 347f87372e1fb540436e6cea018c0ee27ddfde2d..2405aba2ffbfdc8d9c149a845a6f1e4bc1503e9b 100644 (file)
@@ -136,7 +136,7 @@ void free_page_and_swap_cache(struct page *page)
                }
                UnlockPage(page);
        }
-        page_cache_release(page);
+       page_cache_release(page);
 }
 
 
index c4b4733b7dd96c3d7b19704f372776af60e6f300..55ef476a38a077f24aa18a5f70dbbdebfc6c5bc7 100644 (file)
@@ -377,7 +377,7 @@ static int try_to_unuse(unsigned int type)
                    page we've been using. */
                if (PageSwapCache(page))
                        delete_from_swap_cache(page);
-               __free_page(page);
+               page_cache_release(page);
                /*
                 * Check for and clear any overflowed swap map counts.
                 */
index ae8e64351c1b65cde659d9f13324b74156ecfc81..00879933cfff4a8ca84ee625571380de5bc91b86 100644 (file)
@@ -3,14 +3,17 @@
  *
  *  Copyright (C) 1993  Linus Torvalds
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ *  SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
  */
 
 #include <linux/malloc.h>
 #include <linux/vmalloc.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
+rwlock_t vmlist_lock = RW_LOCK_UNLOCKED;
 struct vm_struct * vmlist = NULL;
 
 static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size)
@@ -163,11 +166,13 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
        if (!area)
                return NULL;
        addr = VMALLOC_START;
+       write_lock(&vmlist_lock);
        for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
                if (size + addr < (unsigned long) tmp->addr)
                        break;
                addr = tmp->size + (unsigned long) tmp->addr;
                if (addr > VMALLOC_END-size) {
+                       write_unlock(&vmlist_lock);
                        kfree(area);
                        return NULL;
                }
@@ -177,6 +182,7 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
        area->size = size + PAGE_SIZE;
        area->next = *p;
        *p = area;
+       write_unlock(&vmlist_lock);
        return area;
 }
 
@@ -190,14 +196,17 @@ void vfree(void * addr)
                printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
                return;
        }
+       write_lock(&vmlist_lock);
        for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
                if (tmp->addr == addr) {
                        *p = tmp->next;
                        vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
                        kfree(tmp);
+                       write_unlock(&vmlist_lock);
                        return;
                }
        }
+       write_unlock(&vmlist_lock);
        printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
 }
 
@@ -235,6 +244,7 @@ long vread(char *buf, char *addr, unsigned long count)
        if ((unsigned long) addr + count < count)
                count = -(unsigned long) addr;
 
+       read_lock(&vmlist_lock);
        for (tmp = vmlist; tmp; tmp = tmp->next) {
                vaddr = (char *) tmp->addr;
                if (addr >= vaddr + tmp->size - PAGE_SIZE)
@@ -242,7 +252,7 @@ long vread(char *buf, char *addr, unsigned long count)
                while (addr < vaddr) {
                        if (count == 0)
                                goto finished;
-                       put_user('\0', buf);
+                       *buf = '\0';
                        buf++;
                        addr++;
                        count--;
@@ -251,12 +261,13 @@ long vread(char *buf, char *addr, unsigned long count)
                do {
                        if (count == 0)
                                goto finished;
-                       put_user(*addr, buf);
+                       *buf = *addr;
                        buf++;
                        addr++;
                        count--;
                } while (--n > 0);
        }
 finished:
+       read_unlock(&vmlist_lock);
        return buf - buf_start;
 }
index c96b1bc9122acc6d4cb1c8ea0ef4d007810bd3e0..143c74833d310d85a7b8653b26af523a51fc16f0 100644 (file)
@@ -79,7 +79,7 @@ drop_pte:
                mm->swap_cnt--;
                vma->vm_mm->rss--;
                flush_tlb_page(vma, address);
-               __free_page(page);
+               page_cache_release(page);
                goto out_failed;
        }
 
@@ -151,7 +151,7 @@ drop_pte:
                if (file) fput(file);
                if (!error)
                        goto out_free_success;
-               __free_page(page);
+               page_cache_release(page);
                return error;
        }
 
@@ -184,7 +184,7 @@ drop_pte:
        rw_swap_page(WRITE, page, 0);
 
 out_free_success:
-       __free_page(page);
+       page_cache_release(page);
        return 1;
 out_swap_free:
        swap_free(entry);
index b8c0a7be877cf5023bf65c76e5c25433292bbd64..7eb578a60b63ff8b00769eda11c91e3d0d94e412 100644 (file)
@@ -84,6 +84,11 @@ rpcauth_init_credcache(struct rpc_auth *auth)
 static inline void
 rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred)
 {
+#ifdef RPC_DEBUG
+       if (cred->cr_magic != RPCAUTH_CRED_MAGIC)
+               BUG();
+       cred->cr_magic = 0;
+#endif
        if (auth->au_ops->crdestroy)
                auth->au_ops->crdestroy(cred);
        else
@@ -190,8 +195,13 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
        }
        spin_unlock(&rpc_credcache_lock);
 
-       if (!cred)
+       if (!cred) {
                cred = auth->au_ops->crcreate(taskflags);
+#ifdef RPC_DEBUG
+               if (cred)
+                       cred->cr_magic = RPCAUTH_CRED_MAGIC;
+#endif
+       }
 
        if (cred)
                rpcauth_insert_credcache(auth, cred);