Commit 16c82539 authored by Linus Torvalds's avatar Linus Torvalds

pre-patch-2.1.131-3

Ok,
 I've made a new pre-patch-2.1.131-3.

The basic problem (that Alexander Viro correctly diagnosed) is that the
inode locking was horribly and subtly wrong for the case of a "rmdir()"
call. What rmdir() did was essentially something like

 - VFS: lock the directory that contains the directory to remove
   (this is normal and required to make sure that the name updates are
   completely atomic - so removing or adding anything requires you to hold
   the lock on the directory that contains the removee/addee)
 - low-level filesystem: lock the directory you're going to remove, in
   order to atomically check that it's empty.

So far so good, the above makes tons of sense. HOWEVER, the problem is
fairly obvious if anybody before Alexander had actually bothered to think
about it: when we hold two locks, we had better make sure that we get the
locks in the right order, or we may end up deadlocked with two (or more)
processes getting the locks in the wrong order and waiting on each other.

Now, if it was only rmdir(), things would be fine, because the directory
hierarchy itself imposes a lock order for rmdir(). But we have another
case that needs to lock two directories: "rename()". And that one doesn't
have the same kind of obvious order, and uses a different way to order the
two locks it gets. BOOM.

As far as I can tell, this is a problem in 2.0.x too, but while it's a
potential really nasty DoS-opening, it does have the saving grace that the
window to trigger it is really really small. I don't know if you can
actually make an exploit for it that has any real chance of hitting it,
but it's at least conceptually possible.

Now, the only sane fix was to actually make the VFS layer do all the
locking for rmdir(), and thus let the VFS layer make sure the order is
correct, so that low-level filesystems don't need to worry their pretty
heads. I tried to do that in the previous pre-patch, and it worked well
for ext2, but not all that much else. The problem was that too many
filesystems "knew" what the rmdir() downcall used to do. Oh, well.

Anyway, I've fixed the low-level filesystems as far as I can tell, and the
end result is a much cleaner interface (and one less bug). But it's an
interface change at a fairly late date, and while the fixes to smbfs etc
looked for the most part obvious, I haven't been able to test them, so
I've done most of them "blind".

Sadly, this bug couldn't just be glossed over, because a normal user could
(by knowing the exact right incantation) force tons of unkillable
processes that held critical filesystem resources (any lookup on a
directory that was locked would in turn also lock up). So I'd ask people
who have done filesystems for Linux to look over my changes, and if the
filesystems are not part of the standard distribution please look over
your own locally maintained fs code. I think we can ignore 2.0.x by virtue
of it probably being virtually impossible to trigger. I'll leave the
decision up to Alan.

Most specially, I'd like to have people who use/maintain vfat and umsdos
filesystems to test out that I actually made those filesystems happy with
my changes. The other filesystems were more straightforward.

Oh, and thanks to Alexander. Not that I really needed another bug to fix,
but it feels good to plug holes.

                        Linus

The change is basically:
 - the VFS layer locks the directory to be removed for you (as opposed to
   just the directory that contains the directory to be removed as it used
   to). A lot of filesystems didn't actually do this, and it is required,
   because otherwise the test for an empty directory may be subverted by a
   clever hacker.
 - the VFS layer will have done a dcache "prune" operation on the
   directory, and if there were no other uses for that dcache entry, it
   will have done a "d_drop()" on it too.
 - the above essentially means that any filesystem can do a
        if (!list_empty(&dentry->d_hash))
                return -EBUSY;
   to test whether there are other users of this directory. No need to do
   any extra pruning etc - if it's been dropped there won't be any new
   users of the dentry afterwards, so there are no races. So after doing
   the above test you know that you'll have exclusive access to the dentry
   forever.
   Most notably, the low-level filesystem should _not_ look at the
   dentry->d_count member to see how many users there are. The VFS layer
   currently artificially raises the dentry count to make sure
   "d_delete()" doesn't get rid of the inode early.
 - however: traditional local UNIX-type filesystems tend to want to allow
   removing of the directory even if it is in use by something else. This
   requires that the inode be accessible even after the rmdir() - even
   though it doesn't necessarily need to actually _do_ anything.
   For a normal UNIX-like filesystem this tends to be trivial and quite
   automatic behaviour, but you need to think about whether your
   filesystem is of the kind where the inode stays around even after the
   delete until we locally do the final "iput()". For example, on
   networked filesystems this is generally not true, simply because the
   server will have de-allocated the inode even if we still have a
   reference to it locally.
