Commit 9521288f authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.99pre9-5

parent dad12642
...@@ -12468,14 +12468,6 @@ CONFIG_APM_DISPLAY_BLANK ...@@ -12468,14 +12468,6 @@ CONFIG_APM_DISPLAY_BLANK
backlight at all, or it might print a lot of errors to the console, backlight at all, or it might print a lot of errors to the console,
especially if you are using gpm. especially if you are using gpm.
Ignore multiple suspend/standby events
CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
This option is necessary on the IBM Thinkpad 560, but should work on
all other laptops. When the APM BIOS returns multiple suspend or
standby events while one is already being processed they will be
ignored. Without this the Thinkpad 560 has troubles with the user
level daemon apmd, and with the PCMCIA package pcmcia-cs.
Ignore multiple suspend/resume cycles Ignore multiple suspend/resume cycles
CONFIG_APM_IGNORE_SUSPEND_BOUNCE CONFIG_APM_IGNORE_SUSPEND_BOUNCE
This option is necessary on the Dell Inspiron 3200 and others, but This option is necessary on the Dell Inspiron 3200 and others, but
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
<para> <para>
The first parallel port support for Linux came with the line The first parallel port support for Linux came with the line
printer driver, <filename>lp</filename>. The printer driver is a printer driver, <literal>lp</literal>. The printer driver is a
character special device, and (in Linux 2.0) had support for character special device, and (in Linux 2.0) had support for
writing, via <function>write</function>, and configuration and writing, via <function>write</function>, and configuration and
statistics reporting via <function>ioctl</function>. statistics reporting via <function>ioctl</function>.
...@@ -152,7 +152,7 @@ ...@@ -152,7 +152,7 @@
--> -->
<para> <para>
The <filename>parport</filename> code in Linux 2.2 was designed to The <literal>parport</literal> code in Linux 2.2 was designed to
meet these problems of architectural differences in parallel meet these problems of architectural differences in parallel
ports, of port-sharing between devices with pass-through ports, ports, of port-sharing between devices with pass-through ports,
and of lack of support for IEEE 1284 transfer modes. and of lack of support for IEEE 1284 transfer modes.
...@@ -161,7 +161,7 @@ ...@@ -161,7 +161,7 @@
<!-- platform differences --> <!-- platform differences -->
<para> <para>
There are two layers to the <filename>parport</filename> There are two layers to the <literal>parport</literal>
subsystem, only one of which deals directly with the hardware. subsystem, only one of which deals directly with the hardware.
The other layer deals with sharing and IEEE 1284 transfer modes. The other layer deals with sharing and IEEE 1284 transfer modes.
In this way, parallel support for a particular architecture comes In this way, parallel support for a particular architecture comes
...@@ -172,13 +172,13 @@ ...@@ -172,13 +172,13 @@
<!-- sharing model --> <!-- sharing model -->
<para> <para>
The sharing model provided by the <filename>parport</filename> The sharing model provided by the <literal>parport</literal>
subsystem is one of exclusive access. A device driver, such as subsystem is one of exclusive access. A device driver, such as
the printer driver, must ask the <filename>parport</filename> the printer driver, must ask the <literal>parport</literal>
layer for access to the port, and can only use the port once layer for access to the port, and can only use the port once
access has been granted. When it has finished a access has been granted. When it has finished a
<quote>transaction</quote>, it can tell the <quote>transaction</quote>, it can tell the
<filename>parport</filename> layer that it may release the port <literal>parport</literal> layer that it may release the port
for other device drivers to use. for other device drivers to use.
</para> </para>
...@@ -299,10 +299,10 @@ ...@@ -299,10 +299,10 @@
<title>Sharing core</title> <title>Sharing core</title>
<para> <para>
At the core of the <filename>parport</filename> subsystem is the At the core of the <literal>parport</literal> subsystem is the
sharing mechanism (see sharing mechanism (see
<filename>drivers/parport/share.c</filename>). This module, <filename>drivers/parport/share.c</filename>). This module,
<filename>parport</filename>, is responsible for keeping track of <literal>parport</literal>, is responsible for keeping track of
which ports there are in the system, which device drivers might be which ports there are in the system, which device drivers might be
interested in new ports, and whether or not each port is available interested in new ports, and whether or not each port is available
for use (or if not, which driver is currently using it). for use (or if not, which driver is currently using it).
...@@ -314,10 +314,10 @@ ...@@ -314,10 +314,10 @@
<title>Parports and their overrides</title> <title>Parports and their overrides</title>
<para> <para>
The generic <filename>parport</filename> sharing code doesn't The generic <literal>parport</literal> sharing code doesn't
directly handle the parallel port hardware. That is done instead directly handle the parallel port hardware. That is done instead
by <quote>low-level</quote> <filename>parport</filename> drivers. by <quote>low-level</quote> <literal>parport</literal> drivers.
The function of a low-level <filename>parport</filename> driver is The function of a low-level <literal>parport</literal> driver is
to detect parallel ports, register them with the sharing code, and to detect parallel ports, register them with the sharing code, and
provide a list of access functions for each port. provide a list of access functions for each port.
</para> </para>
...@@ -340,11 +340,11 @@ ...@@ -340,11 +340,11 @@
<para> <para>
Stacked on top of the sharing mechanism, but still in the Stacked on top of the sharing mechanism, but still in the
<filename>parport</filename> module, are functions for <literal>parport</literal> module, are functions for
transferring data. They are provided for the device drivers to transferring data. They are provided for the device drivers to
use, and are very much like library routines. Since these use, and are very much like library routines. Since these
transfer functions are provided by the generic transfer functions are provided by the generic
<filename>parport</filename> core they must use the <quote>lowest <literal>parport</literal> core they must use the <quote>lowest
common denominator</quote> set of access functions: they can set common denominator</quote> set of access functions: they can set
the control lines, examine the status lines, and use the data the control lines, examine the status lines, and use the data
lines. With some parallel ports the data lines can only be set lines. With some parallel ports the data lines can only be set
...@@ -356,7 +356,7 @@ ...@@ -356,7 +356,7 @@
</para> </para>
<para> <para>
The low-level <filename>parport</filename> drivers also provide The low-level <literal>parport</literal> drivers also provide
IEEE 1284 transfer functions, as names in the access function IEEE 1284 transfer functions, as names in the access function
list. The low-level driver can just name the generic IEEE 1284 list. The low-level driver can just name the generic IEEE 1284
transfer functions for this. Some parallel ports can do IEEE 1284 transfer functions for this. Some parallel ports can do IEEE 1284
...@@ -373,7 +373,7 @@ ...@@ -373,7 +373,7 @@
<para> <para>
When a parallel port device driver (such as When a parallel port device driver (such as
<filename>lp</filename>) initialises it tells the sharing layer <literal>lp</literal>) initialises it tells the sharing layer
about itself using <function>parport_register_driver</function>. about itself using <function>parport_register_driver</function>.
The information is put into a <structname>struct The information is put into a <structname>struct
parport_driver</structname>, which is put into a linked list. The parport_driver</structname>, which is put into a linked list. The
...@@ -441,7 +441,7 @@ ...@@ -441,7 +441,7 @@
the draft specifies the on-the-wire protocol for daisy-chaining the draft specifies the on-the-wire protocol for daisy-chaining
and multiplexing, and also suggests a programming interface for and multiplexing, and also suggests a programming interface for
using it. That interface (or most of it) has been implemented in using it. That interface (or most of it) has been implemented in
the <filename>parport</filename> code in Linux. the <literal>parport</literal> code in Linux.
</para> </para>
<para> <para>
...@@ -494,20 +494,27 @@ ...@@ -494,20 +494,27 @@
<function>parport_device_coords</function>. <function>parport_device_coords</function>.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_device_num</function></funcdef> <funcdef>int <function>parport_device_num</function></funcdef>
<paramdef>int <parameter>parport</parameter></paramdef> <paramdef>int <parameter>parport</parameter></paramdef>
<paramdef>int <parameter>mux</parameter></paramdef> <paramdef>int <parameter>mux</parameter></paramdef>
<paramdef>int <parameter>daisy</parameter></paramdef> <paramdef>int <parameter>daisy</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_device_coords</function></funcdef> <funcdef>int <function>parport_device_coords</function></funcdef>
<paramdef>int <parameter>devnum</parameter></paramdef> <paramdef>int <parameter>devnum</parameter></paramdef>
<paramdef>int *<parameter>parport</parameter></paramdef> <paramdef>int *<parameter>parport</parameter></paramdef>
<paramdef>int *<parameter>mux</parameter></paramdef> <paramdef>int *<parameter>mux</parameter></paramdef>
<paramdef>int *<parameter>daisy</parameter></paramdef> <paramdef>int *<parameter>daisy</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
Any parallel port peripheral will be connected directly or Any parallel port peripheral will be connected directly or
...@@ -524,18 +531,25 @@ ...@@ -524,18 +531,25 @@
<function>parport_find_class</function>. <function>parport_find_class</function>.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_find_device</function></funcdef> <funcdef>int <function>parport_find_device</function></funcdef>
<paramdef>const char *<parameter>mfg</parameter></paramdef> <paramdef>const char *<parameter>mfg</parameter></paramdef>
<paramdef>const char *<parameter>mdl</parameter></paramdef> <paramdef>const char *<parameter>mdl</parameter></paramdef>
<paramdef>int <parameter>from</parameter></paramdef> <paramdef>int <parameter>from</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_find_class</function></funcdef> <funcdef>int <function>parport_find_class</function></funcdef>
<paramdef>parport_device_class <parameter>cls</parameter></paramdef> <paramdef>parport_device_class <parameter>cls</parameter></paramdef>
<paramdef>int <parameter>from</parameter></paramdef> <paramdef>int <parameter>from</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
These functions take a device number (in addition to some other These functions take a device number (in addition to some other
...@@ -572,7 +586,7 @@ ...@@ -572,7 +586,7 @@
This section is written from the point of view of the device driver 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 programmer, who might be writing a driver for a printer or a
scanner or else anything that plugs into the parallel port. It scanner or else anything that plugs into the parallel port. It
explains how to use the <filename>parport</filename> interface to explains how to use the <literal>parport</literal> interface to
find parallel ports, use them, and share them with other device find parallel ports, use them, and share them with other device
drivers. drivers.
</para> </para>
...@@ -585,55 +599,62 @@ ...@@ -585,55 +599,62 @@
<para> <para>
The interactions between the device driver and the The interactions between the device driver and the
<filename>parport</filename> layer are as follows. First, the <literal>parport</literal> layer are as follows. First, the
device driver registers its existence with device driver registers its existence with
<filename>parport</filename>, in order to get told about any <literal>parport</literal>, in order to get told about any
parallel ports that have been (or will be) detected. When it gets parallel ports that have been (or will be) detected. When it gets
told about a parallel port, it then tells told about a parallel port, it then tells
<filename>parport</filename> that it wants to drive a device on <literal>parport</literal> that it wants to drive a device on
that port. Thereafter it can claim exclusive access to the port in that port. Thereafter it can claim exclusive access to the port in
order to talk to its device. order to talk to its device.
</para> </para>
<para> <para>
So, the first thing for the device driver to do is tell So, the first thing for the device driver to do is tell
<filename>parport</filename> that it wants to know what parallel <literal>parport</literal> that it wants to know what parallel
ports are on the system. To do this, it uses the ports are on the system. To do this, it uses the
<function>parport_register_device</function> function: <function>parport_register_device</function> function:
</para> </para>
<programlisting> <funcsynopsis>
<![CDATA[ <funcsynopsisinfo>
#include &lt;parport.h&gt;
struct parport_driver { struct parport_driver {
const char *name; const char *name;
void (*attach) (struct parport *); void (*attach) (struct parport *);
void (*detach) (struct parport *); void (*detach) (struct parport *);
struct parport_driver *next; struct parport_driver *next;
}; };
]]></programlisting> </funcsynopsisinfo>
<funcsynopsis><funcprototype> <funcprototype>
<funcdef>int <function>parport_register_driver</function></funcdef> <funcdef>int <function>parport_register_driver</function></funcdef>
<paramdef>struct parport_driver *<parameter>driver</parameter></paramdef> <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
In other words, the device driver passes pointers to a couple of In other words, the device driver passes pointers to a couple of
functions to <filename>parport</filename>, and functions to <literal>parport</literal>, and
<filename>parport</filename> calls <function>attach</function> for <literal>parport</literal> calls <function>attach</function> for
each port that's detected (and <function>detach</function> for each each port that's detected (and <function>detach</function> for each
port that disappears---yes, this can happen). port that disappears---yes, this can happen).
</para> </para>
<para> <para>
The next thing that happens is that the device driver tells The next thing that happens is that the device driver tells
<filename>parport</filename> that it thinks there's a device on the <literal>parport</literal> that it thinks there's a device on the
port that it can drive. This typically will happen in the driver's port that it can drive. This typically will happen in the driver's
<function>attach</function> function, and is done with <function>attach</function> function, and is done with
<function>parport_register_device</function>: <function>parport_register_device</function>:
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct pardevice *<function>parport_register_device</function></funcdef> <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>name</parameter></paramdef> <paramdef>const char *<parameter>name</parameter></paramdef>
...@@ -645,7 +666,8 @@ struct parport_driver { ...@@ -645,7 +666,8 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef> <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef> <paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef> <paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
The <parameter>port</parameter> comes from the parameter supplied The <parameter>port</parameter> comes from the parameter supplied
...@@ -705,7 +727,7 @@ struct parport_driver { ...@@ -705,7 +727,7 @@ struct parport_driver {
<para> <para>
The <parameter>flags</parameter> are for telling The <parameter>flags</parameter> are for telling
<filename>parport</filename> any requirements or hints that are <literal>parport</literal> any requirements or hints that are
useful. The only useful value here (other than useful. The only useful value here (other than
<constant>0</constant>, which is the usual value) is <constant>0</constant>, which is the usual value) is
<constant>PARPORT_DEV_EXCL</constant>. The point of that flag is <constant>PARPORT_DEV_EXCL</constant>. The point of that flag is
...@@ -738,7 +760,11 @@ struct parport_driver { ...@@ -738,7 +760,11 @@ struct parport_driver {
than a pointer to a <structname>struct parport</structname>. than a pointer to a <structname>struct parport</structname>.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct pardevice *<function>parport_open</function></funcdef> <funcdef>struct pardevice *<function>parport_open</function></funcdef>
<paramdef>int <parameter>devnum</parameter></paramdef> <paramdef>int <parameter>devnum</parameter></paramdef>
<paramdef>int <parameter>(*pf)</parameter> <paramdef>int <parameter>(*pf)</parameter>
...@@ -749,14 +775,18 @@ struct parport_driver { ...@@ -749,14 +775,18 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef> <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef> <paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef> <paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_close</function></funcdef> <funcdef>void <function>parport_close</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>struct pardevice *<function>parport_register_device</function></funcdef> <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>name</parameter></paramdef> <paramdef>const char *<parameter>name</parameter></paramdef>
...@@ -768,12 +798,15 @@ struct parport_driver { ...@@ -768,12 +798,15 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef> <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef> <paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef> <paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_unregister_device</function></funcdef> <funcdef>void <function>parport_unregister_device</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
The intended use of these functions is during driver initialisation The intended use of these functions is during driver initialisation
...@@ -799,20 +832,29 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, ...@@ -799,20 +832,29 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
port. port.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_claim</function></funcdef> <funcdef>int <function>parport_claim</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_claim_or_block</function></funcdef> <funcdef>int <function>parport_claim_or_block</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_release</function></funcdef> <funcdef>void <function>parport_release</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
To claim access to the port, use <function>parport_claim</function> To claim access to the port, use <function>parport_claim</function>
...@@ -866,15 +908,22 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, ...@@ -866,15 +908,22 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
a <filename>/proc</filename> entry. a <filename>/proc</filename> entry.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_yield</function></funcdef> <funcdef>int <function>parport_yield</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_yield_blocking</function></funcdef> <funcdef>int <function>parport_yield_blocking</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
The first of these, <function>parport_yield</function>, will not The first of these, <function>parport_yield</function>, will not
...@@ -919,14 +968,14 @@ port->ops->write_data (port, d); ...@@ -919,14 +968,14 @@ port->ops->write_data (port, d);
<listitem> <listitem>
<para> <para>
The device driver registers itself with <filename>parport</filename>. The device driver registers itself with <literal>parport</literal>.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
A low-level driver finds a parallel port and registers it with A low-level driver finds a parallel port and registers it with
<filename>parport</filename> (these first two things can happen <literal>parport</literal> (these first two things can happen
in either order). This registration creates a <structname>struct in either order). This registration creates a <structname>struct
parport</structname> which is linked onto a list of known ports. parport</structname> which is linked onto a list of known ports.
</para> </para>
...@@ -934,7 +983,7 @@ port->ops->write_data (port, d); ...@@ -934,7 +983,7 @@ port->ops->write_data (port, d);
<listitem> <listitem>
<para> <para>
<filename>parport</filename> calls the <literal>parport</literal> calls the
<function>attach</function> function of each registered device <function>attach</function> function of each registered device
driver, passing it the pointer to the new <structname>struct driver, passing it the pointer to the new <structname>struct
parport</structname>. parport</structname>.
...@@ -944,7 +993,7 @@ port->ops->write_data (port, d); ...@@ -944,7 +993,7 @@ port->ops->write_data (port, d);
<listitem> <listitem>
<para> <para>
The device driver gets a handle from The device driver gets a handle from
<filename>parport</filename>, for use with <literal>parport</literal>, for use with
<function>parport_claim</function>/<function>release</function>. <function>parport_claim</function>/<function>release</function>.
This handle takes the form of a pointer to a <structname>struct This handle takes the form of a pointer to a <structname>struct
pardevice</structname>, representing a particular device on the pardevice</structname>, representing a particular device on the
...@@ -993,18 +1042,18 @@ port->ops->write_data (port, d); ...@@ -993,18 +1042,18 @@ port->ops->write_data (port, d);
<!-- Could even talk about parallel port console here. --> <!-- Could even talk about parallel port console here. -->
<para> <para>
The printer driver, <filename>lp</filename> is a character special The printer driver, <literal>lp</literal> is a character special
device driver and a <filename>parport</filename> client. As a device driver and a <literal>parport</literal> client. As a
character special device driver it registers a <structname>struct character special device driver it registers a <structname>struct
file_operations</structname> using file_operations</structname> using
<function>register_chrdev</function>, with pointers filled in for <function>register_chrdev</function>, with pointers filled in for
<structfield>write</structfield>, <structfield>ioctl</structfield>, <structfield>write</structfield>, <structfield>ioctl</structfield>,
<structfield>open</structfield> and <structfield>open</structfield> and
<structfield>release</structfield>. As a client of <structfield>release</structfield>. As a client of
<filename>parport</filename>, it registers a <structname>struct <literal>parport</literal>, it registers a <structname>struct
parport_driver</structname> using parport_driver</structname> using
<function>parport_register_driver</function>, so that <function>parport_register_driver</function>, so that
<filename>parport</filename> knows to call <literal>parport</literal> knows to call
<function>lp_attach</function> when a new parallel port is <function>lp_attach</function> when a new parallel port is
discovered (and <function>lp_detach</function> when it goes discovered (and <function>lp_detach</function> when it goes
away). away).
...@@ -1012,8 +1061,8 @@ port->ops->write_data (port, d); ...@@ -1012,8 +1061,8 @@ port->ops->write_data (port, d);
<para> <para>
The parallel port console functionality is also implemented in The parallel port console functionality is also implemented in
<filename>lp.c</filename>, but that won't be covered here (it's <filename>drivers/char/lp.c</filename>, but that won't be covered
quite simple though). here (it's quite simple though).
</para> </para>
<para> <para>
...@@ -1037,7 +1086,7 @@ port->ops->write_data (port, d); ...@@ -1037,7 +1086,7 @@ port->ops->write_data (port, d);
<para> <para>
After successfully registering itself as a character special device After successfully registering itself as a character special device
driver, the printer driver registers itself as a driver, the printer driver registers itself as a
<filename>parport</filename> client using <literal>parport</literal> client using
<function>parport_register_driver</function>. It passes a pointer <function>parport_register_driver</function>. It passes a pointer
to this structure: to this structure:
</para> </para>
...@@ -1076,14 +1125,14 @@ static struct parport_driver lp_driver = { ...@@ -1076,14 +1125,14 @@ static struct parport_driver lp_driver = {
<para> <para>
The other interesting piece of the printer driver, from the point The other interesting piece of the printer driver, from the point
of view of <filename>parport</filename>, is of view of <literal>parport</literal>, is
<function>lp_write</function>. In this function, the user space <function>lp_write</function>. In this function, the user space
process has data that it wants printed, and the printer driver process has data that it wants printed, and the printer driver
hands it off to the <filename>parport</filename> code to deal with. hands it off to the <literal>parport</literal> code to deal with.
</para> </para>
<para> <para>
The <filename>parport</filename> functions it uses that we have not The <literal>parport</literal> functions it uses that we have not
seen yet are <function>parport_negotiate</function>, seen yet are <function>parport_negotiate</function>,
<function>parport_set_timeout</function>, and <function>parport_set_timeout</function>, and
<function>parport_write</function>. These functions are part of <function>parport_write</function>. These functions are part of
...@@ -1106,11 +1155,16 @@ static struct parport_driver lp_driver = { ...@@ -1106,11 +1155,16 @@ static struct parport_driver lp_driver = {
<function>parport_negotiate</function>. <function>parport_negotiate</function>.
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_negotiate</function></funcdef> <funcdef>int <function>parport_negotiate</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>int <parameter>mode</parameter></paramdef> <paramdef>int <parameter>mode</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
The <parameter>modes</parameter> parameter is a symbolic constant The <parameter>modes</parameter> parameter is a symbolic constant
...@@ -1132,7 +1186,7 @@ static struct parport_driver lp_driver = { ...@@ -1132,7 +1186,7 @@ static struct parport_driver lp_driver = {
<para> <para>
The main work is done in the write-loop. In particular, the line The main work is done in the write-loop. In particular, the line
that hands the data over to <filename>parport</filename> reads: that hands the data over to <literal>parport</literal> reads:
</para> </para>
<programlisting> <programlisting>
...@@ -1147,19 +1201,26 @@ static struct parport_driver lp_driver = { ...@@ -1147,19 +1201,26 @@ static struct parport_driver lp_driver = {
successfully written: successfully written:
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>ssize_t <function>parport_write</function></funcdef> <funcdef>ssize_t <function>parport_write</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const void *<parameter>buf</parameter></paramdef> <paramdef>const void *<parameter>buf</parameter></paramdef>
<paramdef>size_t <parameter>len</parameter></paramdef> <paramdef>size_t <parameter>len</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcprototype>
<funcdef>ssize_t <function>parport_read</function></funcdef> <funcdef>ssize_t <function>parport_read</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>void *<parameter>buf</parameter></paramdef> <paramdef>void *<parameter>buf</parameter></paramdef>
<paramdef>size_t <parameter>len</parameter></paramdef> <paramdef>size_t <parameter>len</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
(<function>parport_read</function> does what it sounds like, but (<function>parport_read</function> does what it sounds like, but
...@@ -1186,49 +1247,106 @@ struct parport_operations { ...@@ -1186,49 +1247,106 @@ struct parport_operations {
[...] [...]
/* Block read/write */ /* Block read/write */
size_t (*epp_write_data) (struct parport *port, const void *buf, size_t (*epp_write_data) (struct parport *port,
const void *buf,
size_t len, int flags); size_t len, int flags);
size_t (*epp_read_data) (struct parport *port, void *buf, size_t len, size_t (*epp_read_data) (struct parport *port,
void *buf, size_t len,
int flags); int flags);
size_t (*epp_write_addr) (struct parport *port, const void *buf, size_t (*epp_write_addr) (struct parport *port,
const void *buf,
size_t len, int flags); size_t len, int flags);
size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len, size_t (*epp_read_addr) (struct parport *port,
void *buf, size_t len,
int flags); int flags);
size_t (*ecp_write_data) (struct parport *port, const void *buf, size_t (*ecp_write_data) (struct parport *port,
const void *buf,
size_t len, int flags); size_t len, int flags);
size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len, size_t (*ecp_read_data) (struct parport *port,
void *buf, size_t len,
int flags); int flags);
size_t (*ecp_write_addr) (struct parport *port, const void *buf, size_t (*ecp_write_addr) (struct parport *port,
const void *buf,
size_t len, int flags); size_t len, int flags);
size_t (*compat_write_data) (struct parport *port, const void *buf, size_t (*compat_write_data) (struct parport *port,
const void *buf,
size_t len, int flags); size_t len, int flags);
size_t (*nibble_read_data) (struct parport *port, void *buf, size_t (*nibble_read_data) (struct parport *port,
size_t len, int flags); void *buf, size_t len,
size_t (*byte_read_data) (struct parport *port, void *buf, int flags);
size_t len, int flags); size_t (*byte_read_data) (struct parport *port,
void *buf, size_t len,
int flags);
}; };
]]></programlisting> ]]></programlisting>
<para> <para>
The transfer code in <filename>parport</filename> will tolerate a The transfer code in <literal>parport</literal> will tolerate a
data transfer stall only for so long, and this timeout can be data transfer stall only for so long, and this timeout can be
specified with <function>parport_set_timeout</function>, which specified with <function>parport_set_timeout</function>, which
returns the previous timeout: returns the previous timeout:
</para> </para>
<funcsynopsis><funcprototype> <funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>long <function>parport_set_timeout</function></funcdef> <funcdef>long <function>parport_set_timeout</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
<paramdef>long <parameter>inactivity</parameter></paramdef> <paramdef>long <parameter>inactivity</parameter></paramdef>
</funcprototype></funcsynopsis> </funcprototype>
</funcsynopsis>
<para> <para>
This timeout is specific to the device, and is restored on This timeout is specific to the device, and is restored on
<function>parport_claim</function>. <function>parport_claim</function>.
</para> </para>
<para>
The next function to look at is the one that allows processes to
read from <filename>/dev/lp0</filename>:
<function>lp_read</function>. It's short, like
<function>lp_write</function>.
</para>
<para>
The semantics of reading from a line printer device are as follows:
</para>
<itemizedlist>
<listitem>
<para>
Switch to reverse nibble mode.
</para>
</listitem>
<listitem>
<para>
Try to read data from the peripheral using reverse nibble mode,
until either the user-provided buffer is full or the peripheral
indicates that there is no more data.
</para>
</listitem>
<listitem>
<para>
If there was data, stop, and return it.
</para>
</listitem>
<listitem>
<para>
Otherwise, we tried to read data and there was none. If the user
opened the device node with the <constant>O_NONBLOCK</constant>
flag, return. Otherwise wait until an interrupt occurs on the
port (or a timeout elapses).
</para>
</listitem>
</itemizedlist>
</chapter> </chapter>
<chapter id="ppdev"> <chapter id="ppdev">
...@@ -1260,7 +1378,7 @@ struct parport_operations { ...@@ -1260,7 +1378,7 @@ struct parport_operations {
</para> </para>
<para> <para>
In contrast, the <filename>ppdev</filename> driver (accessed via In contrast, the <literal>ppdev</literal> driver (accessed via
<filename>/dev/parport0</filename>) allows you to: <filename>/dev/parport0</filename>) allows you to:
</para> </para>
...@@ -1344,11 +1462,13 @@ struct parport_operations { ...@@ -1344,11 +1462,13 @@ struct parport_operations {
<title>Programming interface</title> <title>Programming interface</title>
<para> <para>
The <filename>ppdev</filename> interface is largely the same as The <literal>ppdev</literal> interface is largely the same as that
that of other character special devices, in that it supports of other character special devices, in that it supports
<function>open</function>, <function>close</function>, <function>open</function>, <function>close</function>,
<function>read</function>, <function>write</function>, and <function>read</function>, <function>write</function>, and
<function>ioctl</function>. <function>ioctl</function>. The constants for the
<function>ioctl</function> commands are in
<filename>include/linux/ppdev.h</filename>.
</para> </para>
<sect2> <sect2>
...@@ -1379,7 +1499,7 @@ struct parport_operations { ...@@ -1379,7 +1499,7 @@ struct parport_operations {
Most of the control is done, naturally enough, via the Most of the control is done, naturally enough, via the
<function>ioctl</function> call. Using <function>ioctl</function> call. Using
<function>ioctl</function>, the user-land driver can control both <function>ioctl</function>, the user-land driver can control both
the <filename>ppdev</filename> driver in the kernel and the the <literal>ppdev</literal> driver in the kernel and the
physical parallel port itself. The <function>ioctl</function> physical parallel port itself. The <function>ioctl</function>
call takes as parameters a file descriptor (the one returned from call takes as parameters a file descriptor (the one returned from
opening the device node), a command, and optionally (a pointer opening the device node), a command, and optionally (a pointer
...@@ -1395,7 +1515,7 @@ struct parport_operations { ...@@ -1395,7 +1515,7 @@ struct parport_operations {
writer, you will need to do this before you are able to writer, you will need to do this before you are able to
actually change the state of the parallel port in any way. actually change the state of the parallel port in any way.
Note that some operations only affect the Note that some operations only affect the
<filename>ppdev</filename> driver and not the port, such as <literal>ppdev</literal> driver and not the port, such as
<constant>PPSETMODE</constant>; they can be performed while <constant>PPSETMODE</constant>; they can be performed while
access to the port is not claimed. access to the port is not claimed.
</para> </para>
...@@ -1486,7 +1606,7 @@ struct parport_operations { ...@@ -1486,7 +1606,7 @@ struct parport_operations {
<para> <para>
The <function>ioctl</function> parameter should be a pointer The <function>ioctl</function> parameter should be a pointer
to an <type>int</type>; values for this are in to an <type>int</type>; values for this are in
<filename>parport.h</filename> and include: <filename>incluce/linux/parport.h</filename> and include:
</para> </para>
<itemizedlist spacing=compact> <itemizedlist spacing=compact>
...@@ -1566,7 +1686,7 @@ struct parport_operations { ...@@ -1566,7 +1686,7 @@ struct parport_operations {
Sets the control lines. The <function>ioctl</function> Sets the control lines. The <function>ioctl</function>
parameter is a pointer to an <type>unsigned char</type>, the parameter is a pointer to an <type>unsigned char</type>, the
bitwise OR of the control line values in bitwise OR of the control line values in
<filename>parport.h</filename>. <filename>include/linux/parport.h</filename>.
</para> </para>
</listitem></varlistentry> </listitem></varlistentry>
...@@ -1591,7 +1711,7 @@ struct parport_operations { ...@@ -1591,7 +1711,7 @@ struct parport_operations {
<para> <para>
The control lines bits are defined in The control lines bits are defined in
<filename>parport.h</filename>: <filename>include/linux/parport.h</filename>:
</para> </para>
<itemizedlist spacing=compact> <itemizedlist spacing=compact>
...@@ -1619,7 +1739,7 @@ struct parport_operations { ...@@ -1619,7 +1739,7 @@ struct parport_operations {
course, each driver could remember what state the control course, each driver could remember what state the control
lines are supposed to be in (they are never changed by lines are supposed to be in (they are never changed by
anything else), but in order to provide anything else), but in order to provide
<constant>PPRCONTROL</constant>, <filename>ppdev</filename> <constant>PPRCONTROL</constant>, <literal>ppdev</literal>
must remember the state of the control lines anyway. must remember the state of the control lines anyway.
</para> </para>
...@@ -1728,7 +1848,7 @@ struct ppdev_frob_struct { ...@@ -1728,7 +1848,7 @@ struct ppdev_frob_struct {
<listitem> <listitem>
<para> <para>
Clears the interrupt count. The <filename>ppdev</filename> Clears the interrupt count. The <literal>ppdev</literal>
driver keeps a count of interrupts as they are triggered. driver keeps a count of interrupts as they are triggered.
<constant>PPCLRIRQ</constant> stores this count in an <constant>PPCLRIRQ</constant> stores this count in an
<type>int</type>, a pointer to which is passed in as the <type>int</type>, a pointer to which is passed in as the
...@@ -1790,7 +1910,7 @@ struct ppdev_frob_struct { ...@@ -1790,7 +1910,7 @@ struct ppdev_frob_struct {
<function>select</function></title> <function>select</function></title>
<para> <para>
The <filename>ppdev</filename> driver provides user-land device The <literal>ppdev</literal> driver provides user-land device
drivers with the ability to wait for interrupts, and this is done drivers with the ability to wait for interrupts, and this is done
using <function>poll</function> (and <function>select</function>, using <function>poll</function> (and <function>select</function>,
which is implemented in terms of <function>poll</function>). which is implemented in terms of <function>poll</function>).
...@@ -1799,7 +1919,7 @@ struct ppdev_frob_struct { ...@@ -1799,7 +1919,7 @@ struct ppdev_frob_struct {
<para> <para>
When a user-land device driver wants to wait for an interrupt, it When a user-land device driver wants to wait for an interrupt, it
sleeps with <function>poll</function>. When the interrupt sleeps with <function>poll</function>. When the interrupt
arrives, <filename>ppdev</filename> wakes it up (with a arrives, <literal>ppdev</literal> wakes it up (with a
<quote>read</quote> event, although strictly speaking there is <quote>read</quote> event, although strictly speaking there is
nothing to actually <function>read</function>). nothing to actually <function>read</function>).
</para> </para>
...@@ -1813,7 +1933,7 @@ struct ppdev_frob_struct { ...@@ -1813,7 +1933,7 @@ struct ppdev_frob_struct {
<para> <para>
Presented here are two demonstrations of how to write a simple Presented here are two demonstrations of how to write a simple
printer driver for <filename>ppdev</filename>. Firstly we will printer driver for <literal>ppdev</literal>. Firstly we will
use the <function>write</function> function, and after that we use the <function>write</function> function, and after that we
will drive the control and data lines directly. will drive the control and data lines directly.
</para> </para>
...@@ -1998,7 +2118,7 @@ ssize_t write_printer (int fd, const void *ptr, size_t count) ...@@ -1998,7 +2118,7 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
]]></programlisting> ]]></programlisting>
<para> <para>
To show a bit more of the <filename>ppdev</filename> interface, To show a bit more of the <literal>ppdev</literal> interface,
here is a small piece of code that is intended to mimic the here is a small piece of code that is intended to mimic the
printer's side of printer protocol. printer's side of printer protocol.
</para> </para>
...@@ -2048,6 +2168,43 @@ ssize_t write_printer (int fd, const void *ptr, size_t count) ...@@ -2048,6 +2168,43 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
} }
]]></programlisting> ]]></programlisting>
<para>
And here is an example (with no error checking at all) to show how
to read data from the port, using ECP mode, with optional
negotiation to ECP mode first.
</para>
<programlisting><![CDATA[
{
int fd, mode;
fd = open ("/dev/parport0", O_RDONLY | O_NOCTTY);
ioctl (fd, PPCLAIM);
mode = IEEE1284_MODE_ECP;
if (negotiate_first) {
ioctl (fd, PPNEGOT, &mode);
/* no need for PPSETMODE */
} else {
ioctl (fd, PPSETMODE, &mode);
}
/* Now do whatever we want with fd */
close (0);
dup2 (fd, 0);
if (!fork()) {
/* child */
execlp ("cat", "cat", NULL);
exit (1);
} else {
/* parent */
wait (NULL);
}
/* Okay, finished */
ioctl (fd, PPRELEASE);
close (fd);
}
]]></programlisting>
</sect1> </sect1>
</chapter> </chapter>
...@@ -2078,6 +2235,85 @@ ssize_t write_printer (int fd, const void *ptr, size_t count) ...@@ -2078,6 +2235,85 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
!Fdrivers/parport/ieee1284.c parport_set_timeout !Fdrivers/parport/ieee1284.c parport_set_timeout
</appendix> </appendix>
<appendix>
<title>
The Linux 2.2 Parallel Port Subsystem
</title>
<para>
Although the interface described in this document is largely new
with the 2.4 kernel, the sharing mechanism is available in the 2.2
kernel as well. The functions available in 2.2 are:
</para>
<itemizedlist>
<listitem>
<para>
<function>parport_register_device</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_unregister_device</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_claim</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_claim_or_block</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_release</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_yield</function>
</para>
</listitem>
<listitem>
<para>
<function>parport_yield_blocking</function>
</para>
</listitem>
</itemizedlist>
<para>
In addition, negotiation to reverse nibble mode is supported:
</para>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_ieee1284_nibble_mode_ok</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>unsigned char <parameter>mode</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<para>
The only valid values for <parameter>mode</parameter> are 0 (for
reverse nibble mode) and 4 (for Device ID in reverse nibble mode).
</para>
<para>
This function is obsoleted by
<function>parport_negotiate</function> in Linux 2.4, and has been
removed.
</para>
</appendix>
</book> </book>
<!-- Local Variables: --> <!-- Local Variables: -->
......
...@@ -180,7 +180,6 @@ if [ "$CONFIG_APM" != "n" ]; then ...@@ -180,7 +180,6 @@ if [ "$CONFIG_APM" != "n" ]; then
bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
......
...@@ -132,6 +132,9 @@ ...@@ -132,6 +132,9 @@
* 1.13: Changes for new pm_ interfaces (Andy Henroid * 1.13: Changes for new pm_ interfaces (Andy Henroid
* <andy_henroid@yahoo.com>). * <andy_henroid@yahoo.com>).
* Modularize the code. * Modularize the code.
* Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
* is now the way life works).
* Fix thinko in suspend() (wrong return).
* *
* APM 1.1 Reference: * APM 1.1 Reference:
* *
...@@ -308,9 +311,7 @@ static int clock_slowed = 0; ...@@ -308,9 +311,7 @@ static int clock_slowed = 0;
#endif #endif
static int suspends_pending = 0; static int suspends_pending = 0;
static int standbys_pending = 0; static int standbys_pending = 0;
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
static int waiting_for_resume = 0; static int waiting_for_resume = 0;
#endif
#ifdef CONFIG_APM_RTC_IS_GMT #ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0 # define clock_cmos_diff 0
...@@ -866,22 +867,22 @@ static void reinit_timer(void) ...@@ -866,22 +867,22 @@ static void reinit_timer(void)
static int suspend(void) static int suspend(void)
{ {
int err; int err;
int ret;
struct apm_user *as; struct apm_user *as;
get_time_diff(); get_time_diff();
err = apm_set_power_state(APM_STATE_SUSPEND); err = apm_set_power_state(APM_STATE_SUSPEND);
reinit_timer(); reinit_timer();
set_time(); set_time();
ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR); if (err == APM_NO_ERROR)
if (!ret) err = APM_SUCCESS;
if (err != APM_SUCCESS)
apm_error("suspend", err); apm_error("suspend", err);
for (as = user_list; as != NULL; as = as->next) { for (as = user_list; as != NULL; as = as->next) {
as->suspend_wait = 0; as->suspend_wait = 0;
as->suspend_result = (ret ? 0 : -EIO); as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
} }
wake_up_interruptible(&apm_suspend_waitqueue); wake_up_interruptible(&apm_suspend_waitqueue);
return ret; return err;
} }
static void standby(void) static void standby(void)
...@@ -962,14 +963,7 @@ static void check_events(void) ...@@ -962,14 +963,7 @@ static void check_events(void)
switch (event) { switch (event) {
case APM_SYS_STANDBY: case APM_SYS_STANDBY:
case APM_USER_STANDBY: case APM_USER_STANDBY:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
if (waiting_for_resume)
break;
#endif
if (send_event(event, NULL)) { if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
#endif
if (standbys_pending <= 0) if (standbys_pending <= 0)
standby(); standby();
} }
...@@ -986,14 +980,18 @@ static void check_events(void) ...@@ -986,14 +980,18 @@ static void check_events(void)
if (ignore_bounce) if (ignore_bounce)
break; break;
#endif #endif
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND /*
* If we are already processing a SUSPEND,
* then further SUSPEND events from the BIOS
* will be ignored. We also return here to
* cope with the fact that the Thinkpads keep
* sending a SUSPEND event until something else
* happens!
*/
if (waiting_for_resume) if (waiting_for_resume)
break; return;
#endif
if (send_event(event, NULL)) { if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1; waiting_for_resume = 1;
#endif
if (suspends_pending <= 0) if (suspends_pending <= 0)
(void) suspend(); (void) suspend();
} }
...@@ -1002,9 +1000,7 @@ static void check_events(void) ...@@ -1002,9 +1000,7 @@ static void check_events(void)
case APM_NORMAL_RESUME: case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME: case APM_CRITICAL_RESUME:
case APM_STANDBY_RESUME: case APM_STANDBY_RESUME:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 0; waiting_for_resume = 0;
#endif
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
last_resume = jiffies; last_resume = jiffies;
ignore_bounce = 1; ignore_bounce = 1;
...@@ -1036,8 +1032,10 @@ static void apm_event_handler(void) ...@@ -1036,8 +1032,10 @@ static void apm_event_handler(void)
int err; int err;
if ((standbys_pending > 0) || (suspends_pending > 0)) { if ((standbys_pending > 0) || (suspends_pending > 0)) {
if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) { if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
pending_count = 4; pending_count = 4;
if (debug)
printk(KERN_DEBUG "apm: setting state busy\n");
err = apm_set_power_state(APM_STATE_BUSY); err = apm_set_power_state(APM_STATE_BUSY);
if (err) if (err)
apm_error("busy", err); apm_error("busy", err);
...@@ -1097,7 +1095,7 @@ static void apm_mainloop(void) ...@@ -1097,7 +1095,7 @@ static void apm_mainloop(void)
static int check_apm_user(struct apm_user *as, const char *func) static int check_apm_user(struct apm_user *as, const char *func)
{ {
if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
printk(KERN_ERR "apm: %s passed bad filp", func); printk(KERN_ERR "apm: %s passed bad filp\n", func);
return 1; return 1;
} }
return 0; return 0;
...@@ -1200,7 +1198,7 @@ static int do_ioctl(struct inode * inode, struct file *filp, ...@@ -1200,7 +1198,7 @@ static int do_ioctl(struct inode * inode, struct file *filp,
} else if (!send_event(APM_USER_SUSPEND, as)) } else if (!send_event(APM_USER_SUSPEND, as))
return -EAGAIN; return -EAGAIN;
if (suspends_pending <= 0) { if (suspends_pending <= 0) {
if (!suspend()) if (suspend() != APM_SUCCESS)
return -EIO; return -EIO;
} else { } else {
as->suspend_wait = 1; as->suspend_wait = 1;
...@@ -1251,7 +1249,7 @@ static int do_release(struct inode * inode, struct file * filp) ...@@ -1251,7 +1249,7 @@ static int do_release(struct inode * inode, struct file * filp)
as1 = as1->next) as1 = as1->next)
; ;
if (as1 == NULL) if (as1 == NULL)
printk(KERN_ERR "apm: filp not in user list"); printk(KERN_ERR "apm: filp not in user list\n");
else else
as1->next = as->next; as1->next = as->next;
} }
...@@ -1268,7 +1266,7 @@ static int do_open(struct inode * inode, struct file * filp) ...@@ -1268,7 +1266,7 @@ static int do_open(struct inode * inode, struct file * filp)
as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) { if (as == NULL) {
printk(KERN_ERR "apm: cannot allocate struct of size %d bytes", printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
sizeof(*as)); sizeof(*as));
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return -ENOMEM; return -ENOMEM;
......
...@@ -12,7 +12,6 @@ extern int mkiss_init_ctrl_dev(void); ...@@ -12,7 +12,6 @@ extern int mkiss_init_ctrl_dev(void);
extern int slip_init_ctrl_dev(void); extern int slip_init_ctrl_dev(void);
extern int strip_init_ctrl_dev(void); extern int strip_init_ctrl_dev(void);
extern int x25_asy_init_ctrl_dev(void); extern int x25_asy_init_ctrl_dev(void);
extern int slhc_install(void);
extern int dmascc_init(void); extern int dmascc_init(void);
extern int yam_init(void); extern int yam_init(void);
...@@ -78,22 +77,12 @@ struct net_probe pci_probes[] __initdata = { ...@@ -78,22 +77,12 @@ struct net_probe pci_probes[] __initdata = {
#endif #endif
#if defined(CONFIG_COMX) #if defined(CONFIG_COMX)
{comx_init, 0}, {comx_init, 0},
#endif /* #endif
* SLHC if present needs attaching so other people see it
* even if not opened.
*/
#if defined(CONFIG_LANMEDIA) #if defined(CONFIG_LANMEDIA)
{lmc_setup, 0}, {lmc_setup, 0},
#endif #endif
#ifdef CONFIG_INET
#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
|| defined(CONFIG_PPP) \
|| (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP))
{slhc_install, 0},
#endif
#endif
/* /*
* *
* Wireless non-HAM * Wireless non-HAM
......
...@@ -77,7 +77,6 @@ ...@@ -77,7 +77,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/init.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/slhc_vj.h> #include <net/slhc_vj.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -751,12 +750,6 @@ void cleanup_module(void) ...@@ -751,12 +750,6 @@ void cleanup_module(void)
return; return;
} }
#else /* MODULE */
int __init slhc_install(void)
{
return 0;
}
#endif /* MODULE */ #endif /* MODULE */
#else /* CONFIG_INET */ #else /* CONFIG_INET */
......
2000-05-16 Tim Waugh <twaugh@redhat.com>
* share.c (parport_claim): Fix SMP race.
2000-05-15 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de> 2000-05-15 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
* parport_pc.c (parport_pc_compat_write_block_pio): Check for * parport_pc.c (parport_pc_compat_write_block_pio): Check for
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/usb.h> #include <linux/usb.h>
static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Manolov (petkan@spct.net)\n"; static const char *version = __FILE__ ": v0.3.12 2000/05/22 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500 #define PEGASUS_MTU 1500
...@@ -24,12 +24,15 @@ static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Mano ...@@ -24,12 +24,15 @@ static const char *version = __FILE__ ": v0.3.9 2000/04/11 Written by Petko Mano
#define SROM_WRITE 0x01 #define SROM_WRITE 0x01
#define SROM_READ 0x02 #define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5) #define PEGASUS_TX_TIMEOUT (HZ*5)
#define PEGASUS_RESET 1
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) #define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
struct pegasus { struct pegasus {
struct usb_device *usb; struct usb_device *usb;
struct net_device *net; struct net_device *net;
struct net_device_stats stats; struct net_device_stats stats;
int flags;
spinlock_t pegasus_lock; spinlock_t pegasus_lock;
struct urb rx_urb, tx_urb, intr_urb; struct urb rx_urb, tx_urb, intr_urb;
unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
...@@ -44,9 +47,11 @@ struct usb_eth_dev { ...@@ -44,9 +47,11 @@ struct usb_eth_dev {
void *private; void *private;
}; };
static int loopback = 0; static int loopback = 0;
static int multicast_filter_limit = 32; static int multicast_filter_limit = 32;
MODULE_AUTHOR("Petko Manolov <petkan@spct.net>"); MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver"); MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i"); MODULE_PARM(loopback, "i");
...@@ -98,6 +103,7 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd ...@@ -98,6 +103,7 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd
return 1; return 1;
} }
static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata) static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
{ {
int i; int i;
...@@ -115,6 +121,7 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd ...@@ -115,6 +121,7 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
return 1; return 1;
} }
static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction) static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
{ {
int i; int i;
...@@ -134,6 +141,7 @@ static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retda ...@@ -134,6 +141,7 @@ static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retda
return 1; return 1;
} }
static int pegasus_get_node_id(struct usb_device *dev, __u8 *id) static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
{ {
int i; int i;
...@@ -143,6 +151,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id) ...@@ -143,6 +151,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
return 0; return 0;
} }
static int pegasus_reset_mac(struct usb_device *dev) static int pegasus_reset_mac(struct usb_device *dev)
{ {
__u8 data = 0x8; __u8 data = 0x8;
...@@ -165,6 +174,7 @@ static int pegasus_reset_mac(struct usb_device *dev) ...@@ -165,6 +174,7 @@ static int pegasus_reset_mac(struct usb_device *dev)
return 1; return 1;
} }
static int pegasus_start_net(struct net_device *dev, struct usb_device *usb) static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
{ {
__u16 partmedia, temp; __u16 partmedia, temp;
...@@ -195,13 +205,14 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb) ...@@ -195,13 +205,14 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
data[0] = 0xc9; data[0] = 0xc9;
data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0); data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
data[2] = (loopback & 1) ? 0x08 : 0x00; data[2] = (loopback & 1) ? 0x09 : 0x01;
pegasus_set_registers(usb, 0, 3, data); pegasus_set_registers(usb, 0, 3, data);
return 0; return 0;
} }
static void pegasus_read_bulk(struct urb *urb) static void pegasus_read_bulk(struct urb *urb)
{ {
struct pegasus *pegasus = urb->context; struct pegasus *pegasus = urb->context;
...@@ -253,15 +264,16 @@ static void pegasus_read_bulk(struct urb *urb) ...@@ -253,15 +264,16 @@ static void pegasus_read_bulk(struct urb *urb)
warn("(prb)failed rx_urb %d", res); warn("(prb)failed rx_urb %d", res);
} }
static void pegasus_irq(urb_t *urb) static void pegasus_irq(urb_t *urb)
{ {
if(urb->status) { __u8 *d = urb->transfer_buffer;
__u8 *d = urb->transfer_buffer;
printk("txst0 %x, txst1 %x, rxst %x, rxlst0 %x, rxlst1 %x, wakest %x", if ( d[0] )
d[0], d[1], d[2], d[3], d[4], d[5]); dbg("txst0=0x%2x", d[0]);
}
} }
static void pegasus_write_bulk(struct urb *urb) static void pegasus_write_bulk(struct urb *urb)
{ {
struct pegasus *pegasus = urb->context; struct pegasus *pegasus = urb->context;
...@@ -280,12 +292,15 @@ static void pegasus_tx_timeout(struct net_device *net) ...@@ -280,12 +292,15 @@ static void pegasus_tx_timeout(struct net_device *net)
struct pegasus *pegasus = net->priv; struct pegasus *pegasus = net->priv;
warn("%s: Tx timed out. Reseting...", net->name); warn("%s: Tx timed out. Reseting...", net->name);
usb_unlink_urb(&pegasus->tx_urb);
pegasus->stats.tx_errors++; pegasus->stats.tx_errors++;
net->trans_start = jiffies; net->trans_start = jiffies;
pegasus->flags |= PEGASUS_RESET;
netif_wake_queue(net); netif_wake_queue(net);
} }
static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
{ {
struct pegasus *pegasus = net->priv; struct pegasus *pegasus = net->priv;
...@@ -317,11 +332,13 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -317,11 +332,13 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
return 0; return 0;
} }
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
{ {
return &((struct pegasus *)dev->priv)->stats; return &((struct pegasus *)dev->priv)->stats;
} }
static int pegasus_open(struct net_device *net) static int pegasus_open(struct net_device *net)
{ {
struct pegasus *pegasus = (struct pegasus *)net->priv; struct pegasus *pegasus = (struct pegasus *)net->priv;
...@@ -334,8 +351,10 @@ static int pegasus_open(struct net_device *net) ...@@ -334,8 +351,10 @@ static int pegasus_open(struct net_device *net)
if ((res = usb_submit_urb(&pegasus->rx_urb))) if ((res = usb_submit_urb(&pegasus->rx_urb)))
warn("(open)failed rx_urb %d", res); warn("(open)failed rx_urb %d", res);
/* usb_submit_urb(&pegasus->intr_urb);*/ if ((res = usb_submit_urb(&pegasus->intr_urb)))
warn("(open)failed intr_urb %d", res);
netif_start_queue(net); netif_start_queue(net);
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -343,6 +362,7 @@ static int pegasus_open(struct net_device *net) ...@@ -343,6 +362,7 @@ static int pegasus_open(struct net_device *net)
return 0; return 0;
} }
static int pegasus_close(struct net_device *net) static int pegasus_close(struct net_device *net)
{ {
struct pegasus *pegasus = net->priv; struct pegasus *pegasus = net->priv;
...@@ -351,13 +371,14 @@ static int pegasus_close(struct net_device *net) ...@@ -351,13 +371,14 @@ static int pegasus_close(struct net_device *net)
usb_unlink_urb(&pegasus->rx_urb); usb_unlink_urb(&pegasus->rx_urb);
usb_unlink_urb(&pegasus->tx_urb); usb_unlink_urb(&pegasus->tx_urb);
/* usb_unlink_urb(&pegasus->intr_urb); */ usb_unlink_urb(&pegasus->intr_urb);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return 0; return 0;
} }
static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{ {
__u16 *data = (__u16 *)&rq->ifr_data; __u16 *data = (__u16 *)&rq->ifr_data;
...@@ -379,6 +400,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) ...@@ -379,6 +400,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
} }
} }
static void pegasus_set_rx_mode(struct net_device *net) static void pegasus_set_rx_mode(struct net_device *net)
{ {
struct pegasus *pegasus = net->priv; struct pegasus *pegasus = net->priv;
...@@ -400,6 +422,7 @@ static void pegasus_set_rx_mode(struct net_device *net) ...@@ -400,6 +422,7 @@ static void pegasus_set_rx_mode(struct net_device *net)
netif_wake_queue(net); netif_wake_queue(net);
} }
static int check_device_ids( __u16 vendor, __u16 product ) static int check_device_ids( __u16 vendor, __u16 product )
{ {
int i=0; int i=0;
...@@ -413,6 +436,7 @@ static int check_device_ids( __u16 vendor, __u16 product ) ...@@ -413,6 +436,7 @@ static int check_device_ids( __u16 vendor, __u16 product )
return -1; return -1;
} }
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{ {
struct net_device *net; struct net_device *net;
...@@ -463,7 +487,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -463,7 +487,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk, pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
pegasus); pegasus);
FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
pegasus->intr_buff, 8, pegasus_irq, pegasus, 250); pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name); printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
...@@ -471,6 +495,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) ...@@ -471,6 +495,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
return pegasus; return pegasus;
} }
static void pegasus_disconnect(struct usb_device *dev, void *ptr) static void pegasus_disconnect(struct usb_device *dev, void *ptr)
{ {
struct pegasus *pegasus = ptr; struct pegasus *pegasus = ptr;
...@@ -487,11 +512,12 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr) ...@@ -487,11 +512,12 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
usb_unlink_urb(&pegasus->rx_urb); usb_unlink_urb(&pegasus->rx_urb);
usb_unlink_urb(&pegasus->tx_urb); usb_unlink_urb(&pegasus->tx_urb);
/* usb_unlink_urb(&pegasus->intr_urb);*/ usb_unlink_urb(&pegasus->intr_urb);
kfree(pegasus); kfree(pegasus);
} }
static struct usb_driver pegasus_driver = { static struct usb_driver pegasus_driver = {
name: "pegasus", name: "pegasus",
probe: pegasus_probe, probe: pegasus_probe,
......
...@@ -4,8 +4,26 @@ ...@@ -4,8 +4,26 @@
O_TARGET := usb-serial.o O_TARGET := usb-serial.o
M_OBJS := usb-serial.o M_OBJS := usb-serial.o
O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o digi_acceleport.o O_OBJS := usbserial.o
MOD_LIST_NAME := USB_SERIAL_MODULES MOD_LIST_NAME := USB_SERIAL_MODULES
ifeq ($(CONFIG_USB_SERIAL_VISOR),y)
O_OBJS += visor.o
endif
ifeq ($(CONFIG_USB_SERIAL_WHITEHEAT),y)
O_OBJS += whiteheat.o
endif
ifeq ($(CONFIG_USB_SERIAL_FTDI_SIO),y)
O_OBJS += ftdi_sio.o
endif
ifeq ($(CONFIG_USB_SERIAL_KEYSPAN_PDA),y)
O_OBJS += keyspan_pda.o
endif
ifeq ($(CONFIG_USB_SERIAL_OMNINET),y)
O_OBJS += omninet.o
endif
ifeq ($(CONFIG_USB_SERIAL_DIGI_ACCELEPORT),y)
O_OBJS += digi_acceleport.o
endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -47,9 +47,6 @@ ...@@ -47,9 +47,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -1276,4 +1273,3 @@ dbg( "digi_read_oob: opcode=%d, line=%d, status=%d, ret=%d", oob_opcode, oob_lin ...@@ -1276,4 +1273,3 @@ dbg( "digi_read_oob: opcode=%d, line=%d, status=%d, ret=%d", oob_opcode, oob_lin
} }
#endif /* CONFIG_USB_SERIAL_DIGI_ACCELEPORT */
...@@ -32,9 +32,6 @@ ...@@ -32,9 +32,6 @@
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_FTDI_SIO
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -723,6 +720,3 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns ...@@ -723,6 +720,3 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
return 0; return 0;
} /* ftdi_sio_ioctl */ } /* ftdi_sio_ioctl */
#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -700,4 +697,3 @@ struct usb_serial_device_type keyspan_pda_device = { ...@@ -700,4 +697,3 @@ struct usb_serial_device_type keyspan_pda_device = {
shutdown: keyspan_pda_shutdown, shutdown: keyspan_pda_shutdown,
}; };
#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
...@@ -13,9 +13,6 @@ ...@@ -13,9 +13,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_OMNINET
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -336,6 +333,3 @@ static void omninet_write_bulk_callback (struct urb *urb) ...@@ -336,6 +333,3 @@ static void omninet_write_bulk_callback (struct urb *urb)
return; return;
} }
#endif /* CONFIG_USB_SERIAL_OMNINET */
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * See Documentation/usb/usb-serial.txt for more information on using this driver
* *
* (05/22/2000) gkh
* Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
* removed from the individual device source files.
*
* (05/03/2000) gkh * (05/03/2000) gkh
* Added the Digi Acceleport driver from Al Borchers and Peter Berger. * Added the Digi Acceleport driver from Al Borchers and Peter Berger.
* *
......
...@@ -20,9 +20,6 @@ ...@@ -20,9 +20,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_VISOR
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -207,7 +204,3 @@ static int visor_startup (struct usb_serial *serial) ...@@ -207,7 +204,3 @@ static int visor_startup (struct usb_serial *serial)
return (0); return (0);
} }
#endif /* CONFIG_USB_SERIAL_VISOR*/
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -407,6 +404,3 @@ static void whiteheat_shutdown (struct usb_serial *serial) ...@@ -407,6 +404,3 @@ static void whiteheat_shutdown (struct usb_serial *serial)
return; return;
} }
#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
...@@ -92,7 +92,6 @@ static void urb_rm_priv (urb_t * urb) ...@@ -92,7 +92,6 @@ static void urb_rm_priv (urb_t * urb)
kfree (urb->hcpriv); kfree (urb->hcpriv);
urb->hcpriv = NULL; urb->hcpriv = NULL;
wake_up (&op_wakeup);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -493,6 +492,8 @@ static int sohci_submit_urb (urb_t * urb) ...@@ -493,6 +492,8 @@ static int sohci_submit_urb (urb_t * urb)
urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1):
(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff; (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
} }
urb->status = USB_ST_URB_PENDING;
urb->actual_length = 0;
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */ if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed); ep_link (ohci, ed);
...@@ -527,6 +528,8 @@ static int sohci_unlink_urb (urb_t * urb) ...@@ -527,6 +528,8 @@ static int sohci_unlink_urb (urb_t * urb)
urb_print (urb, "UNLINK", 1); urb_print (urb, "UNLINK", 1);
#endif #endif
usb_dec_dev_use (urb->dev);
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */ return rh_unlink_urb (urb); /* a request to the virtual root hub */
...@@ -544,19 +547,23 @@ static int sohci_unlink_urb (urb_t * urb) ...@@ -544,19 +547,23 @@ static int sohci_unlink_urb (urb_t * urb)
ep_rm_ed (urb->dev, urb_priv->ed); ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL; urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags); spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
add_wait_queue (&op_wakeup, &wait); add_wait_queue (&op_wakeup, &wait);
current->state = TASK_UNINTERRUPTIBLE; current->state = TASK_UNINTERRUPTIBLE;
if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
err("unlink URB timeout!"); err("unlink URB timeout!");
remove_wait_queue (&op_wakeup, &wait); remove_wait_queue (&op_wakeup, &wait);
} else urb->status = -ENOENT;
} else
urb->status = -EINPROGRESS;
} else {
urb_rm_priv (urb); urb_rm_priv (urb);
if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
urb->status = -ENOENT; // mark urb as killed urb->complete (urb);
if (urb->complete) urb->status = 0;
urb->complete ((struct urb *) urb); } else
usb_dec_dev_use (urb->dev); urb->status = -ENOENT;
}
} }
return 0; return 0;
} }
...@@ -965,7 +972,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed) ...@@ -965,7 +972,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
/* prepare a TD */ /* prepare a TD */
static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type, int index) static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index)
{ {
volatile td_t * td, * td_pt; volatile td_t * td, * td_pt;
urb_priv_t * urb_priv = urb->hcpriv; urb_priv_t * urb_priv = urb->hcpriv;
...@@ -982,7 +989,6 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int t ...@@ -982,7 +989,6 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int t
td->index = index; td->index = index;
td->urb = urb; td->urb = urb;
td->hwINFO = cpu_to_le32 (info); td->hwINFO = cpu_to_le32 (info);
td->type = type;
if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) { if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
td->hwCBP = cpu_to_le32 (((!data || !len)? td->hwCBP = cpu_to_le32 (((!data || !len)?
0 : virt_to_bus (data)) & 0xFFFFF000); 0 : virt_to_bus (data)) & 0xFFFFF000);
...@@ -1029,12 +1035,12 @@ static void td_submit_urb (urb_t * urb) ...@@ -1029,12 +1035,12 @@ static void td_submit_urb (urb_t * urb)
info = usb_pipeout (urb->pipe)? info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
while(data_len > 4096) { while(data_len > 4096) {
td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt); td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
data += 4096; data_len -= 4096; cnt++; data += 4096; data_len -= 4096; cnt++;
} }
info = usb_pipeout (urb->pipe)? info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt); td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
cnt++; cnt++;
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break; break;
...@@ -1042,20 +1048,20 @@ static void td_submit_urb (urb_t * urb) ...@@ -1042,20 +1048,20 @@ static void td_submit_urb (urb_t * urb)
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)? info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle; TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++); td_fill (info, data, data_len, urb, cnt++);
break; break;
case PIPE_CONTROL: case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0; info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++); td_fill (info, ctrl, 8, urb, cnt++);
if (data_len > 0) { if (data_len > 0) {
info = usb_pipeout (urb->pipe)? info = usb_pipeout (urb->pipe)?
TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1; TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
td_fill (info, data, data_len, urb, ADD_LEN, cnt++); td_fill (info, data, data_len, urb, cnt++);
} }
info = usb_pipeout (urb->pipe)? info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (info, NULL, 0, urb, 0, cnt++); td_fill (info, NULL, 0, urb, cnt++);
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break; break;
...@@ -1063,7 +1069,7 @@ static void td_submit_urb (urb_t * urb) ...@@ -1063,7 +1069,7 @@ static void td_submit_urb (urb_t * urb)
for (cnt = 0; cnt < urb->number_of_packets; cnt++) { for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
(__u8 *) data + urb->iso_frame_desc[cnt].offset, (__u8 *) data + urb->iso_frame_desc[cnt].offset,
urb->iso_frame_desc[cnt].length, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt); urb->iso_frame_desc[cnt].length, urb, cnt);
} }
break; break;
} }
...@@ -1074,7 +1080,55 @@ static void td_submit_urb (urb_t * urb) ...@@ -1074,7 +1080,55 @@ static void td_submit_urb (urb_t * urb)
/*-------------------------------------------------------------------------* /*-------------------------------------------------------------------------*
* Done List handling functions * Done List handling functions
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
/* calculate the transfer length and update the urb */
static void dl_transfer_length(td_t * td)
{
__u32 tdINFO, tdBE, tdCBP;
__u16 tdPSW;
urb_t * urb = td->urb;
urb_priv_t * urb_priv = urb->hcpriv;
int dlen = 0;
int cc = 0;
tdINFO = le32_to_cpup (&td->hwINFO);
tdBE = le32_to_cpup (&td->hwBE);
tdCBP = le32_to_cpup (&td->hwCBP);
if (tdINFO & TD_ISO) {
tdPSW = le16_to_cpu (td->hwPSW[0]);
cc = (tdPSW >> 12) & 0xF;
if (cc < 0xE) {
if (usb_pipeout(urb->pipe)) {
dlen = urb->iso_frame_desc[td->index].length;
} else {
dlen = tdPSW & 0x3ff;
}
urb->actual_length += dlen;
urb->iso_frame_desc[td->index].actual_length = dlen;
if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
cc = TD_CC_NOERROR;
urb->iso_frame_desc[td->index].status = cc_to_error[cc];
}
} else { /* BULK, INT, CONTROL DATA */
if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
((td->index == 0) || (td->index == urb_priv->length - 1)))) {
if (tdBE != 0) {
if (td->hwCBP == 0)
urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
else
urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
}
}
}
}
/*-------------------------------------------------------------------------*/
/* replies to the request have to be on a FIFO basis so /* replies to the request have to be on a FIFO basis so
* we reverse the reversed done-list */ * we reverse the reversed done-list */
...@@ -1128,6 +1182,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) ...@@ -1128,6 +1182,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
unsigned long flags; unsigned long flags;
ed_t * ed; ed_t * ed;
__u32 edINFO; __u32 edINFO;
__u32 tdINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP; td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
__u32 * td_p; __u32 * td_p;
int ctrl = 0, bulk = 0; int ctrl = 0, bulk = 0;
...@@ -1139,16 +1194,25 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) ...@@ -1139,16 +1194,25 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0); tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
edINFO = le32_to_cpup (&ed->hwINFO); edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP; td_p = &ed->hwHeadP;
for (td = tdHeadP; td != tdTailP; td = td_next) { for (td = tdHeadP; td != tdTailP; td = td_next) {
urb_t * urb = td->urb; urb_t * urb = td->urb;
urb_priv_t * urb_priv = td->urb->hcpriv; urb_priv_t * urb_priv = td->urb->hcpriv;
td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0); td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) { if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3)); *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
if(++ (urb_priv->td_cnt) == urb_priv->length) if(++ (urb_priv->td_cnt) == urb_priv->length)
urb_rm_priv (urb); urb_rm_priv (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
usb_dec_dev_use (urb->dev);
urb->status = -ECONNRESET;
urb->complete (urb);
} else {
wake_up (&op_wakeup);
}
} else { } else {
td_p = &td->hwNextTD; td_p = &td->hwNextTD;
} }
...@@ -1165,7 +1229,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) ...@@ -1165,7 +1229,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
} }
else { else {
ed->state &= ~ED_URB_DEL; ed->state &= ~ED_URB_DEL;
ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP); ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
} }
if ((ed->type & 3) == CTRL) ctrl |= 1; if ((ed->type & 3) == CTRL) ctrl |= 1;
...@@ -1183,6 +1247,8 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) ...@@ -1183,6 +1247,8 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
spin_unlock_irqrestore (&usb_ed_lock, flags); spin_unlock_irqrestore (&usb_ed_lock, flags);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* td done list */ /* td done list */
...@@ -1191,12 +1257,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list) ...@@ -1191,12 +1257,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
{ {
td_t * td_list_next = NULL; td_t * td_list_next = NULL;
ed_t * ed; ed_t * ed;
int dlen = 0;
int cc = 0; int cc = 0;
urb_t * urb; urb_t * urb;
urb_priv_t * urb_priv; urb_priv_t * urb_priv;
__u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP; __u32 tdINFO, edHeadP, edTailP;
__u16 tdPSW;
unsigned long flags; unsigned long flags;
while (td_list) { while (td_list) {
...@@ -1205,40 +1270,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list) ...@@ -1205,40 +1270,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
urb = td_list->urb; urb = td_list->urb;
urb_priv = urb->hcpriv; urb_priv = urb->hcpriv;
tdINFO = le32_to_cpup (&td_list->hwINFO); tdINFO = le32_to_cpup (&td_list->hwINFO);
tdBE = le32_to_cpup (&td_list->hwBE);
tdCBP = le32_to_cpup (&td_list->hwCBP);
ed = td_list->ed; ed = td_list->ed;
if (td_list->type & ST_ADDR) dl_transfer_length(td_list);
urb->actual_length = 0;
if (td_list->type & ADD_LEN) { /* accumulate length of multi td transfers */
if (tdINFO & TD_ISO) {
tdPSW = le16_to_cpu (td_list->hwPSW[0]);
cc = (tdPSW >> 12) & 0xF;
if (cc < 0xE) {
if (usb_pipeout(urb->pipe)) {
dlen = urb->iso_frame_desc[td_list->index].length;
} else {
dlen = tdPSW & 0x3ff;
}
urb->actual_length += dlen;
urb->iso_frame_desc[td_list->index].actual_length = dlen;
if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
cc = TD_CC_NOERROR;
urb->iso_frame_desc[td_list->index].status = cc_to_error[cc];
}
} else {
if (tdBE != 0) {
if (td_list->hwCBP == 0)
urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
else
urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
}
}
}
/* error code of transfer */ /* error code of transfer */
cc = TD_CC_GET (tdINFO); cc = TD_CC_GET (tdINFO);
if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
......
...@@ -432,7 +432,7 @@ static int ep_unlink(ohci_t * ohci, ed_t * ed); ...@@ -432,7 +432,7 @@ static int ep_unlink(ohci_t * ohci, ed_t * ed);
static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load); static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed); static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
/* td */ /* td */
static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type, int index); static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index);
static void td_submit_urb(urb_t * urb); static void td_submit_urb(urb_t * urb);
/* root hub */ /* root hub */
static int rh_submit_urb(urb_t * urb); static int rh_submit_urb(urb_t * urb);
......
...@@ -84,15 +84,17 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod ...@@ -84,15 +84,17 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
#define NEXT_BUFFER(_ix) ((_ix) ^ 1) #define NEXT_BUFFER(_ix) ((_ix) ^ 1)
/* /*
* BLKS_PER_BUF_SHIFT must be at least 1 to allow for "compressed" * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
* data that takes up more space than the original. 1 is guaranteed * data that takes up more space than the original and with unlucky
* to suffice, though. Larger values provide more read-ahead and * alignment.
* proportionally less wastage at the end of the buffer.
*/ */
#define BLKS_PER_BUF_SHIFT (2) #define BLKS_PER_BUF_SHIFT (2)
#define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT) #define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT)
static unsigned char read_buffers[READ_BUFFERS][BLKS_PER_BUF][PAGE_CACHE_SIZE]; #define BUFFER_SIZE (BLKS_PER_BUF*PAGE_CACHE_SIZE)
static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
static unsigned buffer_blocknr[READ_BUFFERS]; static unsigned buffer_blocknr[READ_BUFFERS];
static struct super_block * buffer_dev[READ_BUFFERS];
static int next_buffer = 0; static int next_buffer = 0;
/* /*
...@@ -102,19 +104,27 @@ static int next_buffer = 0; ...@@ -102,19 +104,27 @@ static int next_buffer = 0;
static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
{ {
struct buffer_head * bh_array[BLKS_PER_BUF]; struct buffer_head * bh_array[BLKS_PER_BUF];
unsigned i, blocknr, last_blocknr, buffer; unsigned i, blocknr, buffer;
char *data;
if (!len) if (!len)
return NULL; return NULL;
blocknr = offset >> PAGE_CACHE_SHIFT; blocknr = offset >> PAGE_CACHE_SHIFT;
last_blocknr = (offset + len - 1) >> PAGE_CACHE_SHIFT;
if (last_blocknr - blocknr >= BLKS_PER_BUF)
goto eek; resume:
offset &= PAGE_CACHE_SIZE - 1; offset &= PAGE_CACHE_SIZE - 1;
/* Check if an existing buffer already has the data.. */
for (i = 0; i < READ_BUFFERS; i++) { for (i = 0; i < READ_BUFFERS; i++) {
if ((blocknr >= buffer_blocknr[i]) && unsigned int blk_offset;
(last_blocknr - buffer_blocknr[i] < BLKS_PER_BUF))
return &read_buffers[i][blocknr - buffer_blocknr[i]][offset]; if (buffer_dev[i] != sb)
continue;
if (blocknr < buffer_blocknr[i])
continue;
blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
blk_offset += offset;
if (blk_offset + len > BUFFER_SIZE)
continue;
return read_buffers[i] + blk_offset;
} }
/* Ok, read in BLKS_PER_BUF pages completely first. */ /* Ok, read in BLKS_PER_BUF pages completely first. */
...@@ -125,24 +135,18 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i ...@@ -125,24 +135,18 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
buffer = next_buffer; buffer = next_buffer;
next_buffer = NEXT_BUFFER(buffer); next_buffer = NEXT_BUFFER(buffer);
buffer_blocknr[buffer] = blocknr; buffer_blocknr[buffer] = blocknr;
buffer_dev[buffer] = sb;
data = read_buffers[buffer];
for (i = 0; i < BLKS_PER_BUF; i++) { for (i = 0; i < BLKS_PER_BUF; i++) {
struct buffer_head * bh = bh_array[i]; struct buffer_head * bh = bh_array[i];
if (bh) { if (bh) {
memcpy(read_buffers[buffer][i], bh->b_data, PAGE_CACHE_SIZE); memcpy(data, bh->b_data, PAGE_CACHE_SIZE);
bforget(bh); bforget(bh);
} else } else
memset(read_buffers[buffer][i], 0, PAGE_CACHE_SIZE); memset(data, 0, PAGE_CACHE_SIZE);
data += PAGE_CACHE_SIZE;
} }
return read_buffers[buffer][0] + offset; return read_buffers[buffer] + offset;
eek:
printk(KERN_ERR
"cramfs (device %s): requested chunk (%u:+%u) bigger than buffer\n",
bdevname(sb->s_dev), offset, len);
/* TODO: return EIO to process or kill the current process
instead of resuming. */
*((int *)0) = 0; /* XXX: doesn't work on all archs */
goto resume;
} }
......
#ifndef __NET_SLHC_H
#define __NET_SLHC_H
extern void slhc_install(void);
#endif
...@@ -118,6 +118,7 @@ EXPORT_SYMBOL(kfree); ...@@ -118,6 +118,7 @@ EXPORT_SYMBOL(kfree);
EXPORT_SYMBOL(kfree_s); EXPORT_SYMBOL(kfree_s);
EXPORT_SYMBOL(vmalloc); EXPORT_SYMBOL(vmalloc);
EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(vfree);
EXPORT_SYMBOL(__vmalloc);
EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(mem_map);
EXPORT_SYMBOL(remap_page_range); EXPORT_SYMBOL(remap_page_range);
EXPORT_SYMBOL(max_mapnr); EXPORT_SYMBOL(max_mapnr);
......
...@@ -79,7 +79,6 @@ ...@@ -79,7 +79,6 @@
#include <linux/brlock.h> #include <linux/brlock.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <net/slhc.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment