drivers/block: Remove PARIDE core and high-level protocols

Remove PARIDE core and high level protocols, taking care not to break
low-level drivers (used by pata_parport). Also update documentation.

Signed-off-by: Ondrej Zary <linux@zary.sk>
Acked-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
This commit is contained in:
Ondrej Zary 2023-01-30 22:10:49 +01:00 committed by Damien Le Moal
parent 246a1c4c6b
commit 7750d8b510
33 changed files with 115 additions and 6359 deletions

View File

@ -2,10 +2,8 @@
Linux and parallel port IDE devices
===================================
Most of this document describes the old paride driver. For the new libata
pata_parport drivrer, jump to the section 4 at the end.
PARIDE v1.03 (c) 1997-8 Grant Guenther <grant@torque.net>
PATA_PARPORT (c) 2023 Ondrej Zary
1. Introduction
===============
@ -54,27 +52,15 @@ parallel port IDE subsystem, including:
as well as most of the clone and no-name products on the market.
To support such a wide range of devices, PARIDE, the parallel port IDE
subsystem, is actually structured in three parts. There is a base
paride module which provides a registry and some common methods for
accessing the parallel ports. The second component is a set of
high-level drivers for each of the different types of supported devices:
To support such a wide range of devices, pata_parport is actually structured
in two parts. There is a base pata_parport module which provides an interface
to kernel libata subsystem, registry and some common methods for accessing
the parallel ports.
=== =============
pd IDE disk
pcd ATAPI CD-ROM
pf ATAPI disk
pt ATAPI tape
pg ATAPI generic
=== =============
(Currently, the pg driver is only used with CD-R drives).
The high-level drivers function according to the relevant standards.
The third component of PARIDE is a set of low-level protocol drivers
for each of the parallel port IDE adapter chips. Thanks to the interest
and encouragement of Linux users from many parts of the world,
support is available for almost all known adapter protocols:
The second component is a set of low-level protocol drivers for each of the
parallel port IDE adapter chips. Thanks to the interest and encouragement of
Linux users from many parts of the world, support is available for almost all
known adapter protocols:
==== ====================================== ====
aten ATEN EH-100 (HK)
@ -94,361 +80,42 @@ support is available for almost all known adapter protocols:
==== ====================================== ====
2. Using the PARIDE subsystem
=============================
2. Using pata_parport subsystem
===============================
While configuring the Linux kernel, you may choose either to build
the PARIDE drivers into your kernel, or to build them as modules.
the pata_parport drivers into your kernel, or to build them as modules.
In either case, you will need to select "Parallel port IDE device support"
as well as at least one of the high-level drivers and at least one
of the parallel port communication protocols. If you do not know
what kind of parallel port adapter is used in your drive, you could
begin by checking the file names and any text files on your DOS
and at least one of the parallel port communication protocols.
If you do not know what kind of parallel port adapter is used in your drive,
you could begin by checking the file names and any text files on your DOS
installation floppy. Alternatively, you can look at the markings on
the adapter chip itself. That's usually sufficient to identify the
correct device.
You can actually select all the protocol modules, and allow the PARIDE
You can actually select all the protocol modules, and allow the pata_parport
subsystem to try them all for you.
For the "brand-name" products listed above, here are the protocol
and high-level drivers that you would use:
================ ============ ====== ========
Manufacturer Model Driver Protocol
================ ============ ====== ========
MicroSolutions CD-ROM pcd bpck
MicroSolutions PD drive pf bpck
MicroSolutions hard-drive pd bpck
MicroSolutions 8000t tape pt bpck
SyQuest EZ, SparQ pd epat
Imation Superdisk pf epat
Maxell Superdisk pf friq
Avatar Shark pd epat
FreeCom CD-ROM pcd frpw
Hewlett-Packard 5GB Tape pt epat
Hewlett-Packard 7200e (CD) pcd epat
Hewlett-Packard 7200e (CD-R) pg epat
================ ============ ====== ========
2.1 Configuring built-in drivers
---------------------------------
We recommend that you get to know how the drivers work and how to
configure them as loadable modules, before attempting to compile a
kernel with the drivers built-in.
If you built all of your PARIDE support directly into your kernel,
and you have just a single parallel port IDE device, your kernel should
locate it automatically for you. If you have more than one device,
you may need to give some command line options to your bootloader
(eg: LILO), how to do that is beyond the scope of this document.
The high-level drivers accept a number of command line parameters, all
of which are documented in the source files in linux/drivers/block/paride.
By default, each driver will automatically try all parallel ports it
can find, and all protocol types that have been installed, until it finds
a parallel port IDE adapter. Once it finds one, the probe stops. So,
if you have more than one device, you will need to tell the drivers
how to identify them. This requires specifying the port address, the
protocol identification number and, for some devices, the drive's
chain ID. While your system is booting, a number of messages are
displayed on the console. Like all such messages, they can be
reviewed with the 'dmesg' command. Among those messages will be
some lines like::
paride: bpck registered as protocol 0
paride: epat registered as protocol 1
The numbers will always be the same until you build a new kernel with
different protocol selections. You should note these numbers as you
will need them to identify the devices.
If you happen to be using a MicroSolutions backpack device, you will
also need to know the unit ID number for each drive. This is usually
the last two digits of the drive's serial number (but read MicroSolutions'
documentation about this).
As an example, let's assume that you have a MicroSolutions PD/CD drive
with unit ID number 36 connected to the parallel port at 0x378, a SyQuest
EZ-135 connected to the chained port on the PD/CD drive and also an
Imation Superdisk connected to port 0x278. You could give the following
options on your boot command::
pd.drive0=0x378,1 pf.drive0=0x278,1 pf.drive1=0x378,0,36
In the last option, pf.drive1 configures device /dev/pf1, the 0x378
is the parallel port base address, the 0 is the protocol registration
number and 36 is the chain ID.
Please note: while PARIDE will work both with and without the
PARPORT parallel port sharing system that is included by the
"Parallel port support" option, PARPORT must be included and enabled
if you want to use chains of devices on the same parallel port.
2.2 Loading and configuring PARIDE as modules
----------------------------------------------
It is much faster and simpler to get to understand the PARIDE drivers
if you use them as loadable kernel modules.
Note 1:
using these drivers with the "kerneld" automatic module loading
system is not recommended for beginners, and is not documented here.
Note 2:
if you build PARPORT support as a loadable module, PARIDE must
also be built as loadable modules, and PARPORT must be loaded before
the PARIDE modules.
To use PARIDE, you must begin by::
insmod paride
this loads a base module which provides a registry for the protocols,
among other tasks.
Then, load as many of the protocol modules as you think you might need.
As you load each module, it will register the protocols that it supports,
and print a log message to your kernel log file and your console. For
example::
# insmod epat
paride: epat registered as protocol 0
# insmod kbic
paride: k951 registered as protocol 1
paride: k971 registered as protocol 2
Finally, you can load high-level drivers for each kind of device that
you have connected. By default, each driver will autoprobe for a single
device, but you can support up to four similar devices by giving their
individual coordinates when you load the driver.
For example, if you had two no-name CD-ROM drives both using the
KingByte KBIC-951A adapter, one on port 0x378 and the other on 0x3bc
you could give the following command::
# insmod pcd drive0=0x378,1 drive1=0x3bc,1
For most adapters, giving a port address and protocol number is sufficient,
but check the source files in linux/drivers/block/paride for more
information. (Hopefully someone will write some man pages one day !).
As another example, here's what happens when PARPORT is installed, and
a SyQuest EZ-135 is attached to port 0x378::
# insmod paride
paride: version 1.0 installed
# insmod epat
paride: epat registered as protocol 0
# insmod pd
pd: pd version 1.0, major 45, cluster 64, nice 0
pda: Sharing parport1 at 0x378
pda: epat 1.0, Shuttle EPAT chip c3 at 0x378, mode 5 (EPP-32), delay 1
pda: SyQuest EZ135A, 262144 blocks [128M], (512/16/32), removable media
pda: pda1
Note that the last line is the output from the generic partition table
scanner - in this case it reports that it has found a disk with one partition.
2.3 Using a PARIDE device
--------------------------
Once the drivers have been loaded, you can access PARIDE devices in the
same way as their traditional counterparts. You will probably need to
create the device "special files". Here is a simple script that you can
cut to a file and execute::
#!/bin/bash
#
# mkd -- a script to create the device special files for the PARIDE subsystem
#
function mkdev {
mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
}
#
function pd {
D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
mkdev pd$D b 45 $[ $1 * 16 ]
for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
done
}
#
cd /dev
#
for u in 0 1 2 3 ; do pd $u ; done
for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
#
# end of mkd
With the device files and drivers in place, you can access PARIDE devices
like any other Linux device. For example, to mount a CD-ROM in pcd0, use::
mount /dev/pcd0 /cdrom
If you have a fresh Avatar Shark cartridge, and the drive is pda, you
might do something like::
fdisk /dev/pda -- make a new partition table with
partition 1 of type 83
mke2fs /dev/pda1 -- to build the file system
mkdir /shark -- make a place to mount the disk
mount /dev/pda1 /shark
Devices like the Imation superdisk work in the same way, except that
they do not have a partition table. For example to make a 120MB
floppy that you could share with a DOS system::
mkdosfs /dev/pf0
mount /dev/pf0 /mnt
2.4 The pf driver
------------------
The pf driver is intended for use with parallel port ATAPI disk
devices. The most common devices in this category are PD drives
and LS-120 drives. Traditionally, media for these devices are not
partitioned. Consequently, the pf driver does not support partitioned
media. This may be changed in a future version of the driver.
2.5 Using the pt driver
------------------------
The pt driver for parallel port ATAPI tape drives is a minimal driver.
It does not yet support many of the standard tape ioctl operations.
For best performance, a block size of 32KB should be used. You will
probably want to set the parallel port delay to 0, if you can.
2.6 Using the pg driver
------------------------
The pg driver can be used in conjunction with the cdrecord program
to create CD-ROMs. Please get cdrecord version 1.6.1 or later
from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . To record CD-R media
your parallel port should ideally be set to EPP mode, and the "port delay"
should be set to 0. With those settings it is possible to record at 2x
speed without any buffer underruns. If you cannot get the driver to work
in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
3. Troubleshooting
==================
3.1 Use EPP mode if you can
----------------------------
The most common problems that people report with the PARIDE drivers
concern the parallel port CMOS settings. At this time, none of the
PARIDE protocol modules support ECP mode, or any ECP combination modes.
If you are able to do so, please set your parallel port into EPP mode
using your CMOS setup procedure.
3.2 Check the port delay
-------------------------
Some parallel ports cannot reliably transfer data at full speed. To
offset the errors, the PARIDE protocol modules introduce a "port
delay" between each access to the i/o ports. Each protocol sets
a default value for this delay. In most cases, the user can override
the default and set it to 0 - resulting in somewhat higher transfer
rates. In some rare cases (especially with older 486 systems) the
default delays are not long enough. if you experience corrupt data
transfers, or unexpected failures, you may wish to increase the
port delay. The delay can be programmed using the "driveN" parameters
to each of the high-level drivers. Please see the notes above, or
read the comments at the beginning of the driver source files in
linux/drivers/block/paride.
3.3 Some drives need a printer reset
-------------------------------------
There appear to be a number of "noname" external drives on the market
that do not always power up correctly. We have noticed this with some
drives based on OnSpec and older Freecom adapters. In these rare cases,
the adapter can often be reinitialised by issuing a "printer reset" on
the parallel port. As the reset operation is potentially disruptive in
multiple device environments, the PARIDE drivers will not do it
automatically. You can however, force a printer reset by doing::
insmod lp reset=1
rmmod lp
If you have one of these marginal cases, you should probably build
your paride drivers as modules, and arrange to do the printer reset
before loading the PARIDE drivers.
3.4 Use the verbose option and dmesg if you need help
------------------------------------------------------
While a lot of testing has gone into these drivers to make them work
as smoothly as possible, problems will arise. If you do have problems,
please check all the obvious things first: does the drive work in
DOS with the manufacturer's drivers ? If that doesn't yield any useful
clues, then please make sure that only one drive is hooked to your system,
and that either (a) PARPORT is enabled or (b) no other device driver
is using your parallel port (check in /proc/ioports). Then, load the
appropriate drivers (you can load several protocol modules if you want)
as in::
# insmod paride
# insmod epat
# insmod bpck
# insmod kbic
...
# insmod pd verbose=1
(using the correct driver for the type of device you have, of course).
The verbose=1 parameter will cause the drivers to log a trace of their
activity as they attempt to locate your drive.
Use 'dmesg' to capture a log of all the PARIDE messages (any messages
beginning with paride:, a protocol module's name or a driver's name) and
include that with your bug report. You can submit a bug report in one
of two ways. Either send it directly to the author of the PARIDE suite,
by e-mail to grant@torque.net, or join the linux-parport mailing list
and post your report there.
3.5 For more information or help
---------------------------------
You can join the linux-parport mailing list by sending a mail message
to:
linux-parport-request@torque.net
with the single word::
subscribe
in the body of the mail message (not in the subject line). Please be
sure that your mail program is correctly set up when you do this, as
the list manager is a robot that will subscribe you using the reply
address in your mail headers. REMOVE any anti-spam gimmicks you may
have in your mail headers, when sending mail to the list server.
You might also find some useful information on the linux-parport
web pages (although they are not always up to date) at
http://web.archive.org/web/%2E/http://www.torque.net/parport/
4. pata_parport driver
======================
pata_parport is a libata-based driver that uses the same low-level protocol
drivers as PARIDE but there are no high-level drivers (pd, pcd, pf, pt, pg).
The IDE devices behind parallel port adapters are handled by the ATA layer.
The device creation is also changed - no protocol numbers or parport I/O
addresses are used.
================ ============ ========
Manufacturer Model Protocol
================ ============ ========
MicroSolutions CD-ROM bpck
MicroSolutions PD drive bpck
MicroSolutions hard-drive bpck
MicroSolutions 8000t tape bpck
SyQuest EZ, SparQ epat
Imation Superdisk epat
Maxell Superdisk friq
Avatar Shark epat
FreeCom CD-ROM frpw
Hewlett-Packard 5GB Tape epat
Hewlett-Packard 7200e (CD) epat
Hewlett-Packard 7200e (CD-R) epat
================ ============ ========
All parports and all protocol drivers are probed automatically unless probe=0
parameter is used. So just "modprobe epat" is enough for a Imation SuperDisk
@ -464,10 +131,15 @@ where:
port parport name (or "auto" for all parports)
protocol protocol name (or "auto" for all protocols)
mode mode number (protocol-specific) or -1 for probe
unit unit number (see the paride documentation above)
delay I/O delay (see the paride documentation above)
unit unit number (for backpack only, see below)
delay I/O delay (see troubleshooting section below)
======== ================================================
If you happen to be using a MicroSolutions backpack device, you will
also need to know the unit ID number for each drive. This is usually
the last two digits of the drive's serial number (but read MicroSolutions'
documentation about this).
If you omit the parameters from the end, defaults will be used, e.g.:
Probe all parports with all protocols::
@ -489,3 +161,47 @@ Probe all parports using protoocol epat::
Deleting devices::
# echo pata_parport.0 >/sys/bus/pata_parport/delete_device
3. Troubleshooting
==================
3.1 Use EPP mode if you can
----------------------------
The most common problems that people report with the pata_parport drivers
concern the parallel port CMOS settings. At this time, none of the
protocol modules support ECP mode, or any ECP combination modes.
If you are able to do so, please set your parallel port into EPP mode
using your CMOS setup procedure.
3.2 Check the port delay
-------------------------
Some parallel ports cannot reliably transfer data at full speed. To
offset the errors, the protocol modules introduce a "port
delay" between each access to the i/o ports. Each protocol sets
a default value for this delay. In most cases, the user can override
the default and set it to 0 - resulting in somewhat higher transfer
rates. In some rare cases (especially with older 486 systems) the
default delays are not long enough. if you experience corrupt data
transfers, or unexpected failures, you may wish to increase the
port delay.
3.3 Some drives need a printer reset
-------------------------------------
There appear to be a number of "noname" external drives on the market
that do not always power up correctly. We have noticed this with some
drives based on OnSpec and older Freecom adapters. In these rare cases,
the adapter can often be reinitialised by issuing a "printer reset" on
the parallel port. As the reset operation is potentially disruptive in
multiple device environments, the pata_parport drivers will not do it
automatically. You can however, force a printer reset by doing::
insmod lp reset=1
rmmod lp
If you have one of these marginal cases, you should probably build
your pata_parport drivers as modules, and arrange to do the printer reset
before loading the pata_parport drivers.

View File

@ -142,7 +142,6 @@ parameter is applicable::
NFS Appropriate NFS support is enabled.
OF Devicetree is enabled.
PV_OPS A paravirtualized kernel is enabled.
PARIDE The ParIDE (parallel port IDE) subsystem is enabled.
PARISC The PA-RISC architecture is enabled.
PCI PCI bus support is enabled.
PCIE PCI Express support is enabled.

View File

@ -4120,10 +4120,6 @@
pcbit= [HW,ISDN]
pcd. [PARIDE]
See header of drivers/block/paride/pcd.c.
See also Documentation/admin-guide/blockdev/paride.rst.
pci=option[,option...] [PCI] various PCI subsystem options.
Some options herein operate on a specific device
@ -4386,9 +4382,6 @@
for debug and development, but should not be
needed on a platform with proper driver support.
pd. [PARIDE]
See Documentation/admin-guide/blockdev/paride.rst.
pdcchassis= [PARISC,HW] Disable/Enable PDC Chassis Status codes at
boot time.
Format: { 0 | 1 }
@ -4401,12 +4394,6 @@
allocator. This parameter is primarily for debugging
and performance comparison.
pf. [PARIDE]
See Documentation/admin-guide/blockdev/paride.rst.
pg. [PARIDE]
See Documentation/admin-guide/blockdev/paride.rst.
pirq= [SMP,APIC] Manual mp-table setup
See Documentation/x86/i386/IO-APIC.rst.
@ -4568,9 +4555,6 @@
pstore.backend= Specify the name of the pstore backend to use
pt. [PARIDE]
See Documentation/admin-guide/blockdev/paride.rst.
pti= [X86-64] Control Page Table Isolation of user and
kernel address spaces. Disabling this feature
removes hardening, but improves performance of

View File

@ -15844,13 +15844,6 @@ F: arch/*/include/asm/paravirt*.h
F: arch/*/kernel/paravirt*
F: include/linux/hypervisor.h
PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
M: Tim Waugh <tim@cyberelk.net>
L: linux-parport@lists.infradead.org (subscribers-only)
S: Maintained
F: Documentation/admin-guide/blockdev/paride.rst
F: drivers/block/paride/
PARISC ARCHITECTURE
M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
M: Helge Deller <deller@gmx.de>

View File

@ -1164,7 +1164,7 @@ config PATA_WINBOND_VLB
config PATA_PARPORT
tristate "Parallel port IDE device support"
depends on PARPORT_PC && PARIDE=n
depends on PARPORT_PC
help
There are many external CD-ROM and disk devices that connect through
your computer's parallel port. Most of them are actually IDE devices

View File

@ -103,33 +103,6 @@ config GDROM
Most users will want to say "Y" here.
You can also build this as a module which will be called gdrom.
config PARIDE
tristate "Parallel port IDE device support"
depends on PARPORT_PC
help
There are many external CD-ROM and disk devices that connect through
your computer's parallel port. Most of them are actually IDE devices
using a parallel port IDE adapter. This option enables the PARIDE
subsystem which contains drivers for many of these external drives.
Read <file:Documentation/admin-guide/blockdev/paride.rst> for more information.
If you have said Y to the "Parallel-port support" configuration
option, you may share a single port between your printer and other
parallel port devices. Answer Y to build PARIDE support into your
kernel, or M if you would like to build it as a loadable module. If
your parallel port support is in a loadable module, you must build
PARIDE as a module. If you built PARIDE support into your kernel,
you may still build the individual protocol modules and high-level
drivers as loadable modules. If you build this support as a module,
it will be called paride.
To use the PARIDE support, you must say Y or M here and also to at
least one high-level driver (e.g. "Parallel port IDE disks",
"Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and
to at least one protocol driver (e.g. "ATEN EH-100 protocol",
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).
source "drivers/block/paride/Kconfig"
source "drivers/block/mtip32xx/Kconfig"

View File

@ -1,102 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
#
# PARIDE configuration
#
# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module,
# PARIDE must also be a module.
# PARIDE only supports PC style parports. Tough for USB or other parports...
comment "Parallel IDE high-level drivers"
depends on PARIDE
config PARIDE_PD
tristate "Parallel port IDE disks"
depends on PARIDE
help
This option enables the high-level driver for IDE-type disk devices
connected through a parallel port. If you chose to build PARIDE
support into your kernel, you may answer Y here to build in the
parallel port IDE driver, otherwise you should answer M to build
it as a loadable module. The module will be called pd. You
must also have at least one parallel port protocol driver in your
system. Among the devices supported by this driver are the SyQuest
EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
hard drives from MicroSolutions.
config PARIDE_PCD
tristate "Parallel port ATAPI CD-ROMs"
depends on PARIDE
select CDROM
help
This option enables the high-level driver for ATAPI CD-ROM devices
connected through a parallel port. If you chose to build PARIDE
support into your kernel, you may answer Y here to build in the
parallel port ATAPI CD-ROM driver, otherwise you should answer M to
build it as a loadable module. The module will be called pcd. You
must also have at least one parallel port protocol driver in your
system. Among the devices supported by this driver are the
MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
you have such a CD-ROM drive, you should also say Y or M to "ISO
9660 CD-ROM file system support" below, because that's the file
system used on CD-ROMs.
config PARIDE_PF
tristate "Parallel port ATAPI disks"
depends on PARIDE
help
This option enables the high-level driver for ATAPI disk devices
connected through a parallel port. If you chose to build PARIDE
support into your kernel, you may answer Y here to build in the
parallel port ATAPI disk driver, otherwise you should answer M
to build it as a loadable module. The module will be called pf.
You must also have at least one parallel port protocol driver in
your system. Among the devices supported by this driver are the
MicroSolutions backpack PD/CD drive and the Imation Superdisk
LS-120 drive.
config PARIDE_PT
tristate "Parallel port ATAPI tapes"
depends on PARIDE
help
This option enables the high-level driver for ATAPI tape devices
connected through a parallel port. If you chose to build PARIDE
support into your kernel, you may answer Y here to build in the
parallel port ATAPI disk driver, otherwise you should answer M
to build it as a loadable module. The module will be called pt.
You must also have at least one parallel port protocol driver in
your system. Among the devices supported by this driver is the
parallel port version of the HP 5GB drive.
config PARIDE_PG
tristate "Parallel port generic ATAPI devices"
depends on PARIDE
help
This option enables a special high-level driver for generic ATAPI
devices connected through a parallel port. The driver allows user
programs, such as cdrtools, to send ATAPI commands directly to a
device.
If you chose to build PARIDE support into your kernel, you may
answer Y here to build in the parallel port generic ATAPI driver,
otherwise you should answer M to build it as a loadable module. The
module will be called pg.
You must also have at least one parallel port protocol driver in
your system.
This driver implements an API loosely related to the generic SCSI
driver. See <file:include/linux/pg.h>. for details.
You can obtain the most recent version of cdrtools from
<ftp://ftp.berlios.de/pub/cdrecord/>. Versions 1.6.1a3 and
later fully support this driver.
comment "Parallel IDE protocol modules"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
config PARIDE_ATEN
tristate "ATEN EH-100 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the ATEN EH-100 parallel port IDE
protocol. This protocol is used in some inexpensive low performance
@ -109,7 +20,7 @@ config PARIDE_ATEN
config PARIDE_BPCK
tristate "MicroSolutions backpack (Series 5) protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 5 IDE protocol. (Most BACKPACK drives made
@ -127,7 +38,7 @@ config PARIDE_BPCK
config PARIDE_BPCK6
tristate "MicroSolutions backpack (Series 6) protocol"
depends on (PARIDE || PATA_PARPORT) && !64BIT
depends on (PATA_PARPORT) && !64BIT
help
This option enables support for the Micro Solutions BACKPACK
parallel port Series 6 IDE protocol. (Most BACKPACK drives made
@ -146,7 +57,7 @@ config PARIDE_BPCK6
config PARIDE_COMM
tristate "DataStor Commuter protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the Commuter parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@ -157,7 +68,7 @@ config PARIDE_COMM
config PARIDE_DSTR
tristate "DataStor EP-2000 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the EP-2000 parallel port IDE
protocol from DataStor. If you chose to build PARIDE support
@ -168,7 +79,7 @@ config PARIDE_DSTR
config PARIDE_FIT2
tristate "FIT TD-2000 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the TD-2000 parallel port IDE
protocol from Fidelity International Technology. This is a simple
@ -181,7 +92,7 @@ config PARIDE_FIT2
config PARIDE_FIT3
tristate "FIT TD-3000 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the TD-3000 parallel port IDE
protocol from Fidelity International Technology. This protocol is
@ -194,7 +105,7 @@ config PARIDE_FIT3
config PARIDE_EPAT
tristate "Shuttle EPAT/EPEZ protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the EPAT parallel port IDE protocol.
EPAT is a parallel port IDE adapter manufactured by Shuttle
@ -216,7 +127,7 @@ config PARIDE_EPATC8
config PARIDE_EPIA
tristate "Shuttle EPIA protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the (obsolete) EPIA parallel port
IDE protocol from Shuttle Technology. This adapter can still be
@ -228,7 +139,7 @@ config PARIDE_EPIA
config PARIDE_FRIQ
tristate "Freecom IQ ASIC-2 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for version 2 of the Freecom IQ parallel
port IDE adapter. This adapter is used by the Maxell Superdisk
@ -240,7 +151,7 @@ config PARIDE_FRIQ
config PARIDE_FRPW
tristate "FreeCom power protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the Freecom power parallel port IDE
protocol. If you chose to build PARIDE support into your kernel, you
@ -251,7 +162,7 @@ config PARIDE_FRPW
config PARIDE_KBIC
tristate "KingByte KBIC-951A/971A protocols"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the KBIC-951A and KBIC-971A parallel
port IDE protocols from KingByte Information Corp. KingByte's
@ -264,7 +175,7 @@ config PARIDE_KBIC
config PARIDE_KTTI
tristate "KT PHd protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the "PHd" parallel port IDE protocol
from KT Technology. This is a simple (low speed) adapter that is
@ -277,7 +188,7 @@ config PARIDE_KTTI
config PARIDE_ON20
tristate "OnSpec 90c20 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the (obsolete) 90c20 parallel port
IDE protocol from OnSpec (often marketed under the ValuStore brand
@ -289,7 +200,7 @@ config PARIDE_ON20
config PARIDE_ON26
tristate "OnSpec 90c26 protocol"
depends on PARIDE || PATA_PARPORT
depends on PATA_PARPORT
help
This option enables support for the 90c26 parallel port IDE protocol
from OnSpec Electronics (often marketed under the ValuStore brand

View File

@ -6,7 +6,6 @@
# Rewritten to use lists instead of if-statements.
#
obj-$(CONFIG_PARIDE) += paride.o
obj-$(CONFIG_PARIDE_ATEN) += aten.o
obj-$(CONFIG_PARIDE_BPCK) += bpck.o
obj-$(CONFIG_PARIDE_COMM) += comm.o
@ -22,8 +21,3 @@ obj-$(CONFIG_PARIDE_ON20) += on20.o
obj-$(CONFIG_PARIDE_ON26) += on26.o
obj-$(CONFIG_PARIDE_KTTI) += ktti.o
obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o
obj-$(CONFIG_PARIDE_PD) += pd.o
obj-$(CONFIG_PARIDE_PCD) += pcd.o
obj-$(CONFIG_PARIDE_PF) += pf.o
obj-$(CONFIG_PARIDE_PT) += pt.o
obj-$(CONFIG_PARIDE_PG) += pg.o

View File

@ -1,128 +0,0 @@
Lemma 1:
If ps_tq is scheduled, ps_tq_active is 1. ps_tq_int() can be called
only when ps_tq_active is 1.
Proof: All assignments to ps_tq_active and all scheduling of ps_tq happen
under ps_spinlock. There are three places where that can happen:
one in ps_set_intr() (A) and two in ps_tq_int() (B and C).
Consider the sequnce of these events. A can not be preceded by
anything except B, since it is under if (!ps_tq_active) under
ps_spinlock. C is always preceded by B, since we can't reach it
other than through B and we don't drop ps_spinlock between them.
IOW, the sequence is A?(BA|BC|B)*. OTOH, number of B can not exceed
the sum of numbers of A and C, since each call of ps_tq_int() is
the result of ps_tq execution. Therefore, the sequence starts with
A and each B is preceded by either A or C. Moments when we enter
ps_tq_int() are sandwiched between {A,C} and B in that sequence,
since at any time number of B can not exceed the number of these
moments which, in turn, can not exceed the number of A and C.
In other words, the sequence of events is (A or C set ps_tq_active to
1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered,
B resets ps_tq_active)*.
consider the following area:
* in do_pd_request1(): to calls of pi_do_claimed() and return in
case when pd_req is NULL.
* in next_request(): to call of do_pd_request1()
* in do_pd_read(): to call of ps_set_intr()
* in do_pd_read_start(): to calls of pi_do_claimed(), next_request()
and ps_set_intr()
* in do_pd_read_drq(): to calls of pi_do_claimed() and next_request()
* in do_pd_write(): to call of ps_set_intr()
* in do_pd_write_start(): to calls of pi_do_claimed(), next_request()
and ps_set_intr()
* in do_pd_write_done(): to calls of pi_do_claimed() and next_request()
* in ps_set_intr(): to check for ps_tq_active and to scheduling
ps_tq if ps_tq_active was 0.
* in ps_tq_int(): from the moment when we get ps_spinlock() to the
return, call of con() or scheduling ps_tq.
* in pi_schedule_claimed() when called from pi_do_claimed() called from
pd.c, everything until returning 1 or setting or setting ->claim_cont
on the path that returns 0
* in pi_do_claimed() when called from pd.c, everything until the call
of pi_do_claimed() plus the everything until the call of cont() if
pi_do_claimed() has returned 1.
* in pi_wake_up() called for PIA that belongs to pd.c, everything from
the moment when pi_spinlock has been acquired.
Lemma 2:
1) at any time at most one thread of execution can be in that area or
be preempted there.
2) When there is such a thread, pd_busy is set or pd_lock is held by
that thread.
3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is
held by that thread.
4) When there is such a thread, all PIA belonging to pd.c have NULL
->claim_cont or pi_spinlock is held by thread in question.
Proof: consider the first moment when the above is not true.
(1) can become not true if some thread enters that area while another is there.
a) do_pd_request1() can be called from next_request() or do_pd_request()
In the first case the thread was already in the area. In the second,
the thread was holding pd_lock and found pd_busy not set, which would
mean that (2) was already not true.
b) ps_set_intr() and pi_schedule_claimed() can be called only from the
area.
c) pi_do_claimed() is called by pd.c only from the area.
d) ps_tq_int() can enter the area only when the thread is holding
ps_spinlock and ps_tq_active is 1 (due to Lemma 1). It means that
(3) was already not true.
e) do_pd_{read,write}* could be called only from the area. The only
case that needs consideration is call from pi_wake_up() and there
we would have to be called for the PIA that got ->claimed_cont
from pd.c. That could happen only if pi_do_claimed() had been
called from pd.c for that PIA, which happens only for PIA belonging
to pd.c.
f) pi_wake_up() can enter the area only when the thread is holding
pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to
pd.c. It means that (4) was already not true.
(2) can become not true only when pd_lock is released by the thread in question.
Indeed, pd_busy is reset only in the area and thread that resets
it is holding pd_lock. The only place within the area where we
release pd_lock is in pd_next_buf() (called from within the area).
But that code does not reset pd_busy, so pd_busy would have to be
0 when pd_next_buf() had acquired pd_lock. If it become 0 while
we were acquiring the lock, (1) would be already false, since
the thread that had reset it would be in the area simulateously.
If it was 0 before we tried to acquire pd_lock, (2) would be
already false.
For similar reasons, (3) can become not true only when ps_spinlock is released
by the thread in question. However, all such places within the area are right
after resetting ps_tq_active to 0.
(4) is done the same way - all places where we release pi_spinlock within
the area are either after resetting ->claimed_cont to NULL while holding
pi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock
also in the area. The only place where ->claimed_cont is made non-NULL is
in the area, under pi_spinlock and we do not release it until after leaving
the area.
QED.
Corollary 1: ps_tq_active can be killed. Indeed, the only place where we
check its value is in ps_set_intr() and if it had been non-zero at that
point, we would have violated either (2.1) (if it was set while ps_set_intr()
was acquiring ps_spinlock) or (2.3) (if it was set when we started to
acquire ps_spinlock).
Corollary 2: ps_spinlock can be killed. Indeed, Lemma 1 and Lemma 2 show
that the only possible contention is between scheduling ps_tq followed by
immediate release of spinlock and beginning of execution of ps_tq on
another CPU.
Corollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start()
can be killed. Indeed, we are not holding pd_lock and thus pd_busy is already
1 here.
Corollary 4: in ps_tq_int() uses of con can be replaced with uses of
ps_continuation, since the latter is changed only from the area.
We don't need to reset it to NULL, since we are guaranteed that there
will be a call of ps_set_intr() before we look at ps_continuation again.
We can remove the check for ps_continuation being NULL for the same
reason - the value is guaranteed to be set by the last ps_set_intr() and
we never pass it NULL. Assignements in the beginning of ps_set_intr()
can be taken to callers as long as they remain within the area.

View File

@ -25,7 +25,7 @@
#include <linux/types.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88)

View File

@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#undef r2
#undef w2

View File

@ -31,7 +31,7 @@
#include <linux/parport.h>
#include "ppc6lnx.c"
#include "paride.h"
#include <linux/pata_parport.h>
/* PARAMETERS */
static bool verbose; /* set this to 1 to see debugging messages and whatnot */

View File

@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes

View File

@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes

View File

@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0))
#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0))

View File

@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads on port 1, 8-bit writes
1 5/3 reads on ports 1 & 2, 8-bit writes

View File

@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))

View File

@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0))

View File

@ -35,7 +35,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);

View File

@ -33,7 +33,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define cec4 w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
#define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))

View File

@ -28,7 +28,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define r12w() (delay_p,inw(pi->port+1)&0xffff)

View File

@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))

View File

@ -1,31 +0,0 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# mkd -- a script to create the device special files for the PARIDE subsystem
#
# block devices: pd (45), pcd (46), pf (47)
# character devices: pt (96), pg (97)
#
function mkdev {
mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
}
#
function pd {
D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
mkdev pd$D b 45 $[ $1 * 16 ]
for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
done
}
#
cd /dev
#
for u in 0 1 2 3 ; do pd $u ; done
for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
#
# end of mkd

View File

@ -22,7 +22,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
#define op(f) w2(4);w0(f);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4);
#define vl(v) w2(4);w0(v);w2(5);w2(7);w2(5);w2(4);

View File

@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>
#include "paride.h"
#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes

View File

@ -1,479 +0,0 @@
/*
paride.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
Under the terms of the GNU General Public License.
This is the base module for the family of device drivers
that support parallel port IDE devices.
*/
/* Changes:
1.01 GRG 1998.05.03 Use spinlocks
1.02 GRG 1998.05.05 init_proto, release_proto, ktti
1.03 GRG 1998.08.15 eliminate compiler warning
1.04 GRG 1998.11.28 added support for FRIQ
1.05 TMW 2000.06.06 use parport_find_number instead of
parport_enumerate
1.06 TMW 2001.03.26 more sane parport-or-not resource management
*/
#define PI_VERSION "1.06"
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/sched.h> /* TASK_* */
#include <linux/parport.h>
#include <linux/slab.h>
#include "paride.h"
MODULE_LICENSE("GPL");
#define MAX_PROTOS 32
static struct pi_protocol *protocols[MAX_PROTOS];
static DEFINE_SPINLOCK(pi_spinlock);
void pi_write_regr(PIA * pi, int cont, int regr, int val)
{
pi->proto->write_regr(pi, cont, regr, val);
}
EXPORT_SYMBOL(pi_write_regr);
int pi_read_regr(PIA * pi, int cont, int regr)
{
return pi->proto->read_regr(pi, cont, regr);
}
EXPORT_SYMBOL(pi_read_regr);
void pi_write_block(PIA * pi, char *buf, int count)
{
pi->proto->write_block(pi, buf, count);
}
EXPORT_SYMBOL(pi_write_block);
void pi_read_block(PIA * pi, char *buf, int count)
{
pi->proto->read_block(pi, buf, count);
}
EXPORT_SYMBOL(pi_read_block);
static void pi_wake_up(void *p)
{
PIA *pi = (PIA *) p;
unsigned long flags;
void (*cont) (void) = NULL;
spin_lock_irqsave(&pi_spinlock, flags);
if (pi->claim_cont && !parport_claim(pi->pardev)) {
cont = pi->claim_cont;
pi->claim_cont = NULL;
pi->claimed = 1;
}
spin_unlock_irqrestore(&pi_spinlock, flags);
wake_up(&(pi->parq));
if (cont)
cont();
}
int pi_schedule_claimed(PIA * pi, void (*cont) (void))
{
unsigned long flags;
spin_lock_irqsave(&pi_spinlock, flags);
if (pi->pardev && parport_claim(pi->pardev)) {
pi->claim_cont = cont;
spin_unlock_irqrestore(&pi_spinlock, flags);
return 0;
}
pi->claimed = 1;
spin_unlock_irqrestore(&pi_spinlock, flags);
return 1;
}
EXPORT_SYMBOL(pi_schedule_claimed);
void pi_do_claimed(PIA * pi, void (*cont) (void))
{
if (pi_schedule_claimed(pi, cont))
cont();
}
EXPORT_SYMBOL(pi_do_claimed);
static void pi_claim(PIA * pi)
{
if (pi->claimed)
return;
pi->claimed = 1;
if (pi->pardev)
wait_event(pi->parq,
!parport_claim((struct pardevice *) pi->pardev));
}
static void pi_unclaim(PIA * pi)
{
pi->claimed = 0;
if (pi->pardev)
parport_release((struct pardevice *) (pi->pardev));
}
void pi_connect(PIA * pi)
{
pi_claim(pi);
pi->proto->connect(pi);
}
EXPORT_SYMBOL(pi_connect);
void pi_disconnect(PIA * pi)
{
pi->proto->disconnect(pi);
pi_unclaim(pi);
}
EXPORT_SYMBOL(pi_disconnect);
static void pi_unregister_parport(PIA * pi)
{
if (pi->pardev) {
parport_unregister_device((struct pardevice *) (pi->pardev));
pi->pardev = NULL;
}
}
void pi_release(PIA * pi)
{
pi_unregister_parport(pi);
if (pi->proto->release_proto)
pi->proto->release_proto(pi);
module_put(pi->proto->owner);
}
EXPORT_SYMBOL(pi_release);
static int default_test_proto(PIA * pi, char *scratch, int verbose)
{
int j, k;
int e[2] = { 0, 0 };
pi->proto->connect(pi);
for (j = 0; j < 2; j++) {
pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10);
for (k = 0; k < 256; k++) {
pi_write_regr(pi, 0, 2, k ^ 0xaa);
pi_write_regr(pi, 0, 3, k ^ 0x55);
if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa))
e[j]++;
}
}
pi->proto->disconnect(pi);
if (verbose)
printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n",
pi->device, pi->proto->name, pi->port,
pi->mode, e[0], e[1]);
return (e[0] && e[1]); /* not here if both > 0 */
}
static int pi_test_proto(PIA * pi, char *scratch, int verbose)
{
int res;
pi_claim(pi);
if (pi->proto->test_proto)
res = pi->proto->test_proto(pi, scratch, verbose);
else
res = default_test_proto(pi, scratch, verbose);
pi_unclaim(pi);
return res;
}
int paride_register(PIP * pr)
{
int k;
for (k = 0; k < MAX_PROTOS; k++)
if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) {
printk("paride: %s protocol already registered\n",
pr->name);
return -1;
}
k = 0;
while ((k < MAX_PROTOS) && (protocols[k]))
k++;
if (k == MAX_PROTOS) {
printk("paride: protocol table full\n");
return -1;
}
protocols[k] = pr;
pr->index = k;
printk("paride: %s registered as protocol %d\n", pr->name, k);
return 0;
}
EXPORT_SYMBOL(paride_register);
void paride_unregister(PIP * pr)
{
if (!pr)
return;
if (protocols[pr->index] != pr) {
printk("paride: %s not registered\n", pr->name);
return;
}
protocols[pr->index] = NULL;
}
EXPORT_SYMBOL(paride_unregister);
static int pi_register_parport(PIA *pi, int verbose, int unit)
{
struct parport *port;
struct pardev_cb par_cb;
port = parport_find_base(pi->port);
if (!port)
return 0;
memset(&par_cb, 0, sizeof(par_cb));
par_cb.wakeup = pi_wake_up;
par_cb.private = (void *)pi;
pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
unit);
parport_put_port(port);
if (!pi->pardev)
return 0;
init_waitqueue_head(&pi->parq);
if (verbose)
printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name);
pi->parname = (char *) port->name;
return 1;
}
static int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose)
{
int best, range;
if (pi->mode != -1) {
if (pi->mode >= max)
return 0;
range = 3;
if (pi->mode >= pi->proto->epp_first)
range = 8;
if ((range == 8) && (pi->port % 8))
return 0;
pi->reserved = range;
return (!pi_test_proto(pi, scratch, verbose));
}
best = -1;
for (pi->mode = 0; pi->mode < max; pi->mode++) {
range = 3;
if (pi->mode >= pi->proto->epp_first)
range = 8;
if ((range == 8) && (pi->port % 8))
break;
pi->reserved = range;
if (!pi_test_proto(pi, scratch, verbose))
best = pi->mode;
}
pi->mode = best;
return (best > -1);
}
static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
{
int max, s, e;
s = unit;
e = s + 1;
if (s == -1) {
s = 0;
e = pi->proto->max_units;
}
if (!pi_register_parport(pi, verbose, s))
return 0;
if (pi->proto->test_port) {
pi_claim(pi);
max = pi->proto->test_port(pi);
pi_unclaim(pi);
} else
max = pi->proto->max_mode;
if (pi->proto->probe_unit) {
pi_claim(pi);
for (pi->unit = s; pi->unit < e; pi->unit++)
if (pi->proto->probe_unit(pi)) {
pi_unclaim(pi);
if (pi_probe_mode(pi, max, scratch, verbose))
return 1;
pi_unregister_parport(pi);
return 0;
}
pi_unclaim(pi);
pi_unregister_parport(pi);
return 0;
}
if (!pi_probe_mode(pi, max, scratch, verbose)) {
pi_unregister_parport(pi);
return 0;
}
return 1;
}
int pi_init(PIA * pi, int autoprobe, int port, int mode,
int unit, int protocol, int delay, char *scratch,
int devtype, int verbose, char *device)
{
int p, k, s, e;
int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 };
s = protocol;
e = s + 1;
if (!protocols[0])
request_module("paride_protocol");
if (autoprobe) {
s = 0;
e = MAX_PROTOS;
} else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
(!protocols[s]) || (unit < 0) ||
(unit >= protocols[s]->max_units)) {
printk("%s: Invalid parameters\n", device);
return 0;
}
for (p = s; p < e; p++) {
struct pi_protocol *proto = protocols[p];
if (!proto)
continue;
/* still racy */
if (!try_module_get(proto->owner))
continue;
pi->proto = proto;
pi->private = 0;
if (proto->init_proto && proto->init_proto(pi) < 0) {
pi->proto = NULL;
module_put(proto->owner);
continue;
}
if (delay == -1)
pi->delay = pi->proto->default_delay;
else
pi->delay = delay;
pi->devtype = devtype;
pi->device = device;
pi->parname = NULL;
pi->pardev = NULL;
init_waitqueue_head(&pi->parq);
pi->claimed = 0;
pi->claim_cont = NULL;
pi->mode = mode;
if (port != -1) {
pi->port = port;
if (pi_probe_unit(pi, unit, scratch, verbose))
break;
pi->port = 0;
} else {
k = 0;
while ((pi->port = lpts[k++]))
if (pi_probe_unit
(pi, unit, scratch, verbose))
break;
if (pi->port)
break;
}
if (pi->proto->release_proto)
pi->proto->release_proto(pi);
module_put(proto->owner);
}
if (!pi->port) {
if (autoprobe)
printk("%s: Autoprobe failed\n", device);
else
printk("%s: Adapter not found\n", device);
return 0;
}
if (pi->parname)
printk("%s: Sharing %s at 0x%x\n", pi->device,
pi->parname, pi->port);
pi->proto->log_adapter(pi, scratch, verbose);
return 1;
}
EXPORT_SYMBOL(pi_init);
static int pi_probe(struct pardevice *par_dev)
{
struct device_driver *drv = par_dev->dev.driver;
int len = strlen(drv->name);
if (strncmp(par_dev->name, drv->name, len))
return -ENODEV;
return 0;
}
void *pi_register_driver(char *name)
{
struct parport_driver *parp_drv;
int ret;
parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
if (!parp_drv)
return NULL;
parp_drv->name = name;
parp_drv->probe = pi_probe;
parp_drv->devmodel = true;
ret = parport_register_driver(parp_drv);
if (ret) {
kfree(parp_drv);
return NULL;
}
return (void *)parp_drv;
}
EXPORT_SYMBOL(pi_register_driver);
void pi_unregister_driver(void *_drv)
{
struct parport_driver *drv = _drv;
parport_unregister_driver(drv);
kfree(drv);
}
EXPORT_SYMBOL(pi_unregister_driver);

View File

@ -1,185 +0,0 @@
/*
* The low-level protocol modules are used by either paride or pata_parport.
* These two are mutually exclusive because the compiled low-level protocol
* modules are not compatible.
* When PATA_PARPORT is enabled, include pata_parport.h instead of the rest
* of this file.
*/
#if IS_ENABLED(CONFIG_PATA_PARPORT)
#include <linux/pata_parport.h>
#else
#ifndef __DRIVERS_PARIDE_H__
#define __DRIVERS_PARIDE_H__
/*
paride.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
Under the terms of the GPL.
This file defines the interface between the high-level parallel
IDE device drivers (pd, pf, pcd, pt) and the adapter chips.
*/
/* Changes:
1.01 GRG 1998.05.05 init_proto, release_proto
*/
#define PARIDE_H_VERSION "1.01"
/* Some adapters need to know what kind of device they are in
Values for devtype:
*/
#define PI_PD 0 /* IDE disk */
#define PI_PCD 1 /* ATAPI CDrom */
#define PI_PF 2 /* ATAPI disk */
#define PI_PT 3 /* ATAPI tape */
#define PI_PG 4 /* ATAPI generic */
/* The paride module contains no state, instead the drivers allocate
a pi_adapter data structure and pass it to paride in every operation.
*/
struct pi_adapter {
struct pi_protocol *proto; /* adapter protocol */
int port; /* base address of parallel port */
int mode; /* transfer mode in use */
int delay; /* adapter delay setting */
int devtype; /* device type: PI_PD etc. */
char *device; /* name of driver */
int unit; /* unit number for chained adapters */
int saved_r0; /* saved port state */
int saved_r2; /* saved port state */
int reserved; /* number of ports reserved */
unsigned long private; /* for protocol module */
wait_queue_head_t parq; /* semaphore for parport sharing */
void *pardev; /* pointer to pardevice */
char *parname; /* parport name */
int claimed; /* parport has already been claimed */
void (*claim_cont)(void); /* continuation for parport wait */
};
typedef struct pi_adapter PIA;
/* functions exported by paride to the high level drivers */
extern int pi_init(PIA *pi,
int autoprobe, /* 1 to autoprobe */
int port, /* base port address */
int mode, /* -1 for autoprobe */
int unit, /* unit number, if supported */
int protocol, /* protocol to use */
int delay, /* -1 to use adapter specific default */
char * scratch, /* address of 512 byte buffer */
int devtype, /* device type: PI_PD, PI_PCD, etc ... */
int verbose, /* log verbose data while probing */
char *device /* name of the driver */
); /* returns 0 on failure, 1 on success */
extern void pi_release(PIA *pi);
/* registers are addressed as (cont,regr)
cont: 0 for command register file, 1 for control register(s)
regr: 0-7 for register number.
*/
extern void pi_write_regr(PIA *pi, int cont, int regr, int val);
extern int pi_read_regr(PIA *pi, int cont, int regr);
extern void pi_write_block(PIA *pi, char * buf, int count);
extern void pi_read_block(PIA *pi, char * buf, int count);
extern void pi_connect(PIA *pi);
extern void pi_disconnect(PIA *pi);
extern void pi_do_claimed(PIA *pi, void (*cont)(void));
extern int pi_schedule_claimed(PIA *pi, void (*cont)(void));
/* macros and functions exported to the protocol modules */
#define delay_p (pi->delay?udelay(pi->delay):(void)0)
#define out_p(offs,byte) outb(byte,pi->port+offs); delay_p;
#define in_p(offs) (delay_p,inb(pi->port+offs))
#define w0(byte) {out_p(0,byte);}
#define r0() (in_p(0) & 0xff)
#define w1(byte) {out_p(1,byte);}
#define r1() (in_p(1) & 0xff)
#define w2(byte) {out_p(2,byte);}
#define r2() (in_p(2) & 0xff)
#define w3(byte) {out_p(3,byte);}
#define w4(byte) {out_p(4,byte);}
#define r4() (in_p(4) & 0xff)
#define w4w(data) {outw(data,pi->port+4); delay_p;}
#define w4l(data) {outl(data,pi->port+4); delay_p;}
#define r4w() (delay_p,inw(pi->port+4)&0xffff)
#define r4l() (delay_p,inl(pi->port+4)&0xffffffff)
static inline u16 pi_swab16( char *b, int k)
{ union { u16 u; char t[2]; } r;
r.t[0]=b[2*k+1]; r.t[1]=b[2*k];
return r.u;
}
static inline u32 pi_swab32( char *b, int k)
{ union { u32 u; char f[4]; } r;
r.f[0]=b[4*k+1]; r.f[1]=b[4*k];
r.f[2]=b[4*k+3]; r.f[3]=b[4*k+2];
return r.u;
}
struct pi_protocol {
char name[8]; /* name for this protocol */
int index; /* index into protocol table */
int max_mode; /* max mode number */
int epp_first; /* modes >= this use 8 ports */
int default_delay; /* delay parameter if not specified */
int max_units; /* max chained units probed for */
void (*write_regr)(PIA *,int,int,int);
int (*read_regr)(PIA *,int,int);
void (*write_block)(PIA *,char *,int);
void (*read_block)(PIA *,char *,int);
void (*connect)(PIA *);
void (*disconnect)(PIA *);
int (*test_port)(PIA *);
int (*probe_unit)(PIA *);
int (*test_proto)(PIA *,char *,int);
void (*log_adapter)(PIA *,char *,int);
int (*init_proto)(PIA *);
void (*release_proto)(PIA *);
struct module *owner;
};
typedef struct pi_protocol PIP;
extern int paride_register( PIP * );
extern void paride_unregister ( PIP * );
void *pi_register_driver(char *);
void pi_unregister_driver(void *);
#endif /* __DRIVERS_PARIDE_H__ */
/* end of paride.h */
#endif /* IS_ENABLED(CONFIG_PATA_PARPORT) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,734 +0,0 @@
/*
pg.c (c) 1998 Grant R. Guenther <grant@torque.net>
Under the terms of the GNU General Public License.
The pg driver provides a simple character device interface for
sending ATAPI commands to a device. With the exception of the
ATAPI reset operation, all operations are performed by a pair
of read and write operations to the appropriate /dev/pgN device.
A write operation delivers a command and any outbound data in
a single buffer. Normally, the write will succeed unless the
device is offline or malfunctioning, or there is already another
command pending. If the write succeeds, it should be followed
immediately by a read operation, to obtain any returned data and
status information. A read will fail if there is no operation
in progress.
As a special case, the device can be reset with a write operation,
and in this case, no following read is expected, or permitted.
There are no ioctl() operations. Any single operation
may transfer at most PG_MAX_DATA bytes. Note that the driver must
copy the data through an internal buffer. In keeping with all
current ATAPI devices, command packets are assumed to be exactly
12 bytes in length.
To permit future changes to this interface, the headers in the
read and write buffers contain a single character "magic" flag.
Currently this flag must be the character "P".
By default, the driver will autoprobe for a single parallel
port ATAPI device, but if their individual parameters are
specified, the driver can handle up to 4 devices.
To use this device, you must have the following device
special files defined:
/dev/pg0 c 97 0
/dev/pg1 c 97 1
/dev/pg2 c 97 2
/dev/pg3 c 97 3
(You'll need to change the 97 to something else if you use
the 'major' parameter to install the driver on a different
major number.)
The behaviour of the pg driver can be altered by setting
some parameters from the insmod command line. The following
parameters are adjustable:
drive0 These four arguments can be arrays of
drive1 1-6 integers as follows:
drive2
drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
Where,
<prt> is the base of the parallel port address for
the corresponding drive. (required)
<pro> is the protocol number for the adapter that
supports this drive. These numbers are
logged by 'paride' when the protocol modules
are initialised. (0 if not given)
<uni> for those adapters that support chained
devices, this is the unit selector for the
chain of devices on the given port. It should
be zero for devices that don't support chaining.
(0 if not given)
<mod> this can be -1 to choose the best mode, or one
of the mode numbers supported by the adapter.
(-1 if not given)
<slv> ATAPI devices can be jumpered to master or slave.
Set this to 0 to choose the master drive, 1 to
choose the slave, -1 (the default) to choose the
first drive found.
<dly> some parallel ports require the driver to
go more slowly. -1 sets a default value that
should work with the chosen protocol. Otherwise,
set this to a small integer, the larger it is
the slower the port i/o. In some cases, setting
this to zero will speed up the device. (default -1)
major You may use this parameter to override the
default major number (97) that this driver
will use. Be sure to change the device
name as well.
name This parameter is a character string that
contains the name the kernel will use for this
device (in /proc output, for instance).
(default "pg").
verbose This parameter controls the amount of logging
that is done by the driver. Set it to 0 for
quiet operation, to 1 to enable progress
messages while the driver probes for devices,
or to 2 for full debug logging. (default 0)
If this driver is built into the kernel, you can use
the following command line parameters, with the same values
as the corresponding module parameters listed above:
pg.drive0
pg.drive1
pg.drive2
pg.drive3
In addition, you can use the parameter pg.disable to disable
the driver entirely.
*/
/* Changes:
1.01 GRG 1998.06.16 Bug fixes
1.02 GRG 1998.09.24 Added jumbo support
*/
#define PG_VERSION "1.02"
#define PG_MAJOR 97
#define PG_NAME "pg"
#define PG_UNITS 4
#ifndef PI_PG
#define PI_PG 4
#endif
#include <linux/types.h>
/* Here are things one can override from the insmod command.
Most are autoprobed by paride unless set here. Verbose is 0
by default.
*/
static int verbose;
static int major = PG_MAJOR;
static char *name = PG_NAME;
static int disable = 0;
static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
static int pg_drive_count;
enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
/* end of parameters */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
#include <linux/pg.h>
#include <linux/device.h>
#include <linux/sched.h> /* current, TASK_* */
#include <linux/mutex.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
module_param(verbose, int, 0644);
module_param(major, int, 0);
module_param(name, charp, 0);
module_param_array(drive0, int, NULL, 0);
module_param_array(drive1, int, NULL, 0);
module_param_array(drive2, int, NULL, 0);
module_param_array(drive3, int, NULL, 0);
#include "paride.h"
#define PG_SPIN_DEL 50 /* spin delay in micro-seconds */
#define PG_SPIN 200
#define PG_TMO HZ
#define PG_RESET_TMO 10*HZ
#define STAT_ERR 0x01
#define STAT_INDEX 0x02
#define STAT_ECC 0x04
#define STAT_DRQ 0x08
#define STAT_SEEK 0x10
#define STAT_WRERR 0x20
#define STAT_READY 0x40
#define STAT_BUSY 0x80
#define ATAPI_IDENTIFY 0x12
static DEFINE_MUTEX(pg_mutex);
static int pg_open(struct inode *inode, struct file *file);
static int pg_release(struct inode *inode, struct file *file);
static ssize_t pg_read(struct file *filp, char __user *buf,
size_t count, loff_t * ppos);
static ssize_t pg_write(struct file *filp, const char __user *buf,
size_t count, loff_t * ppos);
static int pg_detect(void);
#define PG_NAMELEN 8
struct pg {
struct pi_adapter pia; /* interface to paride layer */
struct pi_adapter *pi;
int busy; /* write done, read expected */
int start; /* jiffies at command start */
int dlen; /* transfer size requested */
unsigned long timeout; /* timeout requested */
int status; /* last sense key */
int drive; /* drive */
unsigned long access; /* count of active opens ... */
int present; /* device present ? */
char *bufptr;
char name[PG_NAMELEN]; /* pg0, pg1, ... */
};
static struct pg devices[PG_UNITS];
static int pg_identify(struct pg *dev, int log);
static char pg_scratch[512]; /* scratch block buffer */
static struct class *pg_class;
static void *par_drv; /* reference of parport driver */
/* kernel glue structures */
static const struct file_operations pg_fops = {
.owner = THIS_MODULE,
.read = pg_read,
.write = pg_write,
.open = pg_open,
.release = pg_release,
.llseek = noop_llseek,
};
static void pg_init_units(void)
{
int unit;
pg_drive_count = 0;
for (unit = 0; unit < PG_UNITS; unit++) {
int *parm = *drives[unit];
struct pg *dev = &devices[unit];
dev->pi = &dev->pia;
clear_bit(0, &dev->access);
dev->busy = 0;
dev->present = 0;
dev->bufptr = NULL;
dev->drive = parm[D_SLV];
snprintf(dev->name, PG_NAMELEN, "%s%c", name, 'a'+unit);
if (parm[D_PRT])
pg_drive_count++;
}
}
static inline int status_reg(struct pg *dev)
{
return pi_read_regr(dev->pi, 1, 6);
}
static inline int read_reg(struct pg *dev, int reg)
{
return pi_read_regr(dev->pi, 0, reg);
}
static inline void write_reg(struct pg *dev, int reg, int val)
{
pi_write_regr(dev->pi, 0, reg, val);
}
static inline u8 DRIVE(struct pg *dev)
{
return 0xa0+0x10*dev->drive;
}
static void pg_sleep(int cs)
{
schedule_timeout_interruptible(cs);
}
static int pg_wait(struct pg *dev, int go, int stop, unsigned long tmo, char *msg)
{
int j, r, e, s, p, to;
dev->status = 0;
j = 0;
while ((((r = status_reg(dev)) & go) || (stop && (!(r & stop))))
&& time_before(jiffies, tmo)) {
if (j++ < PG_SPIN)
udelay(PG_SPIN_DEL);
else
pg_sleep(1);
}
to = time_after_eq(jiffies, tmo);
if ((r & (STAT_ERR & stop)) || to) {
s = read_reg(dev, 7);
e = read_reg(dev, 1);
p = read_reg(dev, 2);
if (verbose > 1)
printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
dev->name, msg, s, e, p, to ? " timeout" : "");
if (to)
e |= 0x100;
dev->status = (e >> 4) & 0xff;
return -1;
}
return 0;
}
static int pg_command(struct pg *dev, char *cmd, int dlen, unsigned long tmo)
{
int k;
pi_connect(dev->pi);
write_reg(dev, 6, DRIVE(dev));
if (pg_wait(dev, STAT_BUSY | STAT_DRQ, 0, tmo, "before command"))
goto fail;
write_reg(dev, 4, dlen % 256);
write_reg(dev, 5, dlen / 256);
write_reg(dev, 7, 0xa0); /* ATAPI packet command */
if (pg_wait(dev, STAT_BUSY, STAT_DRQ, tmo, "command DRQ"))
goto fail;
if (read_reg(dev, 2) != 1) {
printk("%s: command phase error\n", dev->name);
goto fail;
}
pi_write_block(dev->pi, cmd, 12);
if (verbose > 1) {
printk("%s: Command sent, dlen=%d packet= ", dev->name, dlen);
for (k = 0; k < 12; k++)
printk("%02x ", cmd[k] & 0xff);
printk("\n");
}
return 0;
fail:
pi_disconnect(dev->pi);
return -1;
}
static int pg_completion(struct pg *dev, char *buf, unsigned long tmo)
{
int r, d, n, p;
r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
tmo, "completion");
dev->dlen = 0;
while (read_reg(dev, 7) & STAT_DRQ) {
d = (read_reg(dev, 4) + 256 * read_reg(dev, 5));
n = ((d + 3) & 0xfffc);
p = read_reg(dev, 2) & 3;
if (p == 0)
pi_write_block(dev->pi, buf, n);
if (p == 2)
pi_read_block(dev->pi, buf, n);
if (verbose > 1)
printk("%s: %s %d bytes\n", dev->name,
p ? "Read" : "Write", n);
dev->dlen += (1 - p) * d;
buf += d;
r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
tmo, "completion");
}
pi_disconnect(dev->pi);
return r;
}
static int pg_reset(struct pg *dev)
{
int i, k, err;
int expect[5] = { 1, 1, 1, 0x14, 0xeb };
int got[5];
pi_connect(dev->pi);
write_reg(dev, 6, DRIVE(dev));
write_reg(dev, 7, 8);
pg_sleep(20 * HZ / 1000);
k = 0;
while ((k++ < PG_RESET_TMO) && (status_reg(dev) & STAT_BUSY))
pg_sleep(1);
for (i = 0; i < 5; i++)
got[i] = read_reg(dev, i + 1);
err = memcmp(expect, got, sizeof(got)) ? -1 : 0;
if (verbose) {
printk("%s: Reset (%d) signature = ", dev->name, k);
for (i = 0; i < 5; i++)
printk("%3x", got[i]);
if (err)
printk(" (incorrect)");
printk("\n");
}
pi_disconnect(dev->pi);
return err;
}
static void xs(char *buf, char *targ, int len)
{
char l = '\0';
int k;
for (k = 0; k < len; k++) {
char c = *buf++;
if (c != ' ' && c != l)
l = *targ++ = c;
}
if (l == ' ')
targ--;
*targ = '\0';
}
static int pg_identify(struct pg *dev, int log)
{
int s;
char *ms[2] = { "master", "slave" };
char mf[10], id[18];
char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
char buf[36];
s = pg_command(dev, id_cmd, 36, jiffies + PG_TMO);
if (s)
return -1;
s = pg_completion(dev, buf, jiffies + PG_TMO);
if (s)
return -1;
if (log) {
xs(buf + 8, mf, 8);
xs(buf + 16, id, 16);
printk("%s: %s %s, %s\n", dev->name, mf, id, ms[dev->drive]);
}
return 0;
}
/*
* returns 0, with id set if drive is detected
* -1, if drive detection failed
*/
static int pg_probe(struct pg *dev)
{
if (dev->drive == -1) {
for (dev->drive = 0; dev->drive <= 1; dev->drive++)
if (!pg_reset(dev))
return pg_identify(dev, 1);
} else {
if (!pg_reset(dev))
return pg_identify(dev, 1);
}
return -1;
}
static int pg_detect(void)
{
struct pg *dev = &devices[0];
int k, unit;
printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major);
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
k = 0;
if (pg_drive_count == 0) {
if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch,
PI_PG, verbose, dev->name)) {
if (!pg_probe(dev)) {
dev->present = 1;
k++;
} else
pi_release(dev->pi);
}
} else
for (unit = 0; unit < PG_UNITS; unit++, dev++) {
int *parm = *drives[unit];
if (!parm[D_PRT])
continue;
if (pi_init(dev->pi, 0, parm[D_PRT], parm[D_MOD],
parm[D_UNI], parm[D_PRO], parm[D_DLY],
pg_scratch, PI_PG, verbose, dev->name)) {
if (!pg_probe(dev)) {
dev->present = 1;
k++;
} else
pi_release(dev->pi);
}
}
if (k)
return 0;
pi_unregister_driver(par_drv);
printk("%s: No ATAPI device detected\n", name);
return -1;
}
static int pg_open(struct inode *inode, struct file *file)
{
int unit = iminor(inode) & 0x7f;
struct pg *dev = &devices[unit];
int ret = 0;
mutex_lock(&pg_mutex);
if ((unit >= PG_UNITS) || (!dev->present)) {
ret = -ENODEV;
goto out;
}
if (test_and_set_bit(0, &dev->access)) {
ret = -EBUSY;
goto out;
}
if (dev->busy) {
pg_reset(dev);
dev->busy = 0;
}
pg_identify(dev, (verbose > 1));
dev->bufptr = kmalloc(PG_MAX_DATA, GFP_KERNEL);
if (dev->bufptr == NULL) {
clear_bit(0, &dev->access);
printk("%s: buffer allocation failed\n", dev->name);
ret = -ENOMEM;
goto out;
}
file->private_data = dev;
out:
mutex_unlock(&pg_mutex);
return ret;
}
static int pg_release(struct inode *inode, struct file *file)
{
struct pg *dev = file->private_data;
kfree(dev->bufptr);
dev->bufptr = NULL;
clear_bit(0, &dev->access);
return 0;
}
static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
struct pg *dev = filp->private_data;
struct pg_write_hdr hdr;
int hs = sizeof (hdr);
if (dev->busy)
return -EBUSY;
if (count < hs)
return -EINVAL;
if (copy_from_user(&hdr, buf, hs))
return -EFAULT;
if (hdr.magic != PG_MAGIC)
return -EINVAL;
if (hdr.dlen < 0 || hdr.dlen > PG_MAX_DATA)
return -EINVAL;
if ((count - hs) > PG_MAX_DATA)
return -EINVAL;
if (hdr.func == PG_RESET) {
if (count != hs)
return -EINVAL;
if (pg_reset(dev))
return -EIO;
return count;
}
if (hdr.func != PG_COMMAND)
return -EINVAL;
dev->start = jiffies;
dev->timeout = hdr.timeout * HZ + HZ / 2 + jiffies;
if (pg_command(dev, hdr.packet, hdr.dlen, jiffies + PG_TMO)) {
if (dev->status & 0x10)
return -ETIME;
return -EIO;
}
dev->busy = 1;
if (copy_from_user(dev->bufptr, buf + hs, count - hs))
return -EFAULT;
return count;
}
static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
struct pg *dev = filp->private_data;
struct pg_read_hdr hdr;
int hs = sizeof (hdr);
int copy;
if (!dev->busy)
return -EINVAL;
if (count < hs)
return -EINVAL;
dev->busy = 0;
if (pg_completion(dev, dev->bufptr, dev->timeout))
if (dev->status & 0x10)
return -ETIME;
memset(&hdr, 0, sizeof(hdr));
hdr.magic = PG_MAGIC;
hdr.dlen = dev->dlen;
copy = 0;
if (hdr.dlen < 0) {
hdr.dlen = -1 * hdr.dlen;
copy = hdr.dlen;
if (copy > (count - hs))
copy = count - hs;
}
hdr.duration = (jiffies - dev->start + HZ / 2) / HZ;
hdr.scsi = dev->status & 0x0f;
if (copy_to_user(buf, &hdr, hs))
return -EFAULT;
if (copy > 0)
if (copy_to_user(buf + hs, dev->bufptr, copy))
return -EFAULT;
return copy + hs;
}
static int __init pg_init(void)
{
int unit;
int err;
if (disable){
err = -EINVAL;
goto out;
}
pg_init_units();
if (pg_detect()) {
err = -ENODEV;
goto out;
}
err = register_chrdev(major, name, &pg_fops);
if (err < 0) {
printk("pg_init: unable to get major number %d\n", major);
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present)
pi_release(dev->pi);
}
goto out;
}
major = err; /* In case the user specified `major=0' (dynamic) */
pg_class = class_create(THIS_MODULE, "pg");
if (IS_ERR(pg_class)) {
err = PTR_ERR(pg_class);
goto out_chrdev;
}
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present)
device_create(pg_class, NULL, MKDEV(major, unit), NULL,
"pg%u", unit);
}
err = 0;
goto out;
out_chrdev:
unregister_chrdev(major, "pg");
out:
return err;
}
static void __exit pg_exit(void)
{
int unit;
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present)
device_destroy(pg_class, MKDEV(major, unit));
}
class_destroy(pg_class);
unregister_chrdev(major, name);
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present)
pi_release(dev->pi);
}
}
MODULE_LICENSE("GPL");
module_init(pg_init)
module_exit(pg_exit)

View File

@ -1,102 +0,0 @@
/*
pseudo.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
Under the terms of the GNU General Public License.
This is the "pseudo-interrupt" logic for parallel port drivers.
This module is #included into each driver. It makes one
function available:
ps_set_intr( void (*continuation)(void),
int (*ready)(void),
int timeout,
int nice )
Which will arrange for ready() to be evaluated frequently and
when either it returns true, or timeout jiffies have passed,
continuation() will be invoked.
If nice is 1, the test will done approximately once a
jiffy. If nice is 0, the test will also be done whenever
the scheduler runs (by adding it to a task queue). If
nice is greater than 1, the test will be done once every
(nice-1) jiffies.
*/
/* Changes:
1.01 1998.05.03 Switched from cli()/sti() to spinlocks
1.02 1998.12.14 Added support for nice > 1
*/
#define PS_VERSION "1.02"
#include <linux/sched.h>
#include <linux/workqueue.h>
static void ps_tq_int(struct work_struct *work);
static void (* ps_continuation)(void);
static int (* ps_ready)(void);
static unsigned long ps_timeout;
static int ps_tq_active = 0;
static int ps_nice = 0;
static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused)));
static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int);
static void ps_set_intr(void (*continuation)(void),
int (*ready)(void),
int timeout, int nice)
{
unsigned long flags;
spin_lock_irqsave(&ps_spinlock,flags);
ps_continuation = continuation;
ps_ready = ready;
ps_timeout = jiffies + timeout;
ps_nice = nice;
if (!ps_tq_active) {
ps_tq_active = 1;
if (!ps_nice)
schedule_delayed_work(&ps_tq, 0);
else
schedule_delayed_work(&ps_tq, ps_nice-1);
}
spin_unlock_irqrestore(&ps_spinlock,flags);
}
static void ps_tq_int(struct work_struct *work)
{
void (*con)(void);
unsigned long flags;
spin_lock_irqsave(&ps_spinlock,flags);
con = ps_continuation;
ps_tq_active = 0;
if (!con) {
spin_unlock_irqrestore(&ps_spinlock,flags);
return;
}
if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
ps_continuation = NULL;
spin_unlock_irqrestore(&ps_spinlock,flags);
con();
return;
}
ps_tq_active = 1;
if (!ps_nice)
schedule_delayed_work(&ps_tq, 0);
else
schedule_delayed_work(&ps_tq, ps_nice-1);
spin_unlock_irqrestore(&ps_spinlock,flags);
}
/* end of pseudo.h */

File diff suppressed because it is too large Load Diff