parent b468356b
...@@ -8492,13 +8492,14 @@ CONFIG_JOYSTICK ...@@ -8492,13 +8492,14 @@ CONFIG_JOYSTICK
The module will be called joystick.o. If you want to compile it as a The module will be called joystick.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt. module, say M here and read Documentation/modules.txt.
Classic PC analog joysticks Classic PC analog joysticks and gamepads
CONFIG_JOY_ANALOG CONFIG_JOY_ANALOG
Say Y here if you have an analog joystick or gamepad that connects Say Y here if you have an analog joystick or gamepad that connects
to the PC gameport. This supports many different types, including to the PC gameport. This supports many different types, including
joysticks with throttle control, and with CHF / FCS / 6-button joysticks with throttle control, with rudders, or with extensions
extensions. For more information on how to use the driver please like additional hats and buttons compatible with CH Flightstick Pro,
read Documentation/joystick.txt ThrustMaster FCS or 6 and 8 button gamepads. For more information on
how to use the driver please read Documentation/joystick.txt
FPGaming and MadCatz A3D controllers FPGaming and MadCatz A3D controllers
CONFIG_JOY_ASSASIN CONFIG_JOY_ASSASIN
...@@ -8506,25 +8507,26 @@ CONFIG_JOY_ASSASIN ...@@ -8506,25 +8507,26 @@ CONFIG_JOY_ASSASIN
MadCatz Panther XL. For more information on how to use the driver MadCatz Panther XL. For more information on how to use the driver
please read Documentation/joystick.txt please read Documentation/joystick.txt
Gravis GrIP gamepads Gravis GrIP joysticks and gamepads
CONFIG_JOY_GRAVIS CONFIG_JOY_GRAVIS
Say Y here if you have a Gravis GamePad Pro. For more information Say Y here if you have a Gravis GamePad Pro, Gravis Xterminator or
on how to use the driver please read Documentation/joystick.txt Gravis Blackhawk Digital. For more information on how to use the
driver please read Documentation/joystick.txt
PDPI Lightning L4 gamecards PDPI Lightning 4 gamecards
CONFIG_JOY_LIGHTNING CONFIG_JOY_LIGHTNING
Say Y here if you have a PDPI Lightning L4 gamecard and an analog Say Y here if you have a PDPI Lightning 4 gamecard and an analog
joystick or gamepad connected to it. For more information on how to joystick or gamepad connected to it. For more information on how to
use the driver please read Documentation/joystick.txt use the driver please read Documentation/joystick.txt
Logitech Digital joysticks Logitech Digital joysticks and gamepads
CONFIG_JOY_LOGITECH CONFIG_JOY_LOGITECH
Say Y here if you have a Logitech WingMan Extreme Digital, Say Y here if you have a Logitech WingMan Extreme Digital,
Logitech ThunderPad Digital or Logitech CyberMan 2. For more Logitech ThunderPad Digital or Logitech CyberMan 2. For more
information on how to use the driver please read information on how to use the driver please read
Documentation/joystick.txt Documentation/joystick.txt
Microsoft SideWinder, Genius Digital joysticks Microsoft SideWinder, Genius Digital joysticks and gamepads
CONFIG_JOY_SIDEWINDER CONFIG_JOY_SIDEWINDER
Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft
SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro, SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro,
...@@ -8532,34 +8534,35 @@ CONFIG_JOY_SIDEWINDER ...@@ -8532,34 +8534,35 @@ CONFIG_JOY_SIDEWINDER
more information on how to use the driver please read more information on how to use the driver please read
Documentation/joystick.txt Documentation/joystick.txt
ThrustMaster DirectConnect (BSP) joysticks ThrustMaster DirectConnect joysticks and gamepads
CONFIG_JOY_THRUSTMASTER CONFIG_JOY_THRUSTMASTER
Say Y here if you have a ThrustMaster Millenium 3D Inceptor, Say Y here if you have a ThrustMaster Millenium 3D Inceptor or a
ThrustMaster 3D Rage Pad, or ThrustMaster WCS III. For more ThrustMaster 3D Rage Pad. For more information on how to use the
information on how to use the driver please read driver please read Documentation/joystick.txt
Documentation/joystick.txt
NES, SNES, PSX, Multisystem gamepads NES, SNES, PSX, Multisystem joysticks and gamepads
CONFIG_JOY_CONSOLE CONFIG_JOY_CONSOLE
Say Y here if you have a Nintendo Entertainment System gamepad, Say Y here if you have a Nintendo Entertainment System gamepad,
Super Nintendo Entertainment System gamepad, Sony PlayStation Super Nintendo Entertainment System gamepad, Sony PlayStation
gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC
joystick. For more information on how to use the driver please read joystick. For more information on how to use the driver please read
Documentation/joystick.txt Documentation/joystick.txt and Documentation/joystick-parport.txt
Sega, Multisystem gamepads Sega, Multisystem joysticks and gamepads
CONFIG_JOY_DB9 CONFIG_JOY_DB9
Say Y here if you have a Sega Master System gamepad, Sega Genesis Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
Commodore, Amstrad CPC joystick. For more information on how to use Commodore, Amstrad CPC joystick. For more information on how to use
the driver please read Documentation/joystick.txt the driver please read Documentation/joystick.txt and
Documentation/joystick-parport.txt
TurboGraFX Multisystem joystick interface TurboGraFX Multisystem joystick interface
CONFIG_JOY_TURBOGRAFX CONFIG_JOY_TURBOGRAFX
Say Y here if you have the TurboGraFX interface by Steffen Schwenke, Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
and want to use it with Multiststem -- Atari, Amiga, Commodore, and want to use it with Multiststem -- Atari, Amiga, Commodore,
Amstrad CPC joystick. For more information on how to use the driver Amstrad CPC joystick. For more information on how to use the driver
please read Documentation/joystick-parport.txt please read Documentation/joystick-parport.txt and
Documentation/joystick-parport.txt
Amiga joysticks Amiga joysticks
CONFIG_JOY_AMIGA CONFIG_JOY_AMIGA
......
...@@ -506,14 +506,14 @@ more joysticks/pads. ...@@ -506,14 +506,14 @@ more joysticks/pads.
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
The joy-turbografx.c driver uses a very simple kernel/module command line: The joy-turbografx.c driver uses a very simple kernel/module command line:
js_tg=port,count js_tg=port,js1,js2,js3,js4,js5,js6,js7
Where 'port' is either the address of the parallel port the interface is Where 'port' is either the address of the parallel port the interface is
connected to (eg. 0x378), or, if you are using the parport driver of 2.1+ connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
Linux kernels, the number of the parport interface (eg. 0 for parport0). Linux kernels, the number of the parport interface (eg. 0 for parport0).
'Count' is the number of Multisystem, 1-button joysticks connected to the 'jsX' is the number of buttons the Multisystem joysticks connected to the
interface. interface ports 1-7 have. For a standard multisystem joystick, this is 1.
Should you want to use more than one of these interfaces at once, you can Should you want to use more than one of these interfaces at once, you can
use js_tg_2 and js_tg_3 as additional command line parameters for two more use js_tg_2 and js_tg_3 as additional command line parameters for two more
......
Linux Joystick driver v1.2.12 Linux Joystick driver v1.2.13
(c) 1996-1998 Vojtech Pavlik <vojtech@ucw.cz> (c) 1996-1998 Vojtech Pavlik <vojtech@ucw.cz>
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
...@@ -30,10 +30,11 @@ in the package: See the file COPYING. ...@@ -30,10 +30,11 @@ in the package: See the file COPYING.
The joystick driver for Linux provides support for a variety of joysticks The joystick driver for Linux provides support for a variety of joysticks
and similar devices. and similar devices.
These currently include various analog joysticks (both variable resistor These currently include various analog joysticks and gamepads (both
based and microswitch+resistor based), following IBM PC joystick standard, variable resistor based and microswitch+resistor based), following IBM PC
with extensions like additional hats and buttons compatible with CH joystick standard, with extensions like additional hats and buttons
Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. compatible with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button
gamepads.
In addition to these it also supports some of the new PC joysticks that In addition to these it also supports some of the new PC joysticks that
use proprietary digital protocols to communicate over the gameport, use proprietary digital protocols to communicate over the gameport,
...@@ -54,13 +55,23 @@ Amiga linux port. ...@@ -54,13 +55,23 @@ Amiga linux port.
this driver can't make complete use of, I'm very interested in hearing about this driver can't make complete use of, I'm very interested in hearing about
them. Bug reports and success stories are also welcome. them. Bug reports and success stories are also welcome.
The joystick package is available at the following FTP site: The joystick package is available at the following FTP sites:
ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/joystick-1.2.x.tar.gz ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/
ftp://artax.karlin.mff.cuni.cz/pub/linux/joystick/
The joystick driver is also included in the Linux 2.1 kernels:
ftp://linux.kernel.org/pub/linux/kernel/v2.1/
And a homepage of the driver is at: And a homepage of the driver is at:
http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
http://artax.karlin.mff.cuni.cz/~vojtech/joystick/
A mirror of the homepage is at:
http://www.trylinux.com/projects/joystick/
There is also a mailing list for the driver at: There is also a mailing list for the driver at:
...@@ -70,27 +81,42 @@ send "subscribe linux-joystick Your Name" to subscribe to it. ...@@ -70,27 +81,42 @@ send "subscribe linux-joystick Your Name" to subscribe to it.
2. Usage 2. Usage
~~~~~~~~ ~~~~~~~~
To use the driver as a standalone module, without patching the kernel, you You could have obtained this driver in two different ways - either in the
first need to edit the Makefile to meet your needs (namely whether you use joystick package or in the kernel. Because, for successful usage of the
MODVERSIONS). Then you compile the driver by typing joysticks, the utilities in the package are useful, maybe necessary, and
definitely recommended, I suggest you getting the package at some of the
above mentioned locations. The rest of this file assumes you have it.
2.1 Compiling the driver package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To compile the utilities in the joystick package, and the driver itself,
as a standalone module, you first unpack the package, and then edit the
Makefile to meet your needs (namely whether are you using versioned
modules). Then you compile it
make make
And after compiling you first And after that you install it
insmod joystick.o make install
and then In case you have not used the driver before, you'll need to create the
joystick device files in /dev so that applications can use them:
insmod joy-something.o make devs
where 'something' is the type of your joystick. See below for more precise For manual creation of the joystick devices, check the
explanation. Of course, you can insmod more than one hardware specific Documentation/devices.txt file in the Linux source tree.
module at once, if you have more than one joystick installed.
Should you not want to mess with the kernel, and just use the driver
standalone, as modules, skip the next two sections, proceeding right to 2.4,
because all you need is already done.
If you want to have the driver compiled into your kernel, you first need 2.2 Patching the kernel
to patch the kernel, so that it contains the current driver version. You do ~~~~~~~~~~~~~~~~~~~~~~~
that with a command: If you already have the most recent joystick driver in your kernel, skip
this section. If not, you need to patch the kernel, so that it contains the
current driver version. You do that with a command:
patch -Esp1 < /usr/src/joystick-1.2.x/kernel-2.x.y.diff patch -Esp1 < /usr/src/joystick-1.2.x/kernel-2.x.y.diff
...@@ -98,29 +124,101 @@ in ...@@ -98,29 +124,101 @@ in
/usr/src/linux /usr/src/linux
2.3 Compiling the kernel
~~~~~~~~~~~~~~~~~~~~~~~~
To compile joystick support into the kernel, use the kernel configuration To compile joystick support into the kernel, use the kernel configuration
scripts, and answer 'Y' to Joystick support and also to at least one of the scripts, and answer 'Y' to Joystick support and also to at least one of the
hardware specific options. hardware specific options. After doing something like
make bzlilo
you are done with the driver installation. Just reboot and the driver
should find all the connected joysticks. Read the notes about the hardware
specific drivers later in this file, though.
You can also compile the driver as modules, answering 'M' to all joystick You can also compile the driver as modules, answering 'M' to all joystick
support you want to have modules for. It is possible to have the main support you want to have modules for. It is possible to have the main
joystick driver compiled into the kernel and the hardware dependent drivers joystick driver compiled into the kernel and the hardware dependent drivers
as modules. as modules. After you compile the modules
After you're done with installation of the driver itself, you'll need to make modules
create the joystick device files in /dev so that applications can use them.
This is done by typing
make devs And install them
make modules_install
you're set, and can proceed to the next step.
2.4 Inserting the modules into the kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After installing the modules you'll first need to insert the generic
joystick driver module into the kernel
insmod joystick
and then one or more of the hardware specific modules
insmod joy-something
where 'something' is the type of your joystick. See below for more precise
explanation.
in the joystick driver's directory. For manual creation of the joystick 2.5 Verifying that it works
devices, check the Documentation/devices.txt file in the Linux source tree. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
For testing the joystick driver functionality, there is the jstest
program. You run it by typing:
2.1 Analog joysticks jstest /dev/js0
And it should show a line with the joystick values, which update as you
move the stick, and press its buttons. The axes should all be zero when the
joystick is in the center position. They should not jitter by themselves to
other close values, and they also should be steady in any other position of
the stick. They should have the full range from -32767 to 32767. If all this
is met, then it's all fine, and you can play the games. :)
If it's not, then there might be a problem. Try to calibrate the joystick,
and if it still doesn't work, read the drivers section of this file, the
troubleshooting section, and the FAQ.
2.6. Calibration
~~~~~~~~~~~~~~~~
For most joysticks you won't need any manual calibration, since the
joystick should be autocalibrated by the driver automagically. However, with
some analog joysticks, that either do not use linear resistors, or if you
want better precision, you can use the jscal program
jscal -c /dev/js0
included in the joystick package to set better correction coefficients than
what the driver would choose itself.
After calibrating the joystick you can verify if you like the new
calibration using the jstest command, and if you do, you then can save the
correction coefficients into a file
jscal -s /dev/js0 > /etc/joystick.cal
And add a line to your rc script executing that file
source /etc/joystick.cal
This way, after the next reboot your joystick will remain calibrated. You
can also add the jscal -s line to your shutdown script.
3. HW specific driver information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this section each of the separate hardware specific drivers is described.
3.1 Analog joysticks
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
The joy-analog.c uses the standard analog inputs of the gameport, and The joy-analog.c uses the standard analog inputs of the gameport, and thus
thus supports all standard joysticks. However the only types that can be supports all standard joysticks and gamepads. It also supports extensions
autodetected are: like additional hats and buttons compatible with CH Flightstick Pro,
ThrustMaster FCS or 6 and 8 button gamepads.
However the only types that can be autodetected are:
* 2-axis, 4-button joystick * 2-axis, 4-button joystick
* 3-axis, 4-button joystick * 3-axis, 4-button joystick
...@@ -204,7 +302,7 @@ Using this method you'd get a command line: ...@@ -204,7 +302,7 @@ Using this method you'd get a command line:
And it would do the same as the above explained command line. Use And it would do the same as the above explained command line. Use
whichever way you like best. whichever way you like best.
2.2 Microsoft SideWinder and Genius Digital joysticks 3.2 Microsoft SideWinder and Genius Digital joysticks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SideWinder and Genius Digital joysticks are supported by the SideWinder and Genius Digital joysticks are supported by the
joy-sidewinder.c module. All currently supported joysticks: joy-sidewinder.c module. All currently supported joysticks:
...@@ -221,7 +319,7 @@ joy-sidewinder.c module. All currently supported joysticks: ...@@ -221,7 +319,7 @@ joy-sidewinder.c module. All currently supported joysticks:
by the analog driver described above. SideWinder FreeStyle Pro and by the analog driver described above. SideWinder FreeStyle Pro and
SideWinder Force Feedback Wheel are not supported yet. SideWinder Force Feedback Wheel are not supported yet.
2.3 Logitech Digital joysticks 3.3 Logitech Digital joysticks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logitech Digital joysticks are supported by the joy-logitech.c module. It Logitech Digital joysticks are supported by the joy-logitech.c module. It
currently supports these devices: currently supports these devices:
...@@ -239,24 +337,25 @@ serial port and is not supported yet. Logitech Wingman Force, Wingman ...@@ -239,24 +337,25 @@ serial port and is not supported yet. Logitech Wingman Force, Wingman
Formula, Wingman Formula Force, Wingman Gamepad, Wingman Interceptor are USB Formula, Wingman Formula Force, Wingman Gamepad, Wingman Interceptor are USB
joysticks, with optional serial port connection, and are not supported yet. joysticks, with optional serial port connection, and are not supported yet.
2.4 Gravis GrIP 3.4 Gravis GrIP
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Gravis GrIP gamepads are supported by the joy-gravis.c module. It Gravis GrIP gamepads are supported by the joy-gravis.c module. It
currently supports only: currently supports:
* Gravis GamePad Pro * Gravis GamePad Pro
* Gravis Xterminator * Gravis Xterminator
* Gravis Blackhawk Digital
Both the pads are be autodetected, and you can even use any combination of All these pads are autodetected, and you can even use any combination of
up to two these pads either chained together or using an Y-cable on a single up to two of these pads either chained together or using an Y-cable on a single
gameport. gameport.
Gravis Blackhawk Digital, and GrIP MultiPort pads are not supported yet.
GrIP MultiPort support is in the works. Gravis Xcalibur, ArcadeXtreme, GrIP MultiPort support is in the works. Gravis Xcalibur, ArcadeXtreme,
GamePad Pro/M are joysticks/pads that probably never reached mass GamePad Pro/M are joysticks/pads that probably never reached mass
production. production. Gravis Stinger is a serial device and hopefully will be
supported in the future.
2.5 FPGaming A3D and MadCatz A3D 3.5 FPGaming A3D and MadCatz A3D
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Assasin 3D protocol created by FPGaming, is used both by FPGaming The Assasin 3D protocol created by FPGaming, is used both by FPGaming
themselves and is licensed to MadCatz. A3D devices are supported by the themselves and is licensed to MadCatz. A3D devices are supported by the
...@@ -274,22 +373,22 @@ which has the same syntax as js_an for the analog driver. ...@@ -274,22 +373,22 @@ which has the same syntax as js_an for the analog driver.
The trackball support is far from perfect at this stage of development, The trackball support is far from perfect at this stage of development,
but should be well usable. but should be well usable.
2.6 ThrustMaster DirectConnect (BSP) 3.6 ThrustMaster DirectConnect (BSP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c
module. It currently supports: module. It currently supports:
* ThrustMaster Millenium 3D Inceptor * ThrustMaster Millenium 3D Inceptor
* ThrustMaster 3D Rage Pad * ThrustMaster 3D Rage Pad
* ThrustMaster Weapon Control System III
All these drvices are autodetected, and thus no parameters to the module Both these drvices are autodetected, and thus no parameters to the module
are needed. are needed.
The only tested device was the Millenium. Rage Pad might work, and The Millenium and Rage Pad should work fine now. TM WCS III won't work,
WCS III won't, because important parts of code for that are missing. because important parts of code for that are missing. I'm not sure if it was
ever mass produced.
2.7 PDPI Lightning 4 gamecards 3.7 PDPI Lightning 4 gamecards
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PDPI Lightning 4 gamecards are supported by the joy-lightning.c module. PDPI Lightning 4 gamecards are supported by the joy-lightning.c module.
This driver is only for analog joysticks connected to the card - if you want This driver is only for analog joysticks connected to the card - if you want
...@@ -321,7 +420,7 @@ port the joystick is attached to: ...@@ -321,7 +420,7 @@ port the joystick is attached to:
See the description of analog joystick driver for explanations of m0 and See the description of analog joystick driver for explanations of m0 and
n0 values. n0 values.
2.8 Amiga 3.8 Amiga
~~~~~~~~~ ~~~~~~~~~
Amiga joysticks, connected to an Amiga, are supported by the joy-amiga.c Amiga joysticks, connected to an Amiga, are supported by the joy-amiga.c
driver. Since they can't be autodetected, the driver has a command line. driver. Since they can't be autodetected, the driver has a command line.
...@@ -339,11 +438,11 @@ the Amiga. ...@@ -339,11 +438,11 @@ the Amiga.
No more joystick types are supported now, but that should change in the No more joystick types are supported now, but that should change in the
future if I get an Amiga in the reach of my fingers. future if I get an Amiga in the reach of my fingers.
2.9 Game console and 8-bit pads and joysticks 3.9 Game console and 8-bit pads and joysticks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See joystick-parport.txt for more info. See joystick-parport.txt for more info.
3. Troubleshooting 4. Troubleshooting
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
There is quite a high probability that you run into some problems. For There is quite a high probability that you run into some problems. For
testing whether the driver works, if in doubt, use the jstest utility in testing whether the driver works, if in doubt, use the jstest utility in
...@@ -359,7 +458,8 @@ please use the joydump utility first. It's created just by typing ...@@ -359,7 +458,8 @@ please use the joydump utility first. It's created just by typing
make joydump.o make joydump.o
in the driver's directory. It is run then by typing in the directory where you unpacked the joystick package. It is run then
by typing
insmod joydump.o insmod joydump.o
...@@ -370,7 +470,7 @@ with your problem report. ...@@ -370,7 +470,7 @@ with your problem report.
Oh, and read the FAQ! :) Oh, and read the FAQ! :)
4. FAQ 5. FAQ
~~~~~~ ~~~~~~
Q: The driver doesn't find any joysticks connected to my soundcard with the Q: The driver doesn't find any joysticks connected to my soundcard with the
message "joy-something: no joysticks found" and "joy-something.o: message "joy-something: no joysticks found" and "joy-something.o:
...@@ -420,14 +520,9 @@ PC? ...@@ -420,14 +520,9 @@ PC?
A: Yes, it is possible, but it'll burn your serial port or the pad. It A: Yes, it is possible, but it'll burn your serial port or the pad. It
won't work, of course. won't work, of course.
5. Calibration Q: My joystick doesnt work with Quake / Quake 2. What's the cause?
~~~~~~~~~~~~~~ A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses
For most joysticks you won't need any manual calibration, since the for them.
joystick should be autocalibrated by the driver automagically. However, with
some analog joysticks, that either do not use linear resistors, or if you
want better precision, you can use the jscal program included in the
joystick package to set better correction coefficients than what the driver
would choose itself.
6. Programming Interface 6. Programming Interface
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -449,27 +544,27 @@ the driver provides up to 32. ...@@ -449,27 +544,27 @@ the driver provides up to 32.
Thanks to the following people who contributed code, ideas or specifications Thanks to the following people who contributed code, ideas or specifications
to the joystick driver development: to the joystick driver development:
0.1-0.5 Arthur C. Smith <asmith@cbnewsd.att.com> Arthur C. Smith <asmith@cbnewsd.att.com>
0.5 Eyal Lebedinsky <eyal@eyal.emu.id.au> Eyal Lebedinsky <eyal@eyal.emu.id.au>
0.6 Jeff Tranter <tranter@software.mitel.com> Jeff Tranter <tranter@software.mitel.com>
0.7 Carlos Puchol <cpg@cs.utexas.edu> Carlos Puchol <cpg@cs.utexas.edu>
0.7.1-0.8 Matt Rhoten <mrhoten@oz.net> Matt Rhoten <mrhoten@oz.net>
0.7.3 Dan Fandrich <dan@fch.wimsey.bc.ca> Dan Fandrich <dan@fch.wimsey.bc.ca>
0.7.3 Sverker Wilberg <sverkerw@manila.docs.uu.se> Sverker Wilberg <sverkerw@manila.docs.uu.se>
0.8 Hal Maney <maney@norden.com> Hal Maney <maney@norden.com>
0.8 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de> Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
0.9 Alan Cox <alan@lxorguk.ukuu.org.uk> Alan Cox <alan@lxorguk.ukuu.org.uk>
1.1.0 John Markus Bjorndalen <johnm@cs.uit.no> John Markus Bjorndalen <johnm@cs.uit.no>
1.1.0 Boris Muehmer <mhs@cybernet-ag.de> Boris Muehmer <mhs@cybernet-ag.de>
1.1.0 Robert W. Grubbs <rwgrubbs@vt.edu> Robert W. Grubbs <rwgrubbs@vt.edu>
1.1.0 Pete Chown <pete.chown@skygate.co.uk> Pete Chown <pete.chown@skygate.co.uk>
1.1.0 Benji York <benji@cookeville.com> Benji York <benji@cookeville.com>
1.1.3 Leslie F. Donaldson <donaldlf@cs.rose-hulman.edu> Leslie F. Donaldson <donaldlf@cs.rose-hulman.edu>
1.2.0 Eng-Jon Ong <ongej@dcs.qmw.ac.uk> Eng-Jon Ong <ongej@dcs.qmw.ac.uk>
1.2.8 Ragnar Hojland Espinosa <ragnar@lightside.ddns.org> Ragnar Hojland Espinosa <ragnar@lightside.ddns.org>
1.1.0-1.2.9 Brian Gerst <bgerst@quark.vpplus.com> Brian Gerst <bgerst@quark.vpplus.com>
1.2.3-1.2.12 Andree Borrmann <a.borrmann@tu-bs.de> Andree Borrmann <a.borrmann@tu-bs.de>
0.9.0-1.2.12 Vojtech Pavlik <vojtech@ucw.cz> Martin Giguere <zefrench@hotmail.com>
If you think you should be in this list and are not, it's possible that If you think you should be in this list and are not, it's possible that
I forgot to include you - contact me and I'll correct the error. :) I forgot to include you - contact me and I'll correct the error. :)
...@@ -506,14 +601,7 @@ about their hardware .... :( ...@@ -506,14 +601,7 @@ about their hardware .... :(
9. To do 9. To do
~~~~~~~~ ~~~~~~~~
Sooner or later I'll do these: See the TODO file for the list of things planned.
Fix possible races at open/close
Fix possible read/timer races
Make the driver SMP-friendly
Support joysticks on Linux/m68k/Atari
Support joysticks on Linux/FM-TOWNS (?)
Support even more joystick types
10. Current driver status 10. Current driver status
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -545,6 +633,7 @@ joy-db9.c: Multi1 stick - OK ...@@ -545,6 +633,7 @@ joy-db9.c: Multi1 stick - OK
Sega Saturn pad - unknown Sega Saturn pad - unknown
joy-gravis.c Gravis GamePad Pro - OK joy-gravis.c Gravis GamePad Pro - OK
Gravis Xterminator - OK Gravis Xterminator - OK
Gravis Blackhawk Digital- OK
joy-lightning.c PDPI Lightning 4 - OK joy-lightning.c PDPI Lightning 4 - OK
joy-logitech.c WingMan Extreme Digital - OK joy-logitech.c WingMan Extreme Digital - OK
CyberMan 2 - OK CyberMan 2 - OK
...@@ -555,8 +644,7 @@ joy-sidewinder.c SW 3D Pro - OK ...@@ -555,8 +644,7 @@ joy-sidewinder.c SW 3D Pro - OK
SW PP - OK SW PP - OK
SW FFP - OK SW FFP - OK
joy-thrustmaster.c Millenium 3D Inceptor - OK joy-thrustmaster.c Millenium 3D Inceptor - OK
3D-Rage pad - unknown 3D-Rage Pad - OK
WCS III - incomplete
joy-turbografx.c Multi1 stick - OK joy-turbografx.c Multi1 stick - OK
Please help me and send me success / failure reports for the drivers, Please help me and send me success / failure reports for the drivers,
......
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
# Joystick lowlevel driver configuration # Joystick lowlevel driver configuration
# #
dep_tristate ' Classic PC analog joysticks' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
dep_tristate ' Gravis GrIP gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
dep_tristate ' Logitech Digital joysticks' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
dep_tristate ' Microsoft SideWinder, Genius Digital joysticks' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
dep_tristate ' ThrustMaster DirectConnect (BSP) joysticks' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
dep_tristate ' PDPI Lightning L4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
if [ "$CONFIG_PARPORT" != "n" ]; then if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate ' NES, SNES, PSX, Multisystem gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK
dep_tristate ' Sega, Multisystem gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK
dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK
fi fi
if [ "$CONFIG_AMIGA" = "y" ]; then if [ "$CONFIG_AMIGA" = "y" ]; then
......
...@@ -148,8 +148,8 @@ int __init js_am_init(void) ...@@ -148,8 +148,8 @@ int __init js_am_init(void)
#ifdef MODULE #ifdef MODULE
void cleanup_module(void) void cleanup_module(void)
{ {
while (js_am_port) { while (js_am_port != NULL) {
if (js_am_port->devs[0]) if (js_am_port->devs[0] != NULL)
js_unregister_device(js_am_port->devs[0]); js_unregister_device(js_am_port->devs[0]);
js_am_port = js_unregister_port(js_am_port); js_am_port = js_unregister_port(js_am_port);
} }
......
...@@ -195,9 +195,9 @@ void cleanup_module(void) ...@@ -195,9 +195,9 @@ void cleanup_module(void)
int i; int i;
struct js_an_info *info; struct js_an_info *info;
while (js_an_port) { while (js_an_port != NULL) {
for (i = 0; i < js_an_port->ndevs; i++) for (i = 0; i < js_an_port->ndevs; i++)
if (js_an_port->devs[i]) if (js_an_port->devs[i] != NULL)
js_unregister_device(js_an_port->devs[i]); js_unregister_device(js_an_port->devs[i]);
info = js_an_port->info; info = js_an_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -410,9 +410,9 @@ void cleanup_module(void) ...@@ -410,9 +410,9 @@ void cleanup_module(void)
int i; int i;
struct js_as_info *info; struct js_as_info *info;
while (js_as_port) { while (js_as_port != NULL) {
for (i = 0; i < js_as_port->ndevs; i++) for (i = 0; i < js_as_port->ndevs; i++)
if (js_as_port->devs[i]) if (js_as_port->devs[i] != NULL)
js_unregister_device(js_as_port->devs[i]); js_unregister_device(js_as_port->devs[i]);
info = js_as_port->info; info = js_as_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -373,9 +373,9 @@ void cleanup_module(void) ...@@ -373,9 +373,9 @@ void cleanup_module(void)
struct js_console_info *info; struct js_console_info *info;
int i; int i;
while (js_console_port) { while (js_console_port != NULL) {
for (i = 0; i < js_console_port->ndevs; i++) for (i = 0; i < js_console_port->ndevs; i++)
if (js_console_port->devs[i]) if (js_console_port->devs[i] != NULL)
js_unregister_device(js_console_port->devs[i]); js_unregister_device(js_console_port->devs[i]);
info = js_console_port->info; info = js_console_port->info;
#ifdef USE_PARPORT #ifdef USE_PARPORT
...@@ -428,11 +428,11 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port ...@@ -428,11 +428,11 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
struct parport *pp; struct parport *pp;
if (config[0] > 0x10) if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) { if (pp == NULL) {
printk(KERN_ERR "joy-console: no such parport\n"); printk(KERN_ERR "joy-console: no such parport\n");
return port; return port;
} }
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>"); MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
MODULE_PARM(js_db9, "2i"); MODULE_PARM(js_db9, "2i");
MODULE_PARM(js_db9_2, "0-2i"); MODULE_PARM(js_db9_2, "2i");
MODULE_PARM(js_db9_3, "0-2i"); MODULE_PARM(js_db9_3, "2i");
#define JS_MULTI_STICK 0x01 #define JS_MULTI_STICK 0x01
#define JS_MULTI2_STICK 0x02 #define JS_MULTI2_STICK 0x02
...@@ -227,42 +227,6 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons) ...@@ -227,42 +227,6 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons)
return 0; return 0;
} }
/*
* js_db9_enable_ps2() enables PS/2 capabilities on a parallel port and
* switches data lines to input mode. We should use parport_change_mode() for
* that if parport present - unfortunately that does nothing and only contains
* a FIXME comment.
*/
static inline void js_db9_enable_ps2(struct js_db9_info *info)
{
#ifdef USE_PARPORT
int io = info->port->port->base;
#else
int io = info->port;
#endif
outb(0x35,io+0x402); /* enable PS/2 mode: */
outb(JS_DB9_NORMAL,io+2); /* reverse direction, enable Select signal: */
}
/*
* js_db9_disable_ps2() disables PS/2 capabilities on a parallel port
* and restores it to standard mode.
*/
static inline void js_db9_disable_ps2(struct js_db9_info *info)
{
#ifdef USE_PARPORT
int io = info->port->port->base;
#else
int io = info->port;
#endif
outb(0,io+2); /* normal direction */
outb(0x15,io+0x402); /* enable normal mode */
}
/* /*
* open callback: claim parport. * open callback: claim parport.
*/ */
...@@ -275,7 +239,9 @@ int js_db9_open(struct js_dev *dev) ...@@ -275,7 +239,9 @@ int js_db9_open(struct js_dev *dev)
#ifdef USE_PARPORT #ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY; if (parport_claim(info->port)) return -EBUSY;
#endif #endif
js_db9_enable_ps2(info);
JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */
JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */
} }
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -293,7 +259,10 @@ int js_db9_close(struct js_dev *dev) ...@@ -293,7 +259,10 @@ int js_db9_close(struct js_dev *dev)
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
if (!MOD_IN_USE) { if (!MOD_IN_USE) {
js_db9_disable_ps2(info);
JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */
JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */
#ifdef USE_PARPORT #ifdef USE_PARPORT
parport_release(info->port); parport_release(info->port);
#endif #endif
...@@ -306,7 +275,7 @@ void cleanup_module(void) ...@@ -306,7 +275,7 @@ void cleanup_module(void)
{ {
struct js_db9_info *info; struct js_db9_info *info;
while (js_db9_port) { while (js_db9_port != NULL) {
js_unregister_device(js_db9_port->devs[0]); js_unregister_device(js_db9_port->devs[0]);
info = js_db9_port->info; info = js_db9_port->info;
#ifdef USE_PARPORT #ifdef USE_PARPORT
...@@ -359,11 +328,11 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port) ...@@ -359,11 +328,11 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
struct parport *pp; struct parport *pp;
if (config[0] > 0x10) if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) { if (pp == NULL) {
printk(KERN_ERR "joy-db9: no such parport\n"); printk(KERN_ERR "joy-db9: no such parport\n");
return port; return port;
} }
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define JS_GR_STROBE_GPP 75 #define JS_GR_STROBE_GPP 75
#define JS_GR_MODE_XT 2 #define JS_GR_MODE_XT 2
#define JS_GR_MODE_BD 3
#define JS_GR_LENGTH_XT 4 #define JS_GR_LENGTH_XT 4
#define JS_GR_STROBE_XT 30 #define JS_GR_STROBE_XT 30
#define JS_GR_MAX_CHUNKS_XT 10 #define JS_GR_MAX_CHUNKS_XT 10
...@@ -189,9 +190,10 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons) ...@@ -189,9 +190,10 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons)
axes[i][0] = (data[0] >> 2) & 0x3f; axes[i][0] = (data[0] >> 2) & 0x3f;
axes[i][1] = 63 - ((data[0] >> 8) & 0x3f); axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
axes[i][2] = (data[1] >> 2) & 0x3f; axes[i][2] = (data[1] >> 2) & 0x3f;
axes[i][3] = (data[1] >> 8) & 0x3f; axes[i][3] = (data[1] >> 8) & 0x3f;
axes[i][4] = (data[2] >> 8) & 0x3f; axes[i][4] = (data[2] >> 8) & 0x3f;
axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1); axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1);
axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1); axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1); axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1);
...@@ -201,6 +203,22 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons) ...@@ -201,6 +203,22 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons)
break; break;
case JS_GR_MODE_BD:
if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
axes[i][0] = (data[0] >> 2) & 0x3f;
axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
axes[i][2] = (data[2] >> 8) & 0x3f;
axes[i][3] = ((data[2] >> 1) & 1) - ( data[2] & 1);
axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06)
| ((data[3] >> 4) & 0x18);
break;
default: default:
break; break;
...@@ -276,6 +294,28 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr) ...@@ -276,6 +294,28 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr)
break; break;
case JS_GR_MODE_BD:
for (i = 0; i < 3; i++) {
corr[i].type = JS_CORR_BROKEN;
corr[i].prec = 0;
corr[i].coef[0] = 31 - 4;
corr[i].coef[1] = 32 + 4;
corr[i].coef[2] = (1 << 29) / (32 - 14);
corr[i].coef[3] = (1 << 29) / (32 - 14);
}
for (i = 3; i < 5; i++) {
corr[i].type = JS_CORR_BROKEN;
corr[i].prec = 0;
corr[i].coef[0] = 0;
corr[i].coef[1] = 0;
corr[i].coef[2] = (1 << 29);
corr[i].coef[3] = (1 << 29);
}
break;
} }
} }
...@@ -286,9 +326,9 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr) ...@@ -286,9 +326,9 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr)
static struct js_port __init *js_gr_probe(int io, struct js_port *port) static struct js_port __init *js_gr_probe(int io, struct js_port *port)
{ {
struct js_gr_info info; struct js_gr_info info;
char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator" }; char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
char axes[] = { 0, 2, 9 }; char axes[] = { 0, 2, 9, 5};
char buttons[] = { 0, 10, 11 }; char buttons[] = { 0, 10, 11, 5};
unsigned int data[JS_GR_LENGTH_XT]; unsigned int data[JS_GR_LENGTH_XT];
int i; int i;
...@@ -298,7 +338,12 @@ static struct js_port __init *js_gr_probe(int io, struct js_port *port) ...@@ -298,7 +338,12 @@ static struct js_port __init *js_gr_probe(int io, struct js_port *port)
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP; if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP;
if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_XT; if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) {
if ((data[3] & 7) == 7)
info.mode[i] = JS_GR_MODE_XT;
if ((data[3] & 7) == 0)
info.mode[i] = JS_GR_MODE_BD;
}
} }
if (!info.mode[0] && !info.mode[1]) return port; if (!info.mode[0] && !info.mode[1]) return port;
...@@ -344,9 +389,9 @@ void cleanup_module(void) ...@@ -344,9 +389,9 @@ void cleanup_module(void)
int i; int i;
struct js_gr_info *info; struct js_gr_info *info;
while (js_gr_port) { while (js_gr_port != NULL) {
for (i = 0; i < js_gr_port->ndevs; i++) for (i = 0; i < js_gr_port->ndevs; i++)
if (js_gr_port->devs[i]) if (js_gr_port->devs[i] != NULL)
js_unregister_device(js_gr_port->devs[i]); js_unregister_device(js_gr_port->devs[i]);
info = js_gr_port->info; info = js_gr_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -352,9 +352,9 @@ void cleanup_module(void) ...@@ -352,9 +352,9 @@ void cleanup_module(void)
int cal[4] = {59, 59, 59, 59}; int cal[4] = {59, 59, 59, 59};
struct js_l4_info *info; struct js_l4_info *info;
while (js_l4_port) { while (js_l4_port != NULL) {
for (i = 0; i < js_l4_port->ndevs; i++) for (i = 0; i < js_l4_port->ndevs; i++)
if (js_l4_port->devs[i]) if (js_l4_port->devs[i] != NULL)
js_unregister_device(js_l4_port->devs[i]); js_unregister_device(js_l4_port->devs[i]);
info = js_l4_port->info; info = js_l4_port->info;
js_l4_setcal(info->port, cal); js_l4_setcal(info->port, cal);
......
...@@ -361,7 +361,7 @@ void cleanup_module(void) ...@@ -361,7 +361,7 @@ void cleanup_module(void)
{ {
struct js_lt_info *info; struct js_lt_info *info;
while (js_lt_port) { while (js_lt_port != NULL) {
js_unregister_device(js_lt_port->devs[0]); js_unregister_device(js_lt_port->devs[0]);
info = js_lt_port->info; info = js_lt_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -88,6 +88,11 @@ static void __init js_sw_init_digital(int io) ...@@ -88,6 +88,11 @@ static void __init js_sw_init_digital(int io)
} while (delays[i++]); } while (delays[i++]);
__restore_flags(flags); __restore_flags(flags);
for (i = 0; i < 4; i++) {
udelay(300);
outb(0xff, io);
}
return; return;
} }
...@@ -137,19 +142,21 @@ static int js_sw_read_packet(int io, int l1, int l2, int strobe, __u64 *data) ...@@ -137,19 +142,21 @@ static int js_sw_read_packet(int io, int l1, int l2, int strobe, __u64 *data)
__restore_flags(flags); __restore_flags(flags);
*data = 0; *data = 0;
t = i;
if (t == l1) { if (i == l1) {
t = i > 64 ? 64 : i;
for (i = 0; i < t; i++) for (i = 0; i < t; i++)
*data |= (__u64) (buf[i] & 1) << i; *data |= (__u64) (buf[i] & 1) << i;
return t; return t;
} }
if (t == l2) { if (i == l2) {
t = i > 22 ? 22 : i;
for (i = 0; i < t; i++) for (i = 0; i < t; i++)
*data |= (__u64) buf[i] << (3 * i); *data |= (__u64) buf[i] << (3 * i);
return t * 3; return t * 3;
} }
return t;
return i;
} }
/* /*
...@@ -199,7 +206,7 @@ static int js_sw_read(void *xinfo, int **axes, int **buttons) ...@@ -199,7 +206,7 @@ static int js_sw_read(void *xinfo, int **axes, int **buttons)
i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data); i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data);
} else { } else {
i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data); i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data);
if (i == 192) info->optimize = 1; if (i == 198) info->optimize = 1;
} }
if (i < 60) { if (i < 60) {
...@@ -456,9 +463,9 @@ void cleanup_module(void) ...@@ -456,9 +463,9 @@ void cleanup_module(void)
int i; int i;
struct js_sw_info *info; struct js_sw_info *info;
while (js_sw_port) { while (js_sw_port != NULL) {
for (i = 0; i < js_sw_port->ndevs; i++) for (i = 0; i < js_sw_port->ndevs; i++)
if (js_sw_port->devs[i]) if (js_sw_port->devs[i] != NULL)
js_unregister_device(js_sw_port->devs[i]); js_unregister_device(js_sw_port->devs[i]);
info = js_sw_port->info; info = js_sw_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -39,12 +39,12 @@ ...@@ -39,12 +39,12 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h> #include <linux/string.h>
#define JS_TM_MAX_START 200 #define JS_TM_MAX_START 400
#define JS_TM_MAX_STROBE 15 #define JS_TM_MAX_STROBE 25
#define JS_TM_MAX_LENGTH 13 #define JS_TM_MAX_LENGTH 13
#define JS_TM_MODE_M3DI 1 #define JS_TM_MODE_M3DI 1
#define JS_TM_MODE_3DRP 2 #define JS_TM_MODE_3DRP 3
#define JS_TM_MODE_WCS3 4 #define JS_TM_MODE_WCS3 4
#define JS_TM_MODE_MAX 5 /* Last mode + 1 */ #define JS_TM_MODE_MAX 5 /* Last mode + 1 */
...@@ -73,7 +73,7 @@ struct js_tm_info { ...@@ -73,7 +73,7 @@ struct js_tm_info {
unsigned char mode; unsigned char mode;
}; };
static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x22, 0x00, 0x00}; static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x00, 0x22, 0x00};
/* /*
* js_tm_read_packet() reads a ThrustMaster packet. * js_tm_read_packet() reads a ThrustMaster packet.
...@@ -120,6 +120,7 @@ static int js_tm_read_packet(int io, unsigned char *data) ...@@ -120,6 +120,7 @@ static int js_tm_read_packet(int io, unsigned char *data)
i++; i++;
} }
} else { /* Start bit */ } else { /* Start bit */
data[i] = 0;
error |= ~v & 1; error |= ~v & 1;
j++; j++;
} }
...@@ -251,10 +252,10 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js ...@@ -251,10 +252,10 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js
static struct js_port __init *js_tm_probe(int io, struct js_port *port) static struct js_port __init *js_tm_probe(int io, struct js_port *port)
{ {
struct js_tm_info info; struct js_tm_info info;
char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", NULL,
"ThrustMaster Rage 3D Gamepad", NULL, "ThrustMaster WCS III" }; "ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" };
char axes[JS_TM_MODE_MAX] = { 0, 6, 2, 0, 0 }; char axes[JS_TM_MODE_MAX] = { 0, 6, 0, 2, 0 };
char buttons[JS_TM_MODE_MAX] = { 0, 5, 10, 0, 0 }; char buttons[JS_TM_MODE_MAX] = { 0, 5, 0, 10, 0 };
unsigned char data[JS_TM_MAX_LENGTH]; unsigned char data[JS_TM_MAX_LENGTH];
unsigned char u; unsigned char u;
...@@ -320,7 +321,7 @@ void cleanup_module(void) ...@@ -320,7 +321,7 @@ void cleanup_module(void)
{ {
struct js_tm_info *info; struct js_tm_info *info;
while (js_tm_port) { while (js_tm_port != NULL) {
js_unregister_device(js_tm_port->devs[0]); js_unregister_device(js_tm_port->devs[0]);
info = js_tm_port->info; info = js_tm_port->info;
release_region(info->io, 1); release_region(info->io, 1);
......
...@@ -42,21 +42,26 @@ ...@@ -42,21 +42,26 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_PARM(js_tg, "2i"); MODULE_PARM(js_tg, "2-8i");
MODULE_PARM(js_tg_2, "0-2i"); MODULE_PARM(js_tg_2, "2-8i");
MODULE_PARM(js_tg_3, "0-2i"); MODULE_PARM(js_tg_3, "2-8i");
#define JS_TG_BUTTON 3 #define JS_TG_BUTTON1 0x08
#define JS_TG_UP 4 #define JS_TG_UP 0x10
#define JS_TG_DOWN 5 #define JS_TG_DOWN 0x20
#define JS_TG_LEFT 6 #define JS_TG_LEFT 0x40
#define JS_TG_RIGHT 7 #define JS_TG_RIGHT 0x80
#define JS_TG_BUTTON2 0x02
#define JS_TG_BUTTON3 0x04
#define JS_TG_BUTTON4 0x01
#define JS_TG_BUTTON5 0x08
static struct js_port* js_tg_port = NULL; static struct js_port* js_tg_port = NULL;
static int js_tg[] __initdata = { -1, 0 }; static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_2[] __initdata = { -1, 0 }; static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_3[] __initdata = { -1, 0 }; static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
struct js_tg_info { struct js_tg_info {
#ifdef USE_PARPORT #ifdef USE_PARPORT
...@@ -64,7 +69,7 @@ struct js_tg_info { ...@@ -64,7 +69,7 @@ struct js_tg_info {
#else #else
int port; /* hw port */ int port; /* hw port */
#endif #endif
int count; /* number of joysticks */ int sticks; /* joysticks connected */
}; };
/* /*
...@@ -74,17 +79,21 @@ struct js_tg_info { ...@@ -74,17 +79,21 @@ struct js_tg_info {
static int js_tg_read(void *xinfo, int **axes, int **buttons) static int js_tg_read(void *xinfo, int **axes, int **buttons)
{ {
struct js_tg_info *info = xinfo; struct js_tg_info *info = xinfo;
int data, i; int data1, data2, i;
for (i = 0; i < info->count; i++) { for (i = 0; i < 7; i++)
if ((info->sticks >> i) & 1) {
JS_PAR_DATA_OUT(~(1 << i), info->port); JS_PAR_DATA_OUT(~(1 << i), info->port);
data = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT; data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT;
axes[i][0] = ((data >> JS_TG_RIGHT) & 1) - ((data >> JS_TG_LEFT) & 1); axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0);
axes[i][1] = ((data >> JS_TG_DOWN ) & 1) - ((data >> JS_TG_UP ) & 1); axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP ) ? 1 : 0);
buttons[i][0] = (data >> JS_TG_BUTTON) & 1; buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0)
| ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0)
| ((data2 & JS_TG_BUTTON5) ? 0x10 : 0);
} }
...@@ -97,10 +106,14 @@ static int js_tg_read(void *xinfo, int **axes, int **buttons) ...@@ -97,10 +106,14 @@ static int js_tg_read(void *xinfo, int **axes, int **buttons)
int js_tg_open(struct js_dev *dev) int js_tg_open(struct js_dev *dev)
{ {
#ifdef USE_PARPORT
struct js_tg_info *info = dev->port->info; struct js_tg_info *info = dev->port->info;
if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
if (!MOD_IN_USE) {
#ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY;
#endif #endif
JS_PAR_CTRL_OUT(0x04, info->port);
}
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
return 0; return 0;
} }
...@@ -111,13 +124,15 @@ int js_tg_open(struct js_dev *dev) ...@@ -111,13 +124,15 @@ int js_tg_open(struct js_dev *dev)
int js_tg_close(struct js_dev *dev) int js_tg_close(struct js_dev *dev)
{ {
#ifdef USE_PARPORT
struct js_tg_info *info = dev->port->info; struct js_tg_info *info = dev->port->info;
#endif
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
if (!MOD_IN_USE) {
JS_PAR_CTRL_OUT(0x00, info->port);
#ifdef USE_PARPORT #ifdef USE_PARPORT
if (!MOD_IN_USE) parport_release(info->port); parport_release(info->port);
#endif #endif
}
return 0; return 0;
} }
...@@ -127,9 +142,9 @@ void cleanup_module(void) ...@@ -127,9 +142,9 @@ void cleanup_module(void)
struct js_tg_info *info; struct js_tg_info *info;
int i; int i;
while (js_tg_port) { while (js_tg_port != NULL) {
for (i = 0; i < js_tg_port->ndevs; i++) for (i = 0; i < js_tg_port->ndevs; i++)
if (js_tg_port->devs[i]) if (js_tg_port->devs[i] != NULL)
js_unregister_device(js_tg_port->devs[i]); js_unregister_device(js_tg_port->devs[i]);
info = js_tg_port->info; info = js_tg_port->info;
#ifdef USE_PARPORT #ifdef USE_PARPORT
...@@ -147,19 +162,20 @@ void cleanup_module(void) ...@@ -147,19 +162,20 @@ void cleanup_module(void)
* tg gamepads. * tg gamepads.
*/ */
static void __init js_tg_init_corr(int count, struct js_corr **corr) static void __init js_tg_init_corr(int sticks, struct js_corr **corr)
{ {
int i, j; int i, j;
for (i = 0; i < count; i++) for (i = 0; i < 7; i++)
for (j = 0; j < 2; j++) { if ((sticks >> i) & 1)
corr[i][j].type = JS_CORR_BROKEN; for (j = 0; j < 2; j++) {
corr[i][j].prec = 0; corr[i][j].type = JS_CORR_BROKEN;
corr[i][j].coef[0] = 0; corr[i][j].prec = 0;
corr[i][j].coef[1] = 0; corr[i][j].coef[0] = 0;
corr[i][j].coef[2] = (1 << 29); corr[i][j].coef[1] = 0;
corr[i][j].coef[3] = (1 << 29); corr[i][j].coef[2] = (1 << 29);
} corr[i][j].coef[3] = (1 << 29);
}
} }
/* /*
...@@ -168,53 +184,65 @@ static void __init js_tg_init_corr(int count, struct js_corr **corr) ...@@ -168,53 +184,65 @@ static void __init js_tg_init_corr(int count, struct js_corr **corr)
static struct js_port __init *js_tg_probe(int *config, struct js_port *port) static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
{ {
struct js_tg_info info; struct js_tg_info iniinfo;
struct js_tg_info *info = &iniinfo;
int i; int i;
if (config[0] < 0) return port; if (config[0] < 0) return port;
if (config[1] < 1 || config[1] > 8) return port;
#ifdef USE_PARPORT #ifdef USE_PARPORT
{ {
struct parport *pp; struct parport *pp;
if (config[0] > 0x10) if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next); for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--; for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) { if (pp == NULL) {
printk(KERN_ERR "joy-tg: no such parport\n"); printk(KERN_ERR "joy-tg: no such parport\n");
return port; return port;
} }
info.port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!info.port) if (!info->port)
return port; return port;
} }
#else #else
info.port = config[0]; info->port = config[0];
if (check_region(info.port, 3)) return port; if (check_region(info->port, 3)) return port;
request_region(info.port, 3, "joystick (turbografx)"); request_region(info->port, 3, "joystick (turbografx)");
#endif #endif
info.count = config[1]; port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
info = port->info;
port = js_register_port(port, &info, info.count, sizeof(struct js_tg_info), js_tg_read);
info->sticks = 0;
for (i = 0; i < info.count; i++) for (i = 0; i < 7; i++)
if (config[i+1] > 0 && config[i+1] < 6) {
#ifdef USE_PARPORT #ifdef USE_PARPORT
printk(KERN_INFO "js%d: Multisystem joystick on %s\n", printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
js_register_device(port, i, 2, 1, "Multisystem joystick", js_tg_open, js_tg_close), js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
info.port->port->name); info->port->port->name);
#else #else
printk(KERN_INFO "js%d: Multisystem joystick at %#x\n", printk(KERN_INFO "js%d: Multisystem joystick at %#x\n",
js_register_device(port, i, 2, 1, "Multisystem joystick", js_tg_open, js_tg_close), js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
info.port); info->port);
#endif #endif
info->sticks |= (1 << i);
}
js_tg_init_corr(info.count, port->corr); if (!info->sticks) {
#ifdef USE_PARPORT
parport_unregister_device(info->port);
#else
release_region(info->port, 3);
#endif
return port;
}
js_tg_init_corr(info->sticks, port->corr);
return port; return port;
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/segment.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -456,14 +457,14 @@ static void js_do_timer(unsigned long data) ...@@ -456,14 +457,14 @@ static void js_do_timer(unsigned long data)
struct js_dev *curd = js_dev; struct js_dev *curd = js_dev;
unsigned long flags; unsigned long flags;
while (curp) { while (curp != NULL) {
curp->read(curp->info, curp->axes, curp->buttons); curp->read(curp->info, curp->axes, curp->buttons);
curp = curp->next; curp = curp->next;
} }
spin_lock_irqsave(&js_lock, flags); spin_lock_irqsave(&js_lock, flags);
while (curd) { while (curd != NULL) {
if (data) { if (data) {
js_process_data(curd); js_process_data(curd);
js_sync_buff(curd); js_sync_buff(curd);
...@@ -643,12 +644,12 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count) ...@@ -643,12 +644,12 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
if (orig_tail == jd->tail) { if (orig_tail == jd->tail) {
new_tail = curl->tail; new_tail = curl->tail;
curl = jd->list; curl = jd->list;
while (curl && curl->tail != jd->tail) { while (curl != NULL && curl->tail != jd->tail) {
if (ROT(jd->bhead, new_tail, curl->tail) || if (ROT(jd->bhead, new_tail, curl->tail) ||
(jd->bhead == curl->tail)) new_tail = curl->tail; (jd->bhead == curl->tail)) new_tail = curl->tail;
curl = curl->next; curl = curl->next;
} }
if (!curl) jd->tail = new_tail; if (curl == NULL) jd->tail = new_tail;
} }
spin_unlock_irqrestore(&js_lock, flags); spin_unlock_irqrestore(&js_lock, flags);
...@@ -855,42 +856,51 @@ static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un ...@@ -855,42 +856,51 @@ static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
static int js_open(struct inode *inode, struct file *file) static int js_open(struct inode *inode, struct file *file)
{ {
struct js_list *curl; struct js_list *curl, *new;
struct js_dev *jd = js_dev; struct js_dev *jd = js_dev;
int i = MINOR(inode->i_rdev); int i = MINOR(inode->i_rdev);
unsigned long flags; unsigned long flags;
int result; int result;
if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
return -EINVAL; return -EINVAL;
while (i > 0 && jd) { spin_lock_irqsave(&js_lock, flags);
while (i > 0 && jd != NULL) {
jd = jd->next; jd = jd->next;
i--; i--;
} }
if (!jd) return -ENODEV; spin_unlock_irqrestore(&js_lock, flags);
if (jd == NULL) return -ENODEV;
if ((result = jd->open(jd))) return result; if ((result = jd->open(jd))) return result;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
if (!js_use_count++) js_do_timer(0); if (!js_use_count++) js_do_timer(0);
curl = jd->list; if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL)) != NULL) {
spin_lock_irqsave(&js_lock, flags); spin_lock_irqsave(&js_lock, flags);
jd->list = kmalloc(sizeof(struct js_list), GFP_KERNEL); curl = jd->list;
jd->list->next = curl;
jd->list->dev = jd;
jd->list->startup = 0;
jd->list->tail = GOB(jd->bhead);
spin_unlock_irqrestore(&js_lock, flags); jd->list = new;
jd->list->next = curl;
jd->list->dev = jd;
jd->list->startup = 0;
jd->list->tail = GOB(jd->bhead);
file->private_data = jd->list;
file->private_data = jd->list; spin_unlock_irqrestore(&js_lock, flags);
return 0; } else {
result = -ENOMEM;
}
return result;
} }
/* /*
...@@ -915,11 +925,11 @@ static void js_release(struct inode *inode, struct file *file) ...@@ -915,11 +925,11 @@ static void js_release(struct inode *inode, struct file *file)
while (*curp && (*curp != curl)) curp = &((*curp)->next); while (*curp && (*curp != curl)) curp = &((*curp)->next);
*curp = (*curp)->next; *curp = (*curp)->next;
if (jd->list) if (jd->list != NULL)
if (curl->tail == jd->tail) { if (curl->tail == jd->tail) {
curl = jd->list; curl = jd->list;
new_tail = curl->tail; new_tail = curl->tail;
while (curl && curl->tail != jd->tail) { while (curl != NULL && curl->tail != jd->tail) {
if (ROT(jd->bhead, new_tail, curl->tail) || if (ROT(jd->bhead, new_tail, curl->tail) ||
(jd->bhead == curl->tail)) new_tail = curl->tail; (jd->bhead == curl->tail)) new_tail = curl->tail;
curl = curl->next; curl = curl->next;
...@@ -957,7 +967,7 @@ static void js_dump_mem(void) ...@@ -957,7 +967,7 @@ static void js_dump_mem(void)
printk(",--- Dumping Devices:\n"); printk(",--- Dumping Devices:\n");
printk("| js_dev = %x\n", (int) js_dev); printk("| js_dev = %x\n", (int) js_dev);
while (curd) { while (curd != NULL) {
printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n", printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
curd->next ? "|":"`", curd->next ? "|":"`",
(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io); (int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
...@@ -967,7 +977,7 @@ static void js_dump_mem(void) ...@@ -967,7 +977,7 @@ static void js_dump_mem(void)
printk(">--- Dumping ports:\n"); printk(">--- Dumping ports:\n");
printk("| js_port = %x\n", (int) js_port); printk("| js_port = %x\n", (int) js_port);
while (curp) { while (curp != NULL) {
printk("| %s-port %x, next %x, io %#x, devices %d\n", printk("| %s-port %x, next %x, io %#x, devices %d\n",
curp->next ? "|":"`", curp->next ? "|":"`",
(int) curp, (int) curp->next, curp->io, curp->ndevs); (int) curp, (int) curp->next, curp->io, curp->ndevs);
...@@ -995,35 +1005,39 @@ struct js_port *js_register_port(struct js_port *port, ...@@ -995,35 +1005,39 @@ struct js_port *js_register_port(struct js_port *port,
{ {
struct js_port **ptrp = &js_port; struct js_port **ptrp = &js_port;
struct js_port *curp; struct js_port *curp;
void *all;
int i; int i;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&js_lock, flags); if ((all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)) == NULL)
return NULL;
while (*ptrp) ptrp=&((*ptrp)->next); curp = all;
*ptrp = curp = kmalloc(sizeof(struct js_port), GFP_KERNEL);
curp->next = NULL; curp->next = NULL;
curp->prev = port; curp->prev = port;
curp->read = read; curp->read = read;
curp->ndevs = devs; curp->ndevs = devs;
curp->devs = kmalloc(devs * sizeof(struct js_dev*), GFP_KERNEL); curp->devs = all += sizeof(struct js_port);
for (i = 0; i < devs; i++) curp->devs[i] = NULL;
for (i = 0; i < devs; i++)
curp->devs[i] = NULL;
curp->axes = kmalloc(devs * sizeof(int*), GFP_KERNEL); curp->axes = all += devs * sizeof(void*);
curp->buttons = kmalloc(devs * sizeof(int*), GFP_KERNEL); curp->buttons = (void*) all += devs * sizeof(void*);
curp->corr = kmalloc(devs * sizeof(struct js_corr*), GFP_KERNEL); curp->corr = all += devs * sizeof(void*);
if (infos) { if (infos) {
curp->info = kmalloc(infos, GFP_KERNEL); curp->info = all += devs * sizeof(void*);
memcpy(curp->info, info, infos); memcpy(curp->info, info, infos);
} else { } else {
curp->info = NULL; curp->info = NULL;
} }
spin_lock_irqsave(&js_lock, flags);
while (*ptrp != NULL) ptrp=&((*ptrp)->next);
*ptrp = curp;
spin_unlock_irqrestore(&js_lock, flags); spin_unlock_irqrestore(&js_lock, flags);
return curp; return curp;
...@@ -1037,19 +1051,14 @@ struct js_port *js_unregister_port(struct js_port *port) ...@@ -1037,19 +1051,14 @@ struct js_port *js_unregister_port(struct js_port *port)
spin_lock_irqsave(&js_lock, flags); spin_lock_irqsave(&js_lock, flags);
while (*curp && (*curp != port)) curp = &((*curp)->next); while (*curp != NULL && (*curp != port)) curp = &((*curp)->next);
*curp = (*curp)->next; *curp = (*curp)->next;
spin_unlock_irqrestore(&js_lock, flags);
prev = port->prev; prev = port->prev;
kfree(port->devs);
kfree(port->axes);
kfree(port->buttons);
kfree(port->corr);
if (port->info) kfree(port->info);
kfree(port); kfree(port);
spin_unlock_irqrestore(&js_lock, flags);
return prev; return prev;
} }
...@@ -1058,17 +1067,16 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons, ...@@ -1058,17 +1067,16 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
{ {
struct js_dev **ptrd = &js_dev; struct js_dev **ptrd = &js_dev;
struct js_dev *curd; struct js_dev *curd;
void *all;
int i = 0; int i = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&js_lock, flags); if ((all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
while (*ptrd) { axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)) == NULL)
ptrd=&(*ptrd)->next; return -1;
i++;
}
*ptrd = curd = kmalloc(sizeof(struct js_dev), GFP_KERNEL); curd = all;
curd->next = NULL; curd->next = NULL;
curd->list = NULL; curd->list = NULL;
...@@ -1083,20 +1091,25 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons, ...@@ -1083,20 +1091,25 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
curd->num_axes = axes; curd->num_axes = axes;
curd->num_buttons = buttons; curd->num_buttons = buttons;
curd->name = kmalloc(strlen(name) + 1, GFP_KERNEL); curd->cur.axes = all += sizeof(struct js_dev);
strcpy(curd->name, name); curd->cur.buttons = all += axes * sizeof(int);
curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int);
curd->new.buttons = all += axes * sizeof(int);
curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int);
curd->cur.axes = kmalloc(axes * sizeof(int), GFP_KERNEL); curd->name = all += axes * sizeof(struct js_corr);
curd->cur.buttons = kmalloc((((buttons - 1) >> 5) + 1) * sizeof(int), GFP_KERNEL); strcpy(curd->name, name);
curd->new.axes = kmalloc(axes * sizeof(int), GFP_KERNEL);
curd->new.buttons = kmalloc((((buttons -1 ) >> 5) + 1) * sizeof(int), GFP_KERNEL);
curd->corr = kmalloc(axes * sizeof(struct js_corr), GFP_KERNEL);
port->devs[number] = curd; port->devs[number] = curd;
port->axes[number] = curd->new.axes; port->axes[number] = curd->new.axes;
port->buttons[number] = curd->new.buttons; port->buttons[number] = curd->new.buttons;
port->corr[number] = curd->corr; port->corr[number] = curd->corr;
spin_lock_irqsave(&js_lock, flags);
while (*ptrd != NULL) { ptrd=&(*ptrd)->next; i++; }
*ptrd = curd;
spin_unlock_irqrestore(&js_lock, flags); spin_unlock_irqrestore(&js_lock, flags);
return i; return i;
...@@ -1109,17 +1122,11 @@ void js_unregister_device(struct js_dev *dev) ...@@ -1109,17 +1122,11 @@ void js_unregister_device(struct js_dev *dev)
spin_lock_irqsave(&js_lock, flags); spin_lock_irqsave(&js_lock, flags);
while (*curd && (*curd != dev)) curd = &((*curd)->next); while (*curd != NULL && (*curd != dev)) curd = &((*curd)->next);
*curd = (*curd)->next; *curd = (*curd)->next;
spin_unlock_irqrestore(&js_lock, flags); spin_unlock_irqrestore(&js_lock, flags);
kfree(dev->cur.axes);
kfree(dev->new.axes);
kfree(dev->cur.buttons);
kfree(dev->new.buttons);
kfree(dev->corr);
kfree(dev->name);
kfree(dev); kfree(dev);
} }
......
...@@ -374,13 +374,11 @@ affs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -374,13 +374,11 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
/* /*
* Make sure the directory is empty and the dentry isn't busy. * Make sure the directory is empty and the dentry isn't busy.
*/ */
if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
retval = -ENOTEMPTY; retval = -ENOTEMPTY;
if (!empty_dir(bh,AFFS_I2HSIZE(inode))) if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
goto rmdir_done; goto rmdir_done;
retval = -EBUSY; retval = -EBUSY;
if (dentry->d_count > 1) if (!list_empty(&dentry->d_hash))
goto rmdir_done; goto rmdir_done;
if ((retval = affs_remove_header(bh,inode)) < 0) if ((retval = affs_remove_header(bh,inode)) < 0)
......
...@@ -520,7 +520,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ...@@ -520,7 +520,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
struct coda_inode_info *dircnp; struct coda_inode_info *dircnp;
const char *name = de->d_name.name; const char *name = de->d_name.name;
int len = de->d_name.len; int len = de->d_name.len;
int error, rehash = 0; int error;
ENTRY; ENTRY;
coda_vfs_stat.rmdir++; coda_vfs_stat.rmdir++;
...@@ -535,24 +535,13 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ...@@ -535,24 +535,13 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
if (len > CFS_MAXNAMLEN) if (len > CFS_MAXNAMLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
error = -EBUSY; if (!list_empty(&de->d_hash))
if (de->d_count > 1) { return -EBUSY;
/* Attempt to shrink child dentries ... */
shrink_dcache_parent(de);
if (de->d_count > 1)
return error;
}
/* Drop the dentry to force a new lookup */
if (!list_empty(&de->d_hash)) {
d_drop(de);
rehash = 1;
}
/* update i_nlink and free the inode before unlinking; /* update i_nlink and free the inode before unlinking;
if rmdir fails a new lookup set i_nlink right.*/ if rmdir fails a new lookup set i_nlink right.*/
if (de->d_inode->i_nlink) if (de->d_inode->i_nlink)
de->d_inode->i_nlink --; de->d_inode->i_nlink --;
d_delete(de);
error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len); error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
...@@ -561,10 +550,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ...@@ -561,10 +550,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
return error; return error;
} }
if (rehash)
d_add(de, NULL);
/* XXX how can mtime be set? */
return 0; return 0;
} }
......
...@@ -661,27 +661,11 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) ...@@ -661,27 +661,11 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
if (le32_to_cpu(de->inode) != inode->i_ino) if (le32_to_cpu(de->inode) != inode->i_ino)
goto end_rmdir; goto end_rmdir;
/*
* Prune any child dentries so that this dentry becomes negative.
*/
if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
if (!empty_dir (inode)) if (!empty_dir (inode))
retval = -ENOTEMPTY; retval = -ENOTEMPTY;
else if (le32_to_cpu(de->inode) != inode->i_ino) else if (le32_to_cpu(de->inode) != inode->i_ino)
retval = -ENOENT; retval = -ENOENT;
else { else {
if (dentry->d_count > 1) {
/*
* Are we deleting the last instance of a busy directory?
* Better clean up if so.
*
* Make directory empty (it will be truncated when finally
* dereferenced). This also inhibits ext2_add_entry.
*/
inode->i_size = 0;
}
retval = ext2_delete_entry (de, bh); retval = ext2_delete_entry (de, bh);
dir->i_version = ++event; dir->i_version = ++event;
} }
...@@ -698,6 +682,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) ...@@ -698,6 +682,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
inode->i_nlink); inode->i_nlink);
inode->i_version = ++event; inode->i_version = ++event;
inode->i_nlink = 0; inode->i_nlink = 0;
inode->i_size = 0;
mark_inode_dirty(inode); mark_inode_dirty(inode);
dir->i_nlink--; dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
......
...@@ -352,7 +352,7 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry) ...@@ -352,7 +352,7 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
goto hfs_rmdir_put; goto hfs_rmdir_put;
error = -EBUSY; error = -EBUSY;
if (dentry->d_count > 1) if (!list_empty(&dentry->d_hash))
goto hfs_rmdir_put; goto hfs_rmdir_put;
if (/* we only have to worry about 2 and 3 for mount points */ if (/* we only have to worry about 2 and 3 for mount points */
......
...@@ -452,7 +452,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry) ...@@ -452,7 +452,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
retval = -ENOENT; retval = -ENOENT;
goto end_rmdir; goto end_rmdir;
} }
if (dentry->d_count > 1) { if (!list_empty(&dentry->d_hash)) {
retval = -EBUSY; retval = -EBUSY;
goto end_rmdir; goto end_rmdir;
} }
......
...@@ -452,8 +452,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -452,8 +452,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
if (res) if (res)
goto rmdir_done; goto rmdir_done;
res = -EBUSY; res = -EBUSY;
shrink_dcache_parent(dentry); if (!list_empty(&dentry->d_hash)) {
if (dentry->d_count > 1) {
#ifdef MSDOS_DEBUG #ifdef MSDOS_DEBUG
printk("msdos_rmdir: %s/%s busy, d_count=%d\n", printk("msdos_rmdir: %s/%s busy, d_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count); dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
......
...@@ -881,7 +881,6 @@ static inline int do_rmdir(const char * name) ...@@ -881,7 +881,6 @@ static inline int do_rmdir(const char * name)
error = -ENOENT; error = -ENOENT;
if (!dentry->d_inode) if (!dentry->d_inode)
goto exit; goto exit;
/* /*
* The dentry->d_count stuff confuses d_delete() enough to * The dentry->d_count stuff confuses d_delete() enough to
* not kill the inode from under us while it is locked. This * not kill the inode from under us while it is locked. This
...@@ -919,8 +918,29 @@ static inline int do_rmdir(const char * name) ...@@ -919,8 +918,29 @@ static inline int do_rmdir(const char * name)
DQUOT_INIT(dir->d_inode); DQUOT_INIT(dir->d_inode);
if (dentry->d_count > 1) /*
* We try to drop the dentry early: we should have
* a usage count of 2 if we're the only user of this
* dentry, and if that is true (possibly after pruning
* the dcache), then we drop the dentry now.
*
* A low-level filesystem can, if it choses, legally
* do a
*
* if (!list_empty(&dentry->d_hash))
* return -EBUSY;
*
* if it cannot handle the case of removing a directory
* that is still in use by something else..
*/
switch (dentry->d_count) {
default:
shrink_dcache_parent(dentry); shrink_dcache_parent(dentry);
if (dentry->d_count != 2)
break;
case 2:
d_drop(dentry);
}
error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry); error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
......
...@@ -24,11 +24,6 @@ ...@@ -24,11 +24,6 @@
#include <linux/ncp_fs.h> #include <linux/ncp_fs.h>
#include "ncplib_kernel.h" #include "ncplib_kernel.h"
#ifndef shrink_dcache_parent
#define shrink_dcache_parent(dentry) shrink_dcache_sb((dentry)->d_sb)
#endif
struct ncp_dirent { struct ncp_dirent {
struct nw_info_struct i; struct nw_info_struct i;
struct nw_search_sequence s; /* given back for i */ struct nw_search_sequence s; /* given back for i */
...@@ -999,17 +994,14 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -999,17 +994,14 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n"); printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
goto out; goto out;
} }
error = -EIO; error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir))) if (!ncp_conn_valid(NCP_SERVER(dir)))
goto out; goto out;
if (dentry->d_count > 1) error = -EBUSY;
{ if (!list_empty(&dentry->d_hash))
shrink_dcache_parent(dentry); goto out;
error = -EBUSY;
if (dentry->d_count > 1)
goto out;
}
strncpy(_name, dentry->d_name.name, dentry->d_name.len); strncpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0'; _name[dentry->d_name.len] = '\0';
...@@ -1023,7 +1015,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1023,7 +1015,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
if (!result) if (!result)
{ {
ncp_invalid_dir_cache(dir); ncp_invalid_dir_cache(dir);
d_delete(dentry);
error = 0; error = 0;
} }
out: out:
......
...@@ -721,7 +721,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -721,7 +721,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
*/ */
static int nfs_rmdir(struct inode *dir, struct dentry *dentry) static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
int error, rehash = 0; int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name); dir->i_dev, dir->i_ino, dentry->d_name.name);
...@@ -731,39 +731,24 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -731,39 +731,24 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
goto out; goto out;
error = -EBUSY; error = -EBUSY;
if (dentry->d_count > 1) { if (!list_empty(&dentry->d_hash))
/* Attempt to shrink child dentries ... */ goto out;
shrink_dcache_parent(dentry);
if (dentry->d_count > 1)
goto out;
}
#ifdef NFS_PARANOIA #ifdef NFS_PARANOIA
if (dentry->d_inode->i_count > 1) if (dentry->d_inode->i_count > 1)
printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n", printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_inode->i_count, dentry->d_inode->i_nlink); dentry->d_inode->i_count, dentry->d_inode->i_nlink);
#endif #endif
/*
* Unhash the dentry while we remove the directory.
*/
if (!list_empty(&dentry->d_hash)) {
d_drop(dentry);
rehash = 1;
}
/* /*
* Update i_nlink and free the inode before unlinking. * Update i_nlink and free the inode before unlinking.
*/ */
if (dentry->d_inode->i_nlink) if (dentry->d_inode->i_nlink)
dentry->d_inode->i_nlink --; dentry->d_inode->i_nlink --;
d_delete(dentry);
nfs_invalidate_dircache(dir); nfs_invalidate_dircache(dir);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent), error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name); dentry->d_name.name);
if (!error) {
if (rehash)
d_add(dentry, NULL);
nfs_renew_times(dentry);
}
out: out:
return error; return error;
} }
......
...@@ -199,7 +199,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -199,7 +199,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
goto end_rmdir; goto end_rmdir;
} }
#endif #endif
if (dentry->d_count > 1) { if (!list_empty(&dentry->d_hash)) {
retval = -EBUSY; retval = -EBUSY;
goto end_rmdir; goto end_rmdir;
} }
......
...@@ -479,22 +479,15 @@ smb_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -479,22 +479,15 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
smb_close(inode); smb_close(inode);
/* /*
* Prune any child dentries so this dentry can become negative. * Check that nobody else is using the directory..
*/ */
if (dentry->d_count > 1) { error = -EBUSY;
shrink_dcache_parent(dentry); if (!list_empty(&dentry->d_hash))
error = -EBUSY; goto out;
if (dentry->d_count > 1)
goto out;
}
smb_invalid_dir_cache(dir); smb_invalid_dir_cache(dir);
error = smb_proc_rmdir(dentry); error = smb_proc_rmdir(dentry);
if (!error)
{
smb_renew_times(dentry);
d_delete(dentry);
}
out: out:
return error; return error;
} }
......
...@@ -1008,8 +1008,7 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry) ...@@ -1008,8 +1008,7 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
goto out; goto out;
ret = -EBUSY; ret = -EBUSY;
shrink_dcache_parent(dentry); if (!list_empty(&dentry->d_hash))
if (dentry->d_count > 1)
goto out; goto out;
/* check the sticky bit */ /* check the sticky bit */
...@@ -1065,15 +1064,6 @@ demd->d_parent->d_name.name, demd->d_name.name, err); ...@@ -1065,15 +1064,6 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
else else
d_drop(temp); d_drop(temp);
/* Check again for a busy dentry */
ret = -EBUSY;
shrink_dcache_parent(dentry);
if (dentry->d_count > 1) {
printk("umsdos_rmdir: %s/%s busy\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
goto out_dput;
}
/* /*
* Attempt to remove the msdos name. * Attempt to remove the msdos name.
*/ */
...@@ -1090,11 +1080,8 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret); ...@@ -1090,11 +1080,8 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
/* dput() temp if we didn't do it above */ /* dput() temp if we didn't do it above */
out_dput: out_dput:
if (temp != dentry) { if (temp != dentry)
dput(temp); dput(temp);
if (!ret)
d_delete (dentry);
}
out: out:
Printk (("umsdos_rmdir %d\n", ret)); Printk (("umsdos_rmdir %d\n", ret));
......
...@@ -156,11 +156,8 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) ...@@ -156,11 +156,8 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
goto out; goto out;
ret = -EBUSY; ret = -EBUSY;
if (dentry->d_count > 1) { if (!list_empty(&dentry->d_hash))
shrink_dcache_parent(dentry); goto out;
if (dentry->d_count > 1)
goto out;
}
ret = msdos_rmdir (dir, dentry); ret = msdos_rmdir (dir, dentry);
if (ret != -ENOTEMPTY) if (ret != -ENOTEMPTY)
......
...@@ -1422,6 +1422,8 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh, ...@@ -1422,6 +1422,8 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) { if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) {
return -EBUSY; return -EBUSY;
} }
if (!list_empty(&dentry->d_hash))
return -EBUSY;
res = vfat_empty(dentry->d_inode); res = vfat_empty(dentry->d_inode);
if (res) { if (res) {
...@@ -1508,18 +1510,16 @@ static void drop_replace_inodes(struct dentry *dentry, struct inode *inode) ...@@ -1508,18 +1510,16 @@ static void drop_replace_inodes(struct dentry *dentry, struct inode *inode)
tmp = next; tmp = next;
next = tmp->next; next = tmp->next;
alias = list_entry(tmp, struct dentry, d_alias); alias = list_entry(tmp, struct dentry, d_alias);
if (alias == dentry)
continue;
if (inode) { if (inode) {
list_del(&alias->d_alias); list_del(&alias->d_alias);
iput(alias->d_inode); iput(alias->d_inode);
d_instantiate(alias, inode); d_instantiate(alias, inode);
/* dentry is already accounted for */ inode->i_count++;
if (alias != dentry) {
inode->i_count++;
}
}
if (alias != dentry) {
d_drop(alias);
} }
d_drop(alias);
} }
} }
} }
...@@ -1551,10 +1551,12 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry) ...@@ -1551,10 +1551,12 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry)
{ {
int res; int res;
PRINTK1(("vfat_rmdir: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); PRINTK1(("vfat_rmdir: dentry=%p, inode=%p\n", dentry, dentry->d_inode));
res = vfat_rmdirx(dir, dentry);
if (res >= 0) { res = -EBUSY;
drop_replace_inodes(dentry, NULL); if (list_empty(&dentry->d_hash)) {
d_delete(dentry); res = vfat_rmdirx(dir, dentry);
if (res >= 0)
drop_replace_inodes(dentry, NULL);
} }
return res; return res;
} }
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
* Version * Version
*/ */
#define JS_VERSION 0x01020c #define JS_VERSION 0x01020d
/* /*
* Types and constants for reading from /dev/js * Types and constants for reading from /dev/js
...@@ -179,18 +179,23 @@ typedef struct { int something; } spinlock_t; ...@@ -179,18 +179,23 @@ typedef struct { int something; } spinlock_t;
#ifdef USE_PARPORT #ifdef USE_PARPORT
#include <linux/parport.h> #include <linux/parport.h>
#define JS_PAR_STATUS(y) parport_read_status(y->port)
#define JS_PAR_DATA_IN(y) parport_read_data(y->port) #define JS_PAR_DATA_IN(y) parport_read_data(y->port)
#define JS_PAR_DATA_OUT(x,y) parport_write_data(y->port, x) #define JS_PAR_DATA_OUT(x,y) parport_write_data(y->port, x)
#define JS_PAR_STATUS(y) parport_read_status(y->port)
#define JS_PAR_CTRL_IN(y) parport_read_control(y->port)
#define JS_PAR_CTRL_OUT(x,y) parport_write_control(y->port, x) #define JS_PAR_CTRL_OUT(x,y) parport_write_control(y->port, x)
#define JS_PAR_ECTRL_OUT(x,y) parport_write_econtrol(y->port, x)
#else #else
#define JS_PAR_STATUS(y) inb(y+1)
#define JS_PAR_DATA_IN(y) inb(y) #define JS_PAR_DATA_IN(y) inb(y)
#define JS_PAR_DATA_OUT(x,y) outb(x,y) #define JS_PAR_DATA_OUT(x,y) outb(x,y)
#define JS_PAR_STATUS(y) inb(y+1)
#define JS_PAR_CTRL_IN(y) inb(y+2)
#define JS_PAR_CTRL_OUT(x,y) outb(x,y+2) #define JS_PAR_CTRL_OUT(x,y) outb(x,y+2)
#define JS_PAR_ECTRL_OUT(x,y) outb(x,y+0x402)
#endif #endif
#define JS_PAR_STATUS_INVERT (0x80) #define JS_PAR_STATUS_INVERT (0x80)
#define JS_PAR_CTRL_INVERT (0x04)
/* /*
* Internal types * Internal types
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment