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
backlight at all, or it might print a lot of errors to the console,
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
CONFIG_APM_IGNORE_SUSPEND_BOUNCE
This option is necessary on the Dell Inspiron 3200 and others, but
......
......@@ -62,7 +62,7 @@
<para>
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
writing, via <function>write</function>, and configuration and
statistics reporting via <function>ioctl</function>.
......@@ -152,7 +152,7 @@
-->
<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
ports, of port-sharing between devices with pass-through ports,
and of lack of support for IEEE 1284 transfer modes.
......@@ -161,7 +161,7 @@
<!-- platform differences -->
<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.
The other layer deals with sharing and IEEE 1284 transfer modes.
In this way, parallel support for a particular architecture comes
......@@ -172,13 +172,13 @@
<!-- sharing model -->
<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
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
access has been granted. When it has finished a
<quote>transaction</quote>, it can tell the
<filename>parport</filename> layer that it may release the port
<literal>parport</literal> layer that it may release the port
for other device drivers to use.
</para>
......@@ -299,10 +299,10 @@
<title>Sharing core</title>
<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
<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
interested in new ports, and whether or not each port is available
for use (or if not, which driver is currently using it).
......@@ -314,10 +314,10 @@
<title>Parports and their overrides</title>
<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
by <quote>low-level</quote> <filename>parport</filename> drivers.
The function of a low-level <filename>parport</filename> driver is
by <quote>low-level</quote> <literal>parport</literal> drivers.
The function of a low-level <literal>parport</literal> driver is
to detect parallel ports, register them with the sharing code, and
provide a list of access functions for each port.
</para>
......@@ -340,11 +340,11 @@
<para>
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
use, and are very much like library routines. Since these
transfer functions are provided by the generic
<filename>parport</filename> core they must use the <quote>lowest
<literal>parport</literal> core they must use the <quote>lowest
common denominator</quote> set of access functions: they can set
the control lines, examine the status lines, and use the data
lines. With some parallel ports the data lines can only be set
......@@ -356,7 +356,7 @@
</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
list. The low-level driver can just name the generic IEEE 1284
transfer functions for this. Some parallel ports can do IEEE 1284
......@@ -373,7 +373,7 @@
<para>
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>.
The information is put into a <structname>struct
parport_driver</structname>, which is put into a linked list. The
......@@ -441,7 +441,7 @@
the draft specifies the on-the-wire protocol for daisy-chaining
and multiplexing, and also suggests a programming interface for
using it. That interface (or most of it) has been implemented in
the <filename>parport</filename> code in Linux.
the <literal>parport</literal> code in Linux.
</para>
<para>
......@@ -494,20 +494,27 @@
<function>parport_device_coords</function>.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_device_num</function></funcdef>
<paramdef>int <parameter>parport</parameter></paramdef>
<paramdef>int <parameter>mux</parameter></paramdef>
<paramdef>int <parameter>daisy</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_device_coords</function></funcdef>
<paramdef>int <parameter>devnum</parameter></paramdef>
<paramdef>int *<parameter>parport</parameter></paramdef>
<paramdef>int *<parameter>mux</parameter></paramdef>
<paramdef>int *<parameter>daisy</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
Any parallel port peripheral will be connected directly or
......@@ -524,18 +531,25 @@
<function>parport_find_class</function>.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_find_device</function></funcdef>
<paramdef>const char *<parameter>mfg</parameter></paramdef>
<paramdef>const char *<parameter>mdl</parameter></paramdef>
<paramdef>int <parameter>from</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_find_class</function></funcdef>
<paramdef>parport_device_class <parameter>cls</parameter></paramdef>
<paramdef>int <parameter>from</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
These functions take a device number (in addition to some other
......@@ -572,7 +586,7 @@
This section is written from the point of view of the device driver
programmer, who might be writing a driver for a printer or a
scanner or else anything that plugs into the parallel port. It
explains how to use the <filename>parport</filename> interface to
explains how to use the <literal>parport</literal> interface to
find parallel ports, use them, and share them with other device
drivers.
</para>
......@@ -585,55 +599,62 @@
<para>
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
<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
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
order to talk to its device.
</para>
<para>
So, the first thing for the device driver to do is tell
<filename>parport</filename> that it wants to know what parallel
<literal>parport</literal> that it wants to know what parallel
ports are on the system. To do this, it uses the
<function>parport_register_device</function> function:
</para>
<programlisting>
<![CDATA[
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
struct parport_driver {
const char *name;
void (*attach) (struct parport *);
void (*detach) (struct parport *);
struct parport_driver *next;
};
]]></programlisting>
</funcsynopsisinfo>
<funcsynopsis><funcprototype>
<funcprototype>
<funcdef>int <function>parport_register_driver</function></funcdef>
<paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
In other words, the device driver passes pointers to a couple of
functions to <filename>parport</filename>, and
<filename>parport</filename> calls <function>attach</function> for
functions to <literal>parport</literal>, and
<literal>parport</literal> calls <function>attach</function> for
each port that's detected (and <function>detach</function> for each
port that disappears---yes, this can happen).
</para>
<para>
The next thing that happens is that the device driver tells
<filename>parport</filename> that it thinks there's a device on the
<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
<function>attach</function> function, and is done with
<function>parport_register_device</function>:
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
......@@ -645,7 +666,8 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
The <parameter>port</parameter> comes from the parameter supplied
......@@ -705,7 +727,7 @@ struct parport_driver {
<para>
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
<constant>0</constant>, which is the usual value) is
<constant>PARPORT_DEV_EXCL</constant>. The point of that flag is
......@@ -738,7 +760,11 @@ struct parport_driver {
than a pointer to a <structname>struct parport</structname>.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>struct pardevice *<function>parport_open</function></funcdef>
<paramdef>int <parameter>devnum</parameter></paramdef>
<paramdef>int <parameter>(*pf)</parameter>
......@@ -749,14 +775,18 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_close</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>struct pardevice *<function>parport_register_device</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
......@@ -768,12 +798,15 @@ struct parport_driver {
<funcparams>int, void *, struct pt_regs *</funcparams></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>handle</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_unregister_device</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
The intended use of these functions is during driver initialisation
......@@ -799,20 +832,29 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
port.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_claim</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_claim_or_block</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>void <function>parport_release</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
To claim access to the port, use <function>parport_claim</function>
......@@ -866,15 +908,22 @@ while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM,
a <filename>/proc</filename> entry.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_yield</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>parport_yield_blocking</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
The first of these, <function>parport_yield</function>, will not
......@@ -919,14 +968,14 @@ port->ops->write_data (port, d);
<listitem>
<para>
The device driver registers itself with <filename>parport</filename>.
The device driver registers itself with <literal>parport</literal>.
</para>
</listitem>
<listitem>
<para>
A low-level driver finds a parallel port and registers it with
<filename>parport</filename> (these first two things can happen
<literal>parport</literal> (these first two things can happen
in either order). This registration creates a <structname>struct
parport</structname> which is linked onto a list of known ports.
</para>
......@@ -934,7 +983,7 @@ port->ops->write_data (port, d);
<listitem>
<para>
<filename>parport</filename> calls the
<literal>parport</literal> calls the
<function>attach</function> function of each registered device
driver, passing it the pointer to the new <structname>struct
parport</structname>.
......@@ -944,7 +993,7 @@ port->ops->write_data (port, d);
<listitem>
<para>
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>.
This handle takes the form of a pointer to a <structname>struct
pardevice</structname>, representing a particular device on the
......@@ -993,18 +1042,18 @@ port->ops->write_data (port, d);
<!-- Could even talk about parallel port console here. -->
<para>
The printer driver, <filename>lp</filename> is a character special
device driver and a <filename>parport</filename> client. As a
The printer driver, <literal>lp</literal> is a character special
device driver and a <literal>parport</literal> client. As a
character special device driver it registers a <structname>struct
file_operations</structname> using
<function>register_chrdev</function>, with pointers filled in for
<structfield>write</structfield>, <structfield>ioctl</structfield>,
<structfield>open</structfield> and
<structfield>release</structfield>. As a client of
<filename>parport</filename>, it registers a <structname>struct
<literal>parport</literal>, it registers a <structname>struct
parport_driver</structname> using
<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
discovered (and <function>lp_detach</function> when it goes
away).
......@@ -1012,8 +1061,8 @@ port->ops->write_data (port, d);
<para>
The parallel port console functionality is also implemented in
<filename>lp.c</filename>, but that won't be covered here (it's
quite simple though).
<filename>drivers/char/lp.c</filename>, but that won't be covered
here (it's quite simple though).
</para>
<para>
......@@ -1037,7 +1086,7 @@ port->ops->write_data (port, d);
<para>
After successfully registering itself as a character special device
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
to this structure:
</para>
......@@ -1076,14 +1125,14 @@ static struct parport_driver lp_driver = {
<para>
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
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>
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>,
<function>parport_set_timeout</function>, and
<function>parport_write</function>. These functions are part of
......@@ -1106,11 +1155,16 @@ static struct parport_driver lp_driver = {
<function>parport_negotiate</function>.
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>parport_negotiate</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>int <parameter>mode</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
The <parameter>modes</parameter> parameter is a symbolic constant
......@@ -1132,7 +1186,7 @@ static struct parport_driver lp_driver = {
<para>
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>
<programlisting>
......@@ -1147,19 +1201,26 @@ static struct parport_driver lp_driver = {
successfully written:
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>ssize_t <function>parport_write</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>const void *<parameter>buf</parameter></paramdef>
<paramdef>size_t <parameter>len</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcprototype>
<funcdef>ssize_t <function>parport_read</function></funcdef>
<paramdef>struct parport *<parameter>port</parameter></paramdef>
<paramdef>void *<parameter>buf</parameter></paramdef>
<paramdef>size_t <parameter>len</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
(<function>parport_read</function> does what it sounds like, but
......@@ -1186,49 +1247,106 @@ struct parport_operations {
[...]
/* 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 (*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);
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 (*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);
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 (*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);
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 (*compat_write_data) (struct parport *port, const void *buf,
size_t len, int flags);
size_t (*nibble_read_data) (struct parport *port, void *buf,
size_t len, int flags);
size_t (*byte_read_data) (struct parport *port, void *buf,
size_t (*compat_write_data) (struct parport *port,
const void *buf,
size_t len, int flags);
size_t (*nibble_read_data) (struct parport *port,
void *buf, size_t len,
int flags);
size_t (*byte_read_data) (struct parport *port,
void *buf, size_t len,
int flags);
};
]]></programlisting>
<para>
The transfer code in <filename>parport</filename> will tolerate a
The transfer code in <literal>parport</literal> will tolerate a
data transfer stall only for so long, and this timeout can be
specified with <function>parport_set_timeout</function>, which
returns the previous timeout:
</para>
<funcsynopsis><funcprototype>
<funcsynopsis>
<funcsynopsisinfo>
#include &lt;parport.h&gt;
</funcsynopsisinfo>
<funcprototype>
<funcdef>long <function>parport_set_timeout</function></funcdef>
<paramdef>struct pardevice *<parameter>dev</parameter></paramdef>
<paramdef>long <parameter>inactivity</parameter></paramdef>
</funcprototype></funcsynopsis>
</funcprototype>
</funcsynopsis>
<para>
This timeout is specific to the device, and is restored on
<function>parport_claim</function>.
</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 id="ppdev">
......@@ -1260,7 +1378,7 @@ struct parport_operations {
</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:
</para>
......@@ -1344,11 +1462,13 @@ struct parport_operations {
<title>Programming interface</title>
<para>
The <filename>ppdev</filename> interface is largely the same as
that of other character special devices, in that it supports
The <literal>ppdev</literal> interface is largely the same as that
of other character special devices, in that it supports
<function>open</function>, <function>close</function>,
<function>read</function>, <function>write</function>, and
<function>ioctl</function>.
<function>ioctl</function>. The constants for the
<function>ioctl</function> commands are in
<filename>include/linux/ppdev.h</filename>.
</para>
<sect2>
......@@ -1379,7 +1499,7 @@ struct parport_operations {
Most of the control is done, naturally enough, via the
<function>ioctl</function> call. Using
<function>ioctl</function>, the user-land driver can control both
the <filename>ppdev</filename> driver in the kernel and the
the <literal>ppdev</literal> driver in the kernel and the
physical parallel port itself. The <function>ioctl</function>
call takes as parameters a file descriptor (the one returned from
opening the device node), a command, and optionally (a pointer
......@@ -1395,7 +1515,7 @@ struct parport_operations {
writer, you will need to do this before you are able to
actually change the state of the parallel port in any way.
Note that some operations only affect the
<filename>ppdev</filename> driver and not the port, such as
<literal>ppdev</literal> driver and not the port, such as
<constant>PPSETMODE</constant>; they can be performed while
access to the port is not claimed.
</para>
......@@ -1486,7 +1606,7 @@ struct parport_operations {
<para>
The <function>ioctl</function> parameter should be a pointer
to an <type>int</type>; values for this are in
<filename>parport.h</filename> and include:
<filename>incluce/linux/parport.h</filename> and include:
</para>
<itemizedlist spacing=compact>
......@@ -1566,7 +1686,7 @@ struct parport_operations {
Sets the control lines. The <function>ioctl</function>
parameter is a pointer to an <type>unsigned char</type>, the
bitwise OR of the control line values in
<filename>parport.h</filename>.
<filename>include/linux/parport.h</filename>.
</para>
</listitem></varlistentry>
......@@ -1591,7 +1711,7 @@ struct parport_operations {
<para>
The control lines bits are defined in
<filename>parport.h</filename>:
<filename>include/linux/parport.h</filename>:
</para>
<itemizedlist spacing=compact>
......@@ -1619,7 +1739,7 @@ struct parport_operations {
course, each driver could remember what state the control
lines are supposed to be in (they are never changed by
anything else), but in order to provide
<constant>PPRCONTROL</constant>, <filename>ppdev</filename>
<constant>PPRCONTROL</constant>, <literal>ppdev</literal>
must remember the state of the control lines anyway.
</para>
......@@ -1728,7 +1848,7 @@ struct ppdev_frob_struct {
<listitem>
<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.
<constant>PPCLRIRQ</constant> stores this count in an
<type>int</type>, a pointer to which is passed in as the
......@@ -1790,7 +1910,7 @@ struct ppdev_frob_struct {
<function>select</function></title>
<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
using <function>poll</function> (and <function>select</function>,
which is implemented in terms of <function>poll</function>).
......@@ -1799,7 +1919,7 @@ struct ppdev_frob_struct {
<para>
When a user-land device driver wants to wait for an interrupt, it
sleeps with <function>poll</function>. When the interrupt
arrives, <filename>ppdev</filename> wakes it up (with a
arrives, <literal>ppdev</literal> wakes it up (with a
<quote>read</quote> event, although strictly speaking there is
nothing to actually <function>read</function>).
</para>
......@@ -1813,7 +1933,7 @@ struct ppdev_frob_struct {
<para>
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
will drive the control and data lines directly.
</para>
......@@ -1998,7 +2118,7 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
]]></programlisting>
<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
printer's side of printer protocol.
</para>
......@@ -2048,6 +2168,43 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
}
]]></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>
</chapter>
......@@ -2078,6 +2235,85 @@ ssize_t write_printer (int fd, const void *ptr, size_t count)
!Fdrivers/parport/ieee1284.c parport_set_timeout
</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>
<!-- Local Variables: -->
......
......@@ -180,7 +180,6 @@ if [ "$CONFIG_APM" != "n" ]; then
bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
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 ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
......
......@@ -132,6 +132,9 @@
* 1.13: Changes for new pm_ interfaces (Andy Henroid
* <andy_henroid@yahoo.com>).
* 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:
*
......@@ -308,9 +311,7 @@ static int clock_slowed = 0;
#endif
static int suspends_pending = 0;
static int standbys_pending = 0;
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
static int waiting_for_resume = 0;
#endif
#ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0
......@@ -866,22 +867,22 @@ static void reinit_timer(void)
static int suspend(void)
{
int err;
int ret;
struct apm_user *as;
get_time_diff();
err = apm_set_power_state(APM_STATE_SUSPEND);
reinit_timer();
set_time();
ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
if (!ret)
if (err == APM_NO_ERROR)
err = APM_SUCCESS;
if (err != APM_SUCCESS)
apm_error("suspend", err);
for (as = user_list; as != NULL; as = as->next) {
as->suspend_wait = 0;
as->suspend_result = (ret ? 0 : -EIO);
as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
}
wake_up_interruptible(&apm_suspend_waitqueue);
return ret;
return err;
}
static void standby(void)
......@@ -962,14 +963,7 @@ static void check_events(void)
switch (event) {
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
if (waiting_for_resume)
break;
#endif
if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
#endif
if (standbys_pending <= 0)
standby();
}
......@@ -986,14 +980,18 @@ static void check_events(void)
if (ignore_bounce)
break;
#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)
break;
#endif
return;
if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
#endif
if (suspends_pending <= 0)
(void) suspend();
}
......@@ -1002,9 +1000,7 @@ static void check_events(void)
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
case APM_STANDBY_RESUME:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 0;
#endif
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
last_resume = jiffies;
ignore_bounce = 1;
......@@ -1036,8 +1032,10 @@ static void apm_event_handler(void)
int err;
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;
if (debug)
printk(KERN_DEBUG "apm: setting state busy\n");
err = apm_set_power_state(APM_STATE_BUSY);
if (err)
apm_error("busy", err);
......@@ -1097,7 +1095,7 @@ static void apm_mainloop(void)
static int check_apm_user(struct apm_user *as, const char *func)
{
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 0;
......@@ -1200,7 +1198,7 @@ static int do_ioctl(struct inode * inode, struct file *filp,
} else if (!send_event(APM_USER_SUSPEND, as))
return -EAGAIN;
if (suspends_pending <= 0) {
if (!suspend())
if (suspend() != APM_SUCCESS)
return -EIO;
} else {
as->suspend_wait = 1;
......@@ -1251,7 +1249,7 @@ static int do_release(struct inode * inode, struct file * filp)
as1 = as1->next)
;
if (as1 == NULL)
printk(KERN_ERR "apm: filp not in user list");
printk(KERN_ERR "apm: filp not in user list\n");
else
as1->next = as->next;
}
......@@ -1268,7 +1266,7 @@ static int do_open(struct inode * inode, struct file * filp)
as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
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));
MOD_DEC_USE_COUNT;
return -ENOMEM;
......
......@@ -12,7 +12,6 @@ extern int mkiss_init_ctrl_dev(void);
extern int slip_init_ctrl_dev(void);
extern int strip_init_ctrl_dev(void);
extern int x25_asy_init_ctrl_dev(void);
extern int slhc_install(void);
extern int dmascc_init(void);
extern int yam_init(void);
......@@ -78,20 +77,10 @@ struct net_probe pci_probes[] __initdata = {
#endif
#if defined(CONFIG_COMX)
{comx_init, 0},
#endif /*
* SLHC if present needs attaching so other people see it
* even if not opened.
*/
#if defined(CONFIG_LANMEDIA)
{lmc_setup, 0},
#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
#if defined(CONFIG_LANMEDIA)
{lmc_setup, 0},
#endif
/*
......
......@@ -77,7 +77,6 @@
#include <linux/timer.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <net/checksum.h>
#include <net/slhc_vj.h>
#include <asm/unaligned.h>
......@@ -751,12 +750,6 @@ void cleanup_module(void)
return;
}
#else /* MODULE */
int __init slhc_install(void)
{
return 0;
}
#endif /* MODULE */
#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>
* parport_pc.c (parport_pc_compat_write_block_pio): Check for
......
......@@ -16,7 +16,7 @@
#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
......@@ -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_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
#define PEGASUS_RESET 1
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
struct pegasus {
struct usb_device *usb;
struct net_device *net;
struct net_device_stats stats;
int flags;
spinlock_t pegasus_lock;
struct urb rx_urb, tx_urb, intr_urb;
unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
......@@ -44,9 +47,11 @@ struct usb_eth_dev {
void *private;
};
static int loopback = 0;
static int multicast_filter_limit = 32;
MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
......@@ -98,6 +103,7 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd
return 1;
}
static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
{
int i;
......@@ -115,6 +121,7 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
return 1;
}
static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
......@@ -134,6 +141,7 @@ static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retda
return 1;
}
static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
{
int i;
......@@ -143,6 +151,7 @@ static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
return 0;
}
static int pegasus_reset_mac(struct usb_device *dev)
{
__u8 data = 0x8;
......@@ -165,6 +174,7 @@ static int pegasus_reset_mac(struct usb_device *dev)
return 1;
}
static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
{
__u16 partmedia, temp;
......@@ -195,13 +205,14 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
data[0] = 0xc9;
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);
return 0;
}
static void pegasus_read_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
......@@ -253,15 +264,16 @@ static void pegasus_read_bulk(struct urb *urb)
warn("(prb)failed rx_urb %d", res);
}
static void pegasus_irq(urb_t *urb)
{
if(urb->status) {
__u8 *d = urb->transfer_buffer;
printk("txst0 %x, txst1 %x, rxst %x, rxlst0 %x, rxlst1 %x, wakest %x",
d[0], d[1], d[2], d[3], d[4], d[5]);
}
if ( d[0] )
dbg("txst0=0x%2x", d[0]);
}
static void pegasus_write_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
......@@ -280,12 +292,15 @@ static void pegasus_tx_timeout(struct net_device *net)
struct pegasus *pegasus = net->priv;
warn("%s: Tx timed out. Reseting...", net->name);
usb_unlink_urb(&pegasus->tx_urb);
pegasus->stats.tx_errors++;
net->trans_start = jiffies;
pegasus->flags |= PEGASUS_RESET;
netif_wake_queue(net);
}
static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
{
struct pegasus *pegasus = net->priv;
......@@ -317,11 +332,13 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
return 0;
}
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
{
return &((struct pegasus *)dev->priv)->stats;
}
static int pegasus_open(struct net_device *net)
{
struct pegasus *pegasus = (struct pegasus *)net->priv;
......@@ -335,7 +352,9 @@ static int pegasus_open(struct net_device *net)
if ((res = usb_submit_urb(&pegasus->rx_urb)))
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);
MOD_INC_USE_COUNT;
......@@ -343,6 +362,7 @@ static int pegasus_open(struct net_device *net)
return 0;
}
static int pegasus_close(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
......@@ -351,13 +371,14 @@ static int pegasus_close(struct net_device *net)
usb_unlink_urb(&pegasus->rx_urb);
usb_unlink_urb(&pegasus->tx_urb);
/* usb_unlink_urb(&pegasus->intr_urb); */
usb_unlink_urb(&pegasus->intr_urb);
MOD_DEC_USE_COUNT;
return 0;
}
static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
__u16 *data = (__u16 *)&rq->ifr_data;
......@@ -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)
{
struct pegasus *pegasus = net->priv;
......@@ -400,6 +422,7 @@ static void pegasus_set_rx_mode(struct net_device *net)
netif_wake_queue(net);
}
static int check_device_ids( __u16 vendor, __u16 product )
{
int i=0;
......@@ -413,6 +436,7 @@ static int check_device_ids( __u16 vendor, __u16 product )
return -1;
}
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
......@@ -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);
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);
......@@ -471,6 +495,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
return pegasus;
}
static void pegasus_disconnect(struct usb_device *dev, void *ptr)
{
struct pegasus *pegasus = 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->tx_urb);
/* usb_unlink_urb(&pegasus->intr_urb);*/
usb_unlink_urb(&pegasus->intr_urb);
kfree(pegasus);
}
static struct usb_driver pegasus_driver = {
name: "pegasus",
probe: pegasus_probe,
......
......@@ -4,8 +4,26 @@
O_TARGET := 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
include $(TOPDIR)/Rules.make
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
......@@ -47,9 +47,6 @@
*/
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_DIGI_ACCELEPORT
#include <linux/kernel.h>
#include <linux/sched.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
}
#endif /* CONFIG_USB_SERIAL_DIGI_ACCELEPORT */
......@@ -32,9 +32,6 @@
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_FTDI_SIO
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......@@ -723,6 +720,3 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
return 0;
} /* ftdi_sio_ioctl */
#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
......@@ -18,9 +18,6 @@
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......@@ -700,4 +697,3 @@ struct usb_serial_device_type keyspan_pda_device = {
shutdown: keyspan_pda_shutdown,
};
#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
......@@ -13,9 +13,6 @@
*/
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_OMNINET
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......@@ -336,6 +333,3 @@ static void omninet_write_bulk_callback (struct urb *urb)
return;
}
#endif /* CONFIG_USB_SERIAL_OMNINET */
......@@ -14,6 +14,10 @@
*
* 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
* Added the Digi Acceleport driver from Al Borchers and Peter Berger.
*
......
......@@ -20,9 +20,6 @@
*/
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_VISOR
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......@@ -207,7 +204,3 @@ static int visor_startup (struct usb_serial *serial)
return (0);
}
#endif /* CONFIG_USB_SERIAL_VISOR*/
......@@ -21,9 +21,6 @@
*/
#include <linux/config.h>
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......@@ -407,6 +404,3 @@ static void whiteheat_shutdown (struct usb_serial *serial)
return;
}
#endif /* CONFIG_USB_SERIAL_WHITEHEAT */
......@@ -92,7 +92,6 @@ static void urb_rm_priv (urb_t * urb)
kfree (urb->hcpriv);
urb->hcpriv = NULL;
wake_up (&op_wakeup);
}
/*-------------------------------------------------------------------------*/
......@@ -493,6 +492,8 @@ static int sohci_submit_urb (urb_t * urb)
urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1):
(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 */
ep_link (ohci, ed);
......@@ -527,6 +528,8 @@ static int sohci_unlink_urb (urb_t * urb)
urb_print (urb, "UNLINK", 1);
#endif
usb_dec_dev_use (urb->dev);
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
......@@ -544,19 +547,23 @@ static int sohci_unlink_urb (urb_t * urb)
ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
add_wait_queue (&op_wakeup, &wait);
current->state = TASK_UNINTERRUPTIBLE;
if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
err("unlink URB timeout!");
remove_wait_queue (&op_wakeup, &wait);
urb->status = -ENOENT;
} else
urb->status = -EINPROGRESS;
} else {
urb_rm_priv (urb);
urb->status = -ENOENT; // mark urb as killed
if (urb->complete)
urb->complete ((struct urb *) urb);
usb_dec_dev_use (urb->dev);
if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
urb->complete (urb);
urb->status = 0;
} else
urb->status = -ENOENT;
}
}
return 0;
}
......@@ -965,7 +972,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
/* 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;
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
td->index = index;
td->urb = urb;
td->hwINFO = cpu_to_le32 (info);
td->type = type;
if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
td->hwCBP = cpu_to_le32 (((!data || !len)?
0 : virt_to_bus (data)) & 0xFFFFF000);
......@@ -1029,12 +1035,12 @@ static void td_submit_urb (urb_t * urb)
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
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++;
}
info = usb_pipeout (urb->pipe)?
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++;
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break;
......@@ -1042,20 +1048,20 @@ static void td_submit_urb (urb_t * urb)
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
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;
case PIPE_CONTROL:
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) {
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_fill (info, data, data_len, urb, ADD_LEN, cnt++);
td_fill (info, data, data_len, urb, cnt++);
}
info = usb_pipeout (urb->pipe)?
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 */
break;
......@@ -1063,7 +1069,7 @@ static void td_submit_urb (urb_t * urb)
for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
(__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;
}
......@@ -1075,6 +1081,54 @@ static void td_submit_urb (urb_t * urb)
* 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
* we reverse the reversed done-list */
......@@ -1128,6 +1182,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
unsigned long flags;
ed_t * ed;
__u32 edINFO;
__u32 tdINFO;
td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
__u32 * td_p;
int ctrl = 0, bulk = 0;
......@@ -1146,9 +1201,18 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
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));
if(++ (urb_priv->td_cnt) == urb_priv->length)
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 {
td_p = &td->hwNextTD;
}
......@@ -1183,6 +1247,8 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
/*-------------------------------------------------------------------------*/
/* td done list */
......@@ -1191,12 +1257,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
{
td_t * td_list_next = NULL;
ed_t * ed;
int dlen = 0;
int cc = 0;
urb_t * urb;
urb_priv_t * urb_priv;
__u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
__u16 tdPSW;
__u32 tdINFO, edHeadP, edTailP;
unsigned long flags;
while (td_list) {
......@@ -1205,40 +1270,11 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
urb = td_list->urb;
urb_priv = urb->hcpriv;
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;
if (td_list->type & ST_ADDR)
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;
dl_transfer_length(td_list);
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 */
cc = TD_CC_GET (tdINFO);
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);
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);
/* 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);
/* root hub */
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
#define NEXT_BUFFER(_ix) ((_ix) ^ 1)
/*
* BLKS_PER_BUF_SHIFT must be at least 1 to allow for "compressed"
* data that takes up more space than the original. 1 is guaranteed
* to suffice, though. Larger values provide more read-ahead and
* proportionally less wastage at the end of the buffer.
* BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
* data that takes up more space than the original and with unlucky
* alignment.
*/
#define BLKS_PER_BUF_SHIFT (2)
#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 struct super_block * buffer_dev[READ_BUFFERS];
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)
{
struct buffer_head * bh_array[BLKS_PER_BUF];
unsigned i, blocknr, last_blocknr, buffer;
unsigned i, blocknr, buffer;
char *data;
if (!len)
return NULL;
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;
/* Check if an existing buffer already has the data.. */
for (i = 0; i < READ_BUFFERS; i++) {
if ((blocknr >= buffer_blocknr[i]) &&
(last_blocknr - buffer_blocknr[i] < BLKS_PER_BUF))
return &read_buffers[i][blocknr - buffer_blocknr[i]][offset];
unsigned int blk_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. */
......@@ -125,24 +135,18 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
buffer = next_buffer;
next_buffer = NEXT_BUFFER(buffer);
buffer_blocknr[buffer] = blocknr;
buffer_dev[buffer] = sb;
data = read_buffers[buffer];
for (i = 0; i < BLKS_PER_BUF; i++) {
struct buffer_head * bh = bh_array[i];
if (bh) {
memcpy(read_buffers[buffer][i], bh->b_data, PAGE_CACHE_SIZE);
memcpy(data, bh->b_data, PAGE_CACHE_SIZE);
bforget(bh);
} 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;
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;
return read_buffers[buffer] + offset;
}
......
#ifndef __NET_SLHC_H
#define __NET_SLHC_H
extern void slhc_install(void);
#endif
......@@ -118,6 +118,7 @@ EXPORT_SYMBOL(kfree);
EXPORT_SYMBOL(kfree_s);
EXPORT_SYMBOL(vmalloc);
EXPORT_SYMBOL(vfree);
EXPORT_SYMBOL(__vmalloc);
EXPORT_SYMBOL(mem_map);
EXPORT_SYMBOL(remap_page_range);
EXPORT_SYMBOL(max_mapnr);
......
......@@ -79,7 +79,6 @@
#include <linux/brlock.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <net/slhc.h>
#include <linux/proc_fs.h>
#include <linux/stat.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