mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 17:53:56 +08:00
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:
parent
246a1c4c6b
commit
7750d8b510
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
@ -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)
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/wait.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "paride.h"
|
||||
#include <linux/pata_parport.h>
|
||||
|
||||
#undef r2
|
||||
#undef w2
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
@ -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
@ -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)
|
@ -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
Loading…
Reference in New Issue
Block a user