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
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
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
(echo "*** You need to install DocBook stylesheets ***"; \
exit 1)
+%.eps: %.fig
+ -fig2dev -Leps $< $@
+
$(TOPDIR)/scripts/docproc:
$(MAKE) -C $(TOPDIR)/scripts docproc
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 $<
+<!-- -*- 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
- 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
- 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...
<!-- 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 {
[...]
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;
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.)
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;
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;
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
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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
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/
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
CONFIG_EXPERIMENTAL=y
#
-# System and processor type
+# System and Processor Type
#
# CONFIG_ARCH_ARC is not set
# CONFIG_ARCH_A5K is not set
# 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
# 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
# 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
# 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
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
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
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
# 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
#
# 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
# 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
# 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
CONFIG_EXPERIMENTAL=y
#
-# System and processor type
+# System and Processor Type
#
# CONFIG_ARCH_ARC is not set
# CONFIG_ARCH_A5K is not set
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
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
#
#
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
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
# 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
# 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
#
# 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
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
# 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
#
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
# 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_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
# 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
# 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
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
# 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
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_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
#
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
# Automatically generated make config: don't edit
#
CONFIG_ARM=y
+CONFIG_UID16=y
#
# Code maturity level options
CONFIG_EXPERIMENTAL=y
#
-# System and processor type
+# System and Processor Type
#
# CONFIG_ARCH_ARC is not set
# CONFIG_ARCH_A5K is not set
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
#
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
# 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
# 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
# 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
#
# 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
#
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
# 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
#
# 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
# 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
#
# 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
#
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
# 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
# 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
#
# 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
# 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
# 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
#
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
# 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
# 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
# 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
# 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
#
# CONFIG_NLS_ISO8859_15 is not set
CONFIG_NLS_KOI8_R=m
+#
+# USB support
+#
+# CONFIG_USB is not set
+
#
# Kernel hacking
#
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
+++ /dev/null
-/*
- * 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;
-}
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
# 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
# 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
{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},
}
}
+/*
+ * 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)
{
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;
+ }
}
}
# 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
# 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
# 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
* 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>
* 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>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
* 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>
#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
* 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>
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
/* 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
/* 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
*/
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.
*/
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
# 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
#
# CONFIG_HAMRADIO is not set
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
#
# ISDN subsystem
#
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
CONFIG_MAGIC_SYSRQ=y
# CONFIG_KGDB is not set
CONFIG_XMON=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
# 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
#
# CONFIG_HAMRADIO is not set
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
#
# ISDN subsystem
#
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
#include <asm/prom.h>
#include <asm/gg2.h>
#include <asm/machdep.h>
+#include <asm/init.h>
#include "pci.h"
* 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) {
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) {
}
-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) {
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)
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)
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)
| (((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) {
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) {
}
-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) {
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)
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)
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)
}
-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);
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);
}
-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);
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);
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);
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);
#include <asm/irq.h>
#include <asm/hydra.h>
#include <asm/keyboard.h>
+#include <asm/init.h>
#include "time.h"
#include "local_irq.h"
"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
};
-int
+int __chrp
chrp_get_cpuinfo(char *buffer)
{
int i, len, sdramen;
}
}
-void
+void __chrp
chrp_event_scan(void)
{
unsigned char log[1024];
ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
}
-void
+void __chrp
chrp_restart(char *cmd)
{
printk("RTAS system-reboot returned %d\n",
for (;;);
}
-void
+void __chrp
chrp_power_off(void)
{
/* allow power on only with power button press */
for (;;);
}
-void
+void __chrp
chrp_halt(void)
{
chrp_power_off();
}
-u_int
+u_int __chrp
chrp_irq_cannonicalize(u_int irq)
{
if (irq == 2)
}
}
-int chrp_get_irq( struct pt_regs *regs )
+int __chrp chrp_get_irq( struct pt_regs *regs )
{
int irq;
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
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);
}
}
-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)
return chrp_ide_irq;
}
-ide_ioreg_t
+ide_ioreg_t __chrp
chrp_ide_default_io_base(int index)
{
if (chrp_ide_ports_known == 0)
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)
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;
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;
#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;
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);
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);
/*
* 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;
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;
* -- 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
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)
/*
* 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 */
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);
EXPORT_SYMBOL(debugger_iabr_match);
EXPORT_SYMBOL(debugger_dabr_match);
EXPORT_SYMBOL(debugger_fault_handler);
+
+EXPORT_SYMBOL(ret_to_user_hook);
/*
* 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"
* 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>
#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>
/*
* 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];
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
- return -1;
+ return -EIO;
}
static inline void
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) {
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);
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
-out:
}
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]);
}
#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"
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,
*/
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.
*/
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);
}
*/
GregorianDay(tm);
}
-
-
-
{
#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)
{
int fixed;
- if (regs->msr & MSR_FP)
- giveup_fpu(current);
fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
}
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);
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
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
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)
* 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
* 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;
}
}
#endif /* EST8260 */
+
--- /dev/null
+/*
+ * 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;
* $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
#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
--- /dev/null
+/*
+ * 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;
--- /dev/null
+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 = . ;
+
+}
{
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)
#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;
}
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
*/
if (error_code & 0x10000000)
/* Guarded storage error. */
-#endif /* CONFIG_8xx */
goto bad_area;
-
+#endif /* CONFIG_8xx */
/* a write */
if (is_write) {
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
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;
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;
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) { \
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);
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;
}
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 )
-#!/usr/local/bin/perl
+#!/usr/bin/perl
#
# Copyright (c) 1998-1999 TiVo, Inc.
-#!/usr/local/bin/perl
+#!/usr/bin/perl
#
# Copyright (c) 1998-1999 TiVo, Inc.
# Original ELF parsing code.
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);
}
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);
. = 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) }
_end = . ;
PROVIDE (end = .);
}
-
# 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 :=
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
* 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>
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
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
/* ------------------------------------------------------------------------- */
-#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(ðer_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(ðer_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);
* 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>
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);
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.
}
}
-#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(ðer_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(ðer_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(ðer_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);
* 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
* ------------------------
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 */
/* --------------------------------------------------------------------------- */
-/*
- * 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);
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:
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:
}
/*
- * 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);
+ }
}
/*
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;
}
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 = ðerh_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 = ðerh_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);
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
/*
- * 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>
#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:
* 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
#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
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);
* '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 */
{ 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" */
* 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);
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);
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
#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;
unsigned long jiffies;
} output_log[OLOGSIZE];
-static int output_log_pos=0;
+static int output_log_pos;
#endif
#define CURRENTD -1
static int maximum(int a, int b)
{
- if(a > b)
+ if (a > b)
return a;
else
return b;
static int minimum(int a, int b)
{
- if(a < b)
+ if (a < b)
return a;
else
return b;
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
{
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;
}
}
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;
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) {
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);
else
break;
}
- if(!initialising) {
+ if (!initialising) {
DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
fdc, status, i);
show_floppy();
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;
{
/* 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));
/* 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);
}
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);
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
* 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 */
}
}
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
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;
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];
process_fd_request();
*g = current_type[drive];
}
- if(!*g)
+ if (!*g)
return -ENODEV;
return 0;
}
/* 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;
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);
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:
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) {
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;
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)){
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);
{ "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)
{
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;
}
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)) {
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;
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++) {
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);
#ifdef MODULE
-char *floppy=NULL;
+char *floppy;
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);
}
}
{
printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n");
- if(floppy)
+ if (floppy)
parse_floppy_cfg_string(floppy);
return floppy_init();
}
void floppy_eject(void)
{
int dummy;
- if(have_no_fdc)
+ if (have_no_fdc)
return;
if(floppy_grab_irq_and_dma()==0)
{
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;
}
/* 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(),
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;
lo->ioctl = NULL;
figure_loop_size(lo);
-out_putf:
+ out_putf:
fput(file);
-out:
+ out:
if (error)
MOD_DEC_USE_COUNT;
return error;
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 {
* (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>
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
#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"
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;
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 }
};
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[] =
/* 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))
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)
{
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)
#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;
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.
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;
}
}
/* 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);
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 */
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");
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 */
}
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)
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),
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
-/*
+/*
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
#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>
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;
#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
#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
}
-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 },
{
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;
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;
}
/*
/* 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)
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;
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;
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);
{
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;
}
--- /dev/null
+/*
+ * 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:
+ */
#include "audiochip.h"
/* Addresses to scan */
-#define I2C_TDA8425 0x82
static unsigned short normal_i2c[] = {
I2C_TDA8425 >> 1,
I2C_CLIENT_END};
*
* 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:
* 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
#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 };
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
#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) */
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)) {
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;
}
{
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;
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;
}
}
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;
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;
}
}
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 */
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 */
{
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;
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
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
- dprintk("VIDIOCGAUDIO\n");
+ dprintk("tda985x: VIDIOCGAUDIO\n");
if (chip == 9855)
{
int left,right;
case VIDIOCSAUDIO:
{
struct video_audio *va = arg;
- dprintk("VIDEOCSAUDIO...\n");
+ dprintk("tda985x: VIDEOCSAUDIO\n");
if (chip == 9855)
{
int left,right;
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;
default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
/* nothing */
- dprintk("Default\n");
+ d2printk("tda985x: Default\n");
} /* end of (cmd) switch */
--- /dev/null
+/*
+ * 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:
+ */
+
--- /dev/null
+/*
+ * 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:
+ */
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
};
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 },
{ 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 },
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;
}
{
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;
__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 */
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;
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))));
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)
{
{
#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;
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;
pci_write_config_byte(dev, 0x4b, tmpbyte);
}
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+ drive->current_speed = speed;
return (err);
}
(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 :
* 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);
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;
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);
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 ",
#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);
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);
}
break;
}
(void) amd7409_tune_chipset(drive, speed);
+ drive->current_speed = speed;
}
static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
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;
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)
(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);
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, ®D);
(void) pci_read_config_byte(dev, pciU, ®U);
regD &= ~(unit ? 0x40 : 0x20);
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;
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 :
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;
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, ®1);
pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2);
- 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);
}
{
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;
pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1);
pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2);
- 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);
}
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) {
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;
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;
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);
}
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, ®50h);
pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0x03);
pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h);
/* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */
+#endif
case ide_dma_timeout:
default:
break;
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)) {
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;
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 */
#include <linux/errno.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
+#include <linux/pci.h>
#include <linux/init.h>
#include <asm/dma.h>
* 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);
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)
{
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;
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)
{
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:
}
}
-static unsigned long
-icside_alloc_dmatable(void)
+static void *icside_alloc_dmatable(void)
{
static unsigned long dmatable;
static unsigned int leftover;
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
#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>
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;
}
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);
}
/*
#include <linux/malloc.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/byteorder.h>
}
}
+/*
+ *
+ */
+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
*/
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);
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;
}
* 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) &&
* 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;
}
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,
return error;
}
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
EXPORT_SYMBOL(ide_driveid_update);
EXPORT_SYMBOL(ide_ata66_check);
EXPORT_SYMBOL(set_transfer);
#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})
{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 },
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;
}
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?
*/
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;
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) &&
*
* 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
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);
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;
#ifdef CONFIG_PMAC_IDEDMA_AUTO
ide_hwifs[ix].autodma = 1;
#endif
+// ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
}
}
/* 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)
{
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);
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)
}
*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,
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);
*/
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) {
++i;
}
pmac_ide_count = i;
+ if (big_delay)
+ mdelay(IDE_WAKEUP_DELAY_MS);
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&idepmac_sleep_notifier);
return result;
}
+/* Calculate MultiWord DMA timings */
static int
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)
/* 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;
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;
#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)) {
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;
}
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);
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;
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;
}
}
}
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;
}
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]);
/* 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);
}
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);
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)
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);
}
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) {
#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);
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)
{
|| !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 */
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);
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;
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]);
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) {
* 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;
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.
*/
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;
}
/*
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 */
/*
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;
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 */
}
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;
}
*/
int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
{
- unsigned long flags;
int i;
u32 *p;
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:
*p = val;
break;
}
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_unlock_irq(&io_request_lock);
return 0;
}
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)
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.
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)
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))
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:
{
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
*/
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
{
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();
#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);
#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);
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;
* 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));
}
}
- 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))
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 :
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) {
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;
}
#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, ®4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
pci_read_config_word(dev, 0x4a, ®4a);
pci_read_config_word(dev, 0x54, ®54);
- 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) {
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);
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 :
#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 */
}
/*
- * 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;
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, ®4bh);
if (drive->media != ide_disk)
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)
* 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;
return err;
}
-#undef SIS5513_TUNEPROC
+#define SIS5513_TUNEPROC
#ifdef SIS5513_TUNEPROC
static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
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) {
}
}
- switch(drive_number) {
+ switch(drive->dn) {
case 0: drive_pci = 0x40;break;
case 1: drive_pci = 0x42;break;
case 2: drive_pci = 0x44;break;
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 :
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 },
{ 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 },
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 },
{ 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 },
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 },
{ 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 },
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 },
{ 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 },
{
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;
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;
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);
}
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++) {
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");
}
#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;
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 *);
{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.
* 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)
/*
* 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:
*/
*
* 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";
/* --------------------------------------------------------------------------- */
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.
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);
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);
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"
"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,
+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.
}
/**
- * 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)
}
/**
- * 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
{
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);
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);
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);
'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
udelay(1);
/* Event 0: Set data */
+ parport_data_forward (port);
parport_write_data (port, m);
udelay (400); /* Shouldn't need to wait this long. */
/**
* parport_set_timeout - set the inactivity timeout for a device
- * on a port
* @dev: device on a port
* @inactivity: inactivity timeout (in jiffies)
*
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;
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,
int flags)
{
size_t written;
+ int r;
/* Special case: a timeout of zero means we cannot call schedule(). */
if (!port->physport->cad->timeout)
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;
int flags)
{
size_t written;
+ int r;
/* Special case: a timeout of zero means we cannot call schedule(). */
if (!port->physport->cad->timeout)
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.*/
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;
{
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;
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.*/
/* 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. */
if (devid == devrev)
/* simple heuristics, we happened to read some
- non-winbond register */
+ non-smsc register */
return;
func=NULL;
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");
plx_9050,
afavlab_tk9902,
timedia_1889,
+ syba_2p_epp,
};
* (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 }, } },
/* 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 = {
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);
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++;
"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,
"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,
*/
-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, }
};
/*
* 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.
*
*/
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;
}
}
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;
}
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;
/* --------------------------------------------------------------------- */
-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)
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;
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);
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;
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);
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);
ssize_t ret = 0;
unsigned long flags;
unsigned int ptr;
+ unsigned int start_thr;
int cnt, err;
if (ppos != &file->f_pos)
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
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;
/* --------------------------------------------------------------------- */
-/*
- * 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);
"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)
{
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);
}
{
struct input_handle *handle = dev->handle;
struct input_dev **devptr = &input_dev;
+ struct input_handle *dnext;
/*
* Kill any pending repeat timers.
*/
while (handle) {
+ dnext = handle->dnext;
input_unlink_handle(handle);
handle->handler->disconnect(handle);
- handle = handle->dnext;
+ handle = dnext;
}
/*
{
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;
}
/*
/*
- * 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>
* 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
*/
/*
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);
}
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;
}
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;
{
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)
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];
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");
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);
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);
* (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>
/* 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"
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;
}
}
/*-------------------------------------------------------------------*/
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
#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);
}
}
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);
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;
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;
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;
}
}
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
}
}
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);
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);
if (type != 0)
continue;
-
if (pci_enable_device (dev) < 0)
continue;
#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
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 {
module_init(cyber2000fb_init);
#endif
module_exit(cyberpro_exit);
+
+MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
*
* 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)
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
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
endif
endif
-ifdef CONFIG_PROC_FS
-SUB_DIRS += proc
-endif
-
ifeq ($(CONFIG_BFS_FS),y)
SUB_DIRS += bfs
else
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__)
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
* 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)
{
if (!mpnt)
return -ENOMEM;
+ down(¤t->mm->mmap_sem);
{
mpnt->vm_mm = current->mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
}
stack_base += PAGE_SIZE;
}
+ up(¤t->mm->mmap_sem);
return 0;
}
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);
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 {
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 {
DIR_REC dir;
THD_REC thd;
} u;
-};
+} __attribute__((packed));
/*================ File-local variables ================*/
hfs_byte_t filler[16];
hfs_word_t entries;
hfs_byte_t descrs[12*HFS_HDR_MAX];
-};
+} __attribute__((packed));
/*================ File-local functions ================*/
struct hfs_name {
hfs_byte_t Len;
hfs_byte_t Name[31];
-};
+} __attribute__((packed));
typedef struct {
hfs_word_t v;
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;
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 {
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)))
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 {
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 ========*/
hfs_byte_t bthResv2; /* reserved */
hfs_lword_t bthAtrb; /* (F) attributes */
hfs_lword_t bthResv3[16]; /* Reserved */
-};
+} __attribute__((packed));
/*
* 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
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 ================*/
hfs_lword_t pdSize;
hfs_lword_t pdFSID;
} pdEntry[42];
-};
+} __attribute__((packed));
/*================ File-local functions ================*/
*
* 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)
/*
* 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)
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);
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:
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;
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);
}
};
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
* 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
{
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);
* 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;
}
*/
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;
}
break;
}
}
- p++; /* EOF flag */
-
- if (p > end) {
- printk(KERN_NOTICE
- "NFS: short packet in readdir reply!\n");
- return -errno_NFSERR_IO;
- }
return nr;
}
}
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);
}
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);
}
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);
}
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);
* 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);
(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);
}
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;
}
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;
}
/*
* 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",
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:
/*
* 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 *);
* 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;
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);
}
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;
}
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;
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;
* 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;
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 */
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 */
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;
* 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;
}
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;
* 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
* 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;
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;
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)
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;
/* 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__)
* 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 */
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;
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)
+{
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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()
--- /dev/null
+/*
+ * 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)
#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)
+++ /dev/null
-/*
- * 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
({ \
__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
#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 */
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);
#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); })
#endif
-
#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)
#include <linux/config.h>
-#include <linux/config.h>
-
extern __inline__ void
__delay(unsigned long loops)
{
#ifndef _ASM_HARDIRQ_H
#define _ASM_HARDIRQ_H
-#include <linux/config.h>
-
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/irq.h>
#include <linux/config.h>
-#include <linux/config.h>
-
/* TLB flushing:
*
* - flush_tlb_all() flushes all processes TLB entries
#include <asm/isadep.h>
-#include <linux/config.h>
-
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
#include <linux/config.h>
-#include <linux/config.h>
-
extern __inline__ void
__delay(unsigned long loops)
{
#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>
#include <linux/config.h>
-#include <linux/config.h>
-
/* TLB flushing:
*
* - flush_tlb_all() flushes all processes TLB entries
*/
#define current_text_addr() ({ __label__ _l; _l: &&_l;})
-#include <linux/config.h>
#if !defined (_LANGUAGE_ASSEMBLY)
#include <asm/cachectl.h>
#include <asm/mipsregs.h>
#ifndef _ASM_SN_ADDRS_H
#define _ASM_SN_ADDRS_H
+#include <linux/config.h>
#if _LANGUAGE_C
#include <linux/types.h>
#endif /* _LANGUAGE_C */
#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>
-/**************************************************************************
- * *
- * 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 */
-/**************************************************************************
- * *
- * 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.
} hub_intmasks_t;
#endif /* _LANGUAGE_C */
-#endif /* __SYS_SN_INTR_PUBLIC_H__ */
-
+#endif /* __ASM_SN_INTR_PUBLIC_H */
#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>
* 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
#ifndef _ASM_SN_KLDIR_H
#define _ASM_SN_KLDIR_H
+#include <linux/config.h>
#if defined(CONFIG_SGI_IO)
#include <asm/hack.h>
#endif
-/**************************************************************************
- * *
- * 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 $"
#define CACHE_ERR_OFF 0x128
#define NMISR_OFF 0x130
-
-#endif /* __SYS_SN_NMI_H__ */
+#endif /* __ASM_SN_NMI_H */
#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);
#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
#endif /* _PPC_BITOPS_H */
+
#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)
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)
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 {
__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) \
#include <linux/config.h>
+#ifndef __ASSEMBLY__
+#include <asm/system.h> /* for xmon definition */
+#endif /* ndef __ASSEMBLY__ */
#ifndef _PPC_PAGE_H
#define _PPC_PAGE_H
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
#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 */
#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 {
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
* 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 */
};
/*
#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 */
*/
#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 :)
*****************************************************************************/
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;
/*
* 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
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 */
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;
/*
* 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
*/
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
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
#include <linux/pagemap.h>
#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/auth.h>
#include <linux/nfs.h>
#include <linux/nfs2.h>
/* 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
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
*/
#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
#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);
* Argument struct for decode_entry function
*/
struct nfs_entry {
- struct page * page;
__u64 ino;
__u64 cookie,
prev_cookie;
int eof;
struct nfs_fh fh;
struct nfs_fattr fattr;
- unsigned long offset,
- prev;
};
/*
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 *,
#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
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;
#define RPCAUTH_CRED_UPTODATE 0x0002
#define RPCAUTH_CRED_DEAD 0x0004
+#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
+
/*
* Client authentication handle
*/
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/spinlock.h>
#include <asm/pgtable.h>
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
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)) \
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
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);
- }
}
/*
};
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)
{
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);
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;
}
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;
}
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;
}
* 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;
if (!highpage)
return page;
if (!PageHighMem(highpage)) {
- __free_page(highpage);
+ page_cache_release(highpage);
return 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;
}
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;
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:
/* 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;
if (page)
return page;
}
+ /* Somebody else is freeing pages? */
+ if (atomic_read(&zonelist->free_before_allocate))
+ try_to_free_pages(zonelist->gfp_mask);
}
/*
*/
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;
}
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;
}
UnlockPage(page);
}
- page_cache_release(page);
+ page_cache_release(page);
}
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.
*/
*
* 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)
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;
}
area->size = size + PAGE_SIZE;
area->next = *p;
*p = area;
+ write_unlock(&vmlist_lock);
return area;
}
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);
}
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)
while (addr < vaddr) {
if (count == 0)
goto finished;
- put_user('\0', buf);
+ *buf = '\0';
buf++;
addr++;
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;
}
mm->swap_cnt--;
vma->vm_mm->rss--;
flush_tlb_page(vma, address);
- __free_page(page);
+ page_cache_release(page);
goto out_failed;
}
if (file) fput(file);
if (!error)
goto out_free_success;
- __free_page(page);
+ page_cache_release(page);
return error;
}
rw_swap_page(WRITE, page, 0);
out_free_success:
- __free_page(page);
+ page_cache_release(page);
return 1;
out_swap_free:
swap_free(entry);
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
}
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);