Commit a4e2c5d1 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-input.bkbits.net/linux-input

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 37c55498 831577c2
......@@ -2582,11 +2582,11 @@ S: The Australian National University, ACT 0200
S: Australia
N: Aristeu Sergio Rozanski Filho
E: aris@conectiva.com.br
E: aris@cathedrallabs.org
D: Support for EtherExpress 10 ISA (i82595) in eepro driver
S: Conectiva S.A.
S: R. Tocantins, 89 - Cristo Rei
S: 80050-430 - Curitiba - Paran
D: User level driver support for input
S: R. Jose Serrato, 130 - Santa Candida
S: 82640-320 - Curitiba - Paran
S: Brazil
N: Alessandro Rubini
......
......@@ -419,6 +419,7 @@ Your cooperation is appreciated.
220 = /dev/mptctl Message passing technology (MPT) control
221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver
222 = /dev/mvista/hasi Montavista PICMG high availability
223 = /dev/input/uinput User level driver support for input
240-255 Reserved for local use
11 char Raw keyboard device
......
Amiga 4-joystick parport extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parallel port pins:
(2) - Up1 (6) - Up2
(3) - Down1 (7) - Down2
(4) - Left1 (8) - Left2
(5) - Right1 (9) - Right2
(13) - Fire1 (11) - Fire2
(18) - Gnd1 (18) - Gnd2
Amiga digital joystick pinout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(1) - Up
(2) - Down
(3) - Left
(4) - Right
(5) - n/c
(6) - Fire button
(7) - +5V (50mA)
(8) - Gnd
(9) - Thumb button
Amiga mouse pinout
~~~~~~~~~~~~~~~~~~
(1) - V-pulse
(2) - H-pulse
(3) - VQ-pulse
(4) - HQ-pulse
(5) - Middle button
(6) - Left button
(7) - +5V (50mA)
(8) - Gnd
(9) - Right button
Amiga analog joystick pinout
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(1) - Top button
(2) - Top2 button
(3) - Trigger button
(4) - Thumb button
(5) - Analog X
(6) - n/c
(7) - +5V (50mA)
(8) - Gnd
(9) - Analog Y
Amiga lightpen pinout
~~~~~~~~~~~~~~~~~~~~~
(1) - n/c
(2) - n/c
(3) - n/c
(4) - n/c
(5) - Touch button
(6) - /Beamtrigger
(7) - +5V (50mA)
(8) - Gnd
(9) - Stylus button
-------------------------------------------------------------------------------
NAME rev ADDR type chip Description
JOY0DAT 00A R Denise Joystick-mouse 0 data (left vert, horiz)
JOY1DAT 00C R Denise Joystick-mouse 1 data (right vert,horiz)
These addresses each read a 16 bit register. These in turn
are loaded from the MDAT serial stream and are clocked in on
the rising edge of SCLK. MLD output is used to parallel load
the external parallel-to-serial converter.This in turn is
loaded with the 4 quadrature inputs from each of two game
controller ports (8 total) plus 8 miscellaneous control bits
which are new for LISA and can be read in upper 8 bits of
LISAID.
Register bits are as follows:
Mouse counter usage (pins 1,3 =Yclock, pins 2,4 =Xclock)
BIT# 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
JOY0DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
JOY1DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
0=LEFT CONTROLLER PAIR, 1=RIGHT CONTROLLER PAIR.
(4 counters total).The bit usage for both left and right
addresses is shown below. Each 6 bit counter (Y7-Y2,X7-X2) is
clocked by 2 of the signals input from the mouse serial
stream. Starting with first bit recived:
+-------------------+-----------------------------------------+
| Serial | Bit Name | Description |
+--------+----------+-----------------------------------------+
| 0 | M0H | JOY0DAT Horizontal Clock |
| 1 | M0HQ | JOY0DAT Horizontal Clock (quadrature) |
| 2 | M0V | JOY0DAT Vertical Clock |
| 3 | M0VQ | JOY0DAT Vertical Clock (quadrature) |
| 4 | M1V | JOY1DAT Horizontall Clock |
| 5 | M1VQ | JOY1DAT Horizontall Clock (quadrature) |
| 6 | M1V | JOY1DAT Vertical Clock |
| 7 | M1VQ | JOY1DAT Vertical Clock (quadrature) |
+--------+----------+-----------------------------------------+
Bits 1 and 0 of each counter (Y1-Y0,X1-X0) may be
read to determine the state of the related input signal pair.
This allows these pins to double as joystick switch inputs.
Joystick switch closures can be deciphered as follows:
+------------+------+---------------------------------+
| Directions | Pin# | Counter bits |
+------------+------+---------------------------------+
| Forward | 1 | Y1 xor Y0 (BIT#09 xor BIT#08) |
| Left | 3 | Y1 |
| Back | 2 | X1 xor X0 (BIT#01 xor BIT#00) |
| Right | 4 | X1 |
+------------+------+---------------------------------+
-------------------------------------------------------------------------------
NAME rev ADDR type chip Description
JOYTEST 036 W Denise Write to all 4 joystick-mouse counters at once.
Mouse counter write test data:
BIT# 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
JOYxDAT Y7 Y6 Y5 Y4 Y3 Y2 xx xx X7 X6 X5 X4 X3 X2 xx xx
JOYxDAT Y7 Y6 Y5 Y4 Y3 Y2 xx xx X7 X6 X5 X4 X3 X2 xx xx
-------------------------------------------------------------------------------
NAME rev ADDR type chip Description
POT0DAT h 012 R Paula Pot counter data left pair (vert, horiz)
POT1DAT h 014 R Paula Pot counter data right pair (vert,horiz)
These addresses each read a pair of 8 bit pot counters.
(4 counters total). The bit assignment for both
addresses is shown below. The counters are stopped by signals
from 2 controller connectors (left-right) with 2 pins each.
BIT# 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
RIGHT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
LEFT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
+--------------------------+-------+
| CONNECTORS | PAULA |
+-------+------+-----+-----+-------+
| Loc. | Dir. | Sym | pin | pin |
+-------+------+-----+-----+-------+
| RIGHT | Y | RX | 9 | 33 |
| RIGHT | X | RX | 5 | 32 |
| LEFT | Y | LY | 9 | 36 |
| LEFT | X | LX | 5 | 35 |
+-------+------+-----+-----+-------+
With normal (NTSC or PAL) horiz. line rate, the pots will
give a full scale (FF) reading with about 500kohms in one
frame time. With proportionally faster horiz line times,
the counters will count proportionally faster.
This should be noted when doing variable beam displays.
-------------------------------------------------------------------------------
NAME rev ADDR type chip Description
POTGO 034 W Paula Pot port (4 bit) bi-direction and data, and pot counter start.
-------------------------------------------------------------------------------
NAME rev ADDR type chip Description
POTINP 016 R Paula Pot pin data read
This register controls a 4 bit bi-direction I/O port
that shares the same 4 pins as the 4 pot counters above.
+-------+----------+---------------------------------------------+
| BIT# | FUNCTION | DESCRIPTION |
+-------+----------+---------------------------------------------+
| 15 | OUTRY | Output enable for Paula pin 33 |
| 14 | DATRY | I/O data Paula pin 33 |
| 13 | OUTRX | Output enable for Paula pin 32 |
| 12 | DATRX | I/O data Paula pin 32 |
| 11 | OUTLY | Out put enable for Paula pin 36 |
| 10 | DATLY | I/O data Paula pin 36 |
| 09 | OUTLX | Output enable for Paula pin 35 |
| 08 | DATLX | I/O data Paula pin 35 |
| 07-01 | X | Not used |
| 00 | START | Start pots (dump capacitors,start counters) |
+-------+----------+---------------------------------------------+
-------------------------------------------------------------------------------
Intelligent Keyboard (ikbd) Protocol
1. Introduction
The Atari Corp. Intelligent Keyboard (ikbd) is a general purpose keyboard
controller that is flexible enough that it can be used in a variety of
products without modification. The keyboard, with its microcontroller,
provides a convenient connection point for a mouse and switch-type joysticks.
The ikbd processor also maintains a time-of-day clock with one second
resolution.
The ikbd has been designed to be general enough that it can be used with a
ariety of new computer products. Product variations in a number of
keyswitches, mouse resolution, etc. can be accommodated.
The ikbd communicates with the main processor over a high speed bi-directional
serial interface. It can function in a variety of modes to facilitate
different applications of the keyboard, joysticks, or mouse. Limited use of
the controller is possible in applications in which only a unidirectional
communications medium is available by carefully designing the default modes.
3. Keyboard
The keyboard always returns key make/break scan codes. The ikbd generates
keyboard scan codes for each key press and release. The key scan make (key
closure) codes start at 1, and are defined in Appendix A. For example, the
ISO key position in the scan code table should exist even if no keyswitch
exists in that position on a particular keyboard. The break code for each key
is obtained by ORing 0x80 with the make code.
The special codes 0xF6 through 0xFF are reserved for use as follows:
0xF6 status report
0xF7 absolute mouse position record
0xF8-0xFB relative mouse position records(lsbs determind by
mouse button states)
0xFC time-of-day
0xFD joystick report (both sticks)
0xFE joystick 0 event
0xFF joystick 1 event
The two shift keys return different scan codes in this mode. The ENTER key
and the RETurn key are also distinct.
4. Mouse
The mouse port should be capable of supporting a mouse with resolution of
approximately 200 counts (phase changes or 'clicks') per inch of travel. The
mouse should be scanned at a rate that will permit accurate tracking at
velocities up to 10 inches per second.
The ikbd can report mouse motion in three distinctly different ways. It can
report relative motion, absolute motion in a coordinate system maintained
within the ikbd, or by converting mouse motion into keyboard cursor control
key equivalents.
The mouse buttons can be treated as part of the mouse or as additional
keyboard keys.
4.1 Relative Position Reporting
In relative position mode, the ikbd will return relative mouse position
records whenever a mouse event occurs. A mouse event consists of a mouse
button being pressed or released, or motion in either axis exceeding a
settable threshold of motion. Regardless of the threshold, all bits of
resolution are returned to the host computer.
Note that the ikbd may return mouse relative position reports with
significantly more than the threshold delta x or y. This may happen since no
relative mouse motion events will be generated: (a) while the keyboard has
been 'paused' ( the event will be stored until keyboard communications is
resumed) (b) while any event is being transmitted.
The relative mouse position record is a three byte record of the form
(regardless of keyboard mode):
%111110xy ; mouse position record flag
; where y is the right button state
; and x is the left button state
X ; delta x as twos complement integer
Y ; delta y as twos complement integer
Note that the value of the button state bits should be valid even if the
MOUSE BUTTON ACTION has set the buttons to act like part of the keyboard.
If the accumulated motion before the report packet is generated exceeds the
+127...-128 range, the motion is broken into multiple packets.
Note that the sign of the delta y reported is a function of the Y origin
selected.
4.2 Absolute Position reporting
The ikbd can also maintain absolute mouse position. Commands exist for
reseting the mouse position, setting X/Y scaling, and interrogating the
current mouse position.
4.3 Mouse Cursor Key Mode
The ikbd can translate mouse motion into the equivalent cursor keystrokes.
The number of mouse clicks per keystroke is independently programmable in
each axis. The ikbd internally maintains mouse motion information to the
highest resolution available, and merely generates a pair of cursor key events
for each multiple of the scale factor.
Mouse motion produces the cursor key make code immediately followed by the
break code for the appropriate cursor key. The mouse buttons produce scan
codes above those normally assigned for the largest envisioned keyboard (i.e.
LEFT=0x74 & RIGHT=0x75).
5. Joystick
5.1 Joystick Event Reporting
In this mode, the ikbd generates a record whever the joystick position is
changed (i.e. for each opening or closing of a joystick switch or trigger).
The joystick event record is two bytes of the form:
%1111111x ; Joystick event marker
; where x is Joystick 0 or 1
%x000yyyy ; where yyyy is the stick position
; and x is the trigger
5.2 Joystick Interrogation
The current state of the joystick ports may be interrogated at any time in
this mode by sending an 'Interrogate Joystick' command to the ikbd.
The ikbd response to joystick interrogation is a three byte report of the form
0xFD ; joystick report header
%x000yyyy ; Joystick 0
%x000yyyy ; Joystick 1
; where x is the trigger
; and yyy is the stick position
5.3 Joystick Monitoring
A mode is available that devotes nearly all of the keyboard communications
time to reporting the state of the joystick ports at a user specifiable rate.
It remains in this mode until reset or commanded into another mode. The PAUSE
command in this mode not only stop the output but also temporarily stops
scanning the joysticks (samples are not queued).
5.4 Fire Button Monitoring
A mode is provided to permit monitoring a single input bit at a high rate. In
this mode the ikbd monitors the state of the Joystick 1 fire button at the
maximum rate permitted by the serial communication channel. The data is packed
8 bits per byte for transmission to the host. The ikbd remains in this mode
until reset or commanded into another mode. The PAUSE command in this mode not
only stops the output but also temporarily stops scanning the button (samples
are not queued).
5.5 Joystick Key Code Mode
The ikbd may be commanded to translate the use of either joystick into the
equivalent cursor control keystroke(s). The ikbd provides a single breakpoint
velocity joystick cursor.
Joystick events produce the make code, immediately followed by the break code
for the appropriate cursor motion keys. The trigger or fire buttons of the
joysticks produce pseudo key scan codes above those used by the largest key
matrix envisioned (i.e. JOYSTICK0=0x74, JOYSTICK1=0x75).
6. Time-of-Day Clock
The ikbd also maintains a time-of-day clock for the system. Commands are
available to set and interrogate the timer-of-day clock. Time-keeping is
maintained down to a resolution of one second.
7. Status Inquiries
The current state of ikbd modes and parameters may be found by sending status
inquiry commands that correspond to the ikbd set commands.
8. Power-Up Mode
The keyboard controller will perform a simple self-test on power-up to detect
major controller faults (ROM checksum and RAM test) and such things as stuck
keys. Any keys down at power-up are presumed to be stuck, and their BREAK
(sic) code is returned (which without the preceding MAKE code is a flag for a
keyboard error). If the controller self-test completes without error, the code
0xF0 is returned. (This code will be used to indicate the version/rlease of
the ikbd controller. The first release of the ikbd is version 0xF0, should
there be a second release it will be 0xF1, and so on.)
The ikbd defaults to a mouse position reporting with threshold of 1 unit in
either axis and the Y=0 origin at the top of the screen, and joystick event
reporting mode for joystick 1, with both buttons being logically assigned to
the mouse. After any joystick command, the ikbd assumes that joysticks are
connected to both Joystick0 and Joystick1. Any mouse command (except MOUSE
DISABLE) then causes port 0 to again be scanned as if it were a mouse, and
both buttons are logically connected to it. If a mouse diable command is
received while port 0 is presumed to be a mouse, the button is logically
assigned to Joystick1 ( until the mouse is reenabled by another mouse command).
9. ikbd Command Set
This section contains a list of commands that can be sent to the ikbd. Command
codes (such as 0x00) which are not specified should perform no operation
(NOPs).
9.1 RESET
0x80
0x01
N.B. The RESET command is the only two byte command understood by the ikbd.
Any byte following an 0x80 command byte other than 0x01 is ignored (and causes
the 0x80 to be ignored).
A reset may also be caused by sending a break lasting at least 200mS to the
ikbd.
Executing the RESET command returns the keyboard to its default (power-up)
mode and parameter settings. It does not affect the time-of-day clock.
The RESET command or function causes the ikbd to perform a simple self-test.
If the test is successful, the ikbd will send the code of 0xF0 within 300mS
of receipt of the RESET command (or the end of the break, or power-up). The
ikbd will then scan the key matrix for any stuck (closed) keys. Any keys found
closed will cause the break scan code to be generated (the break code arriving
without being preceded by the make code is a flag for a key matrix error).
9.2. SET MOUSE BUTTON ACTION
0x07
%00000mss ; mouse button action
; (m is presumed = 1 when in MOUSE KEYCODE mode)
; mss=0xy, mouse button press or release causes mouse
; position report
; where y=1, mouse key press causes absolute report
; and x=1, mouse key release causes absolute report
; mss=100, mouse buttons act like keys
This command sets how the ikbd should treat the buttons on the mouse. The
default mouse button action mode is %00000000, the buttons are treated as part
of the mouse logically.
When buttons act like keys, LEFT=0x74 & RIGHT=0x75.
9.3 SET RELATIVE MOUSE POSITION REPORTING
0x08
Set relative mouse position reporting. (DEFAULT) Mouse position packets are
generated asynchronously by the ikbd whenever motion exceeds the setable
threshold in either axis (see SET MOUSE THRESHOLD). Depending upon the mouse
key mode, mouse position reports may also be generated when either mouse
button is pressed or released. Otherwise the mouse buttons behave as if they
were keyboard keys.
9.4 SET ABSOLUTE MOUSE POSITIONING
0x09
XMSB ; X maximum (in scaled mouse clicks)
XLSB
YMSB ; Y maximum (in scaled mouse clicks)
YLSB
Set absolute mouse position maintenance. Resets the ikbd maintained X and Y
coordinates.
In this mode, the value of the internally maintained coordinates does NOT wrap
between 0 and large positive numbers. Excess motion below 0 is ignored. The
command sets the maximum positive value that can be attained in the scaled
coordinate system. Motion beyond that value is also ignored.
9.5 SET MOUSE KEYCODE MOSE
0x0A
deltax ; distance in X clicks to return (LEFT) or (RIGHT)
deltay ; distance in Y clicks to return (UP) or (DOWN)
Set mouse monitoring routines to return cursor motion keycodes instead of
either RELATIVE or ABSOLUTE motion records. The ikbd returns the appropriate
cursor keycode after mouse travel exceeding the user specified deltas in
either axis. When the keyboard is in key scan code mode, mouse motion will
cause the make code immediately followed by the break code. Note that this
command is not affected by the mouse motion origin.
9..6 SET MOUSE THRESHOLD
0x0B
X ; x threshold in mouse ticks (positive integers)
Y ; y threshold in mouse ticks (positive integers)
This command sets the threshold before a mouse event is generated. Note that
it does NOT affect the resolution of the data returned to the host. This
command is valid only in RELATIVE MOUSE POSITIONING mode. The thresholds
default to 1 at RESET (or power-up).
9.7 SET MOUSE SCALE
0x0C
X ; horizontal mouse ticks per internel X
Y ; vertical mouse ticks per internel Y
This command sets the scale factor for the ABSOLUTE MOUSE POSITIONING mode.
In this mode, the specified number of mouse phase changes ('clicks') must
occur before the internally maintained coordinate is changed by one
(independently scaled for each axis). Remember that the mouse position
information is available only by interrogating the ikbd in the ABSOLUTE MOUSE
POSITIONING mode unless the ikbd has been commanded to report on button press
or release (see SET MOSE BUTTON ACTION).
9.8 INTERROGATE MOUSE POSITION
0x0D
Returns:
0xF7 ; absolute mouse position header
BUTTONS
0000dcba ; where a is right button down since last interrogation
; b is right button up since last
; c is left button down since last
; d is left button up since last
XMSB ; X coordinate
XLSB
YMSB ; Y coordinate
YLSB
The INTERROGATE MOUSE POSITION command is valid when in the ABSOLUTE MOUSE
POSITIONING mode, regardless of the setting of the MOUSE BUTTON ACTION.
9.9 LOAD MOUSE POSITION
0x0E
0x00 ; filler
XMSB ; X coordinate
XLSB ; (in scaled coordinate system)
YMSB ; Y coordinate
YLSB
This command allows the user to preset the internally maintained absolute
mouse position.
9.10 SET Y=0 AT BOTTOM
0x0F
This command makes the origin of the Y axis to be at the bottom of the
logical coordinate system internel to the ikbd for all relative or absolute
mouse motion. This causes mouse motion toward the user to be negative in sign
and away from the user to be positive.
9.11 SET Y=0 AT TOP
0x10
Makes the origin of the Y axis to be at the top of the logical coordinate
system within the ikbd for all relative or absolute mouse motion. (DEFAULT)
This causes mouse motion toward the user to be positive in sign and away from
the user to be negative.
9.12 RESUME
0x11
Resume sending data to the host. Since any command received by the ikbd after
its output has been paused also causes an implicit RESUME this command can be
thought of as a NO OPERATION command. If this command is received by the ikbd
and it is not PAUSED, it is simply ignored.
9.13 DISABLE MOUSE
0x12
All mouse event reporting is disabled (and scanning may be internally
disabled). Any valid mouse mode command resumes mouse motion monitoring. (The
valid mouse mode commands are SET RELATIVE MOUSE POSITION REPORTING, SET
ABSOLUTE MOUSE POSITIONING, and SET MOUSE KEYCODE MODE. )
N.B. If the mouse buttons have been commanded to act like keyboard keys, this
command DOES affect their actions.
9.14 PAUSE OUTPUT
0x13
Stop sending data to the host until another valid command is received. Key
matrix activity is still monitored and scan codes or ASCII characters enqueued
(up to the maximum supported by the microcontroller) to be sent when the host
allows the output to be resumed. If in the JOYSTICK EVENT REPORTING mode,
joystick events are also queued.
Mouse motion should be accumulated while the output is paused. If the ikbd is
in RELATIVE MOUSE POSITIONING REPORTING mode, motion is accumulated beyond the
normal threshold limits to produce the minimum number of packets necessary for
transmission when output is resumed. Pressing or releasing either mouse button
causes any accumulated motion to be immediately queued as packets, if the
mouse is in RELATIVE MOUSE POSITION REPORTING mode.
Because of the limitations of the microcontroller memory this command should
be used sparingly, and the output should not be shut of for more than <tbd>
milliseconds at a time.
The output is stopped only at the end of the current 'even'. If the PAUSE
OUTPUT command is received in the middle of a multiple byte report, the packet
will still be transmitted to conclusion and then the PAUSE will take effect.
When the ikbd is in either the JOYSTICK MONITORING mode or the FIRE BUTTON
MONITORING mode, the PAUSE OUTPUT command also temporarily stops the
monitoring process (i.e. the samples are not enqueued for transmission).
0.15 SET JOYSTICK EVENT REPORTING
0x14
Enter JOYSTICK EVENT REPORTING mode (DEFAULT). Each opening or closure of a
joystick switch or trigger causes a joystick event record to be generated.
9.16 SET JOYSTICK INTERROGATION MODE
0x15
Disables JOYSTICK EVENT REPORTING. Host must send individual JOYSTICK
INTERROGATE commands to sense joystick state.
9.17 JOYSTICK INTERROGATE
0x16
Return a record indicating the current state of the joysticks. This command
is valid in either the JOYSTICK EVENT REPORTING mode or the JOYSTICK
INTERROGATION MODE.
9.18 SET JOYSTICK MONITORING
0x17
rate ; time between samples in hundreths of a second
Returns: (in packets of two as long as in mode)
%000000xy ; where y is JOYSTICK1 Fire button
; and x is JOYSTICK0 Fire button
%nnnnmmmm ; where m is JOYSTICK1 state
; and n is JOYSTICK0 state
Sets the ikbd to do nothing but monitor the serial command lne, maintain the
time-of-day clock, and monitor the joystick. The rate sets the interval
between joystick samples.
N.B. The user should not set the rate higher than the serial communications
channel will allow the 2 bytes packets to be transmitted.
9.19 SET FIRE BUTTON MONITORING
0x18
Returns: (as long as in mode)
%bbbbbbbb ; state of the JOYSTICK1 fire button packed
; 8 bits per byte, the first sample if the MSB
Set the ikbd to do nothing but monitor the serial command line, maintain the
time-of-day clock, and monitor the fire button on Joystick 1. The fire button
is scanned at a rate that causes 8 samples to be made in the time it takes for
the previous byte to be sent to the host (i.e. scan rate = 8/10 * baud rate).
The sample interval should be as constant as possible.
9.20 SET JOYSTICK KEYCODE MODE
0x19
RX ; length of time (in tenths of seconds) until
; horizontal velocity breakpoint is reached
RY ; length of time (in tenths of seconds) until
; vertical velocity breakpoint is reached
TX ; length (in tenths of seconds) of joystick closure
; until horizontal cursor key is generated before RX
; has elapsed
TY ; length (in tenths of seconds) of joystick closure
; until vertical cursor key is generated before RY
; has elapsed
VX ; length (in tenths of seconds) of joystick closure
; until horizontal cursor keystokes are generated
; after RX has elapsed
VY ; length (in tenths of seconds) of joystick closure
; until vertical cursor keystokes are generated
; after RY has elapsed
In this mode, joystick 0 is scanned in a way that simulates cursor keystrokes.
On initial closure, a keystroke pair (make/break) is generated. Then up to Rn
tenths of seconds later, keystroke pairs are generated every Tn tenths of
seconds. After the Rn breakpoint is reached, keystroke pairs are generated
every Vn tenths of seconds. This provides a velocity (auto-repeat) breakpoint
feature.
Note that by setting RX and/or Ry to zero, the velocity feature can be
disabled. The values of TX and TY then become meaningless, and the generation
of cursor 'keystrokes' is set by VX and VY.
9.21 DISABLE JOYSTICKS
0x1A
Disable the generation of any joystick events (and scanning may be internally
disabled). Any valid joystick mode command resumes joystick monitoring. (The
joystick mode commands are SET JOYSTICK EVENT REPORTING, SET JOYSTICK
INTERROGATION MODE, SET JOYSTICK MONITORING, SET FIRE BUTTON MONITORING, and
SET JOYSTICK KEYCODE MODE.)
9.22 TIME-OF-DAY CLOCK SET
0x1B
YY ; year (2 least significant digits)
MM ; month
DD ; day
hh ; hour
mm ; minute
ss ; second
All time-of-day data should be sent to the ikbd in packed BCD format.
Any digit that is not a valid BCD digit should be treated as a 'don't care'
and not alter that particular field of the date or time. This permits setting
only some subfields of the time-of-day clock.
9.23 INTERROGATE TIME-OF-DAT CLOCK
0x1C
Returns:
0xFC ; time-of-day event header
YY ; year (2 least significant digits)
MM ; month
DD ; day
hh ; hour
mm ; minute
ss ; second
All time-of-day is sent in packed BCD format.
9.24 MEMORY LOAD
0x20
ADRMSB ; address in controller
ADRLSB ; memory to be loaded
NUM ; number of bytes (0-128)
{ data }
This command permits the host to load arbitrary values into the ikbd
controller memory. The time between data bytes must be less than 20ms.
9.25 MEMORY READ
0x21
ADRMSB ; address in controller
ADRLSB ; memory to be read
Returns:
0xF6 ; status header
0x20 ; memory access
{ data } ; 6 data bytes starting at ADR
This comand permits the host to read from the ikbd controller memory.
9.26 CONTROLLER EXECUTE
0x22
ADRMSB ; address of subroutine in
ADRLSB ; controller memory to be called
This command allows the host to command the execution of a subroutine in the
ikbd controller memory.
9.27 STATUS INQUIRIES
Status commands are formed by inclusively ORing 0x80 with the
relevant SET command.
Example:
0x88 (or 0x89 or 0x8A) ; request mouse mode
Returns:
0xF6 ; status response header
mode ; 0x08 is RELATIVE
; 0x09 is ABSOLUTE
; 0x0A is KEYCODE
param1 ; 0 is RELATIVE
; XMSB maximum if ABSOLUTE
; DELTA X is KEYCODE
param2 ; 0 is RELATIVE
; YMSB maximum if ABSOLUTE
; DELTA Y is KEYCODE
param3 ; 0 if RELATIVE
; or KEYCODE
; YMSB is ABSOLUTE
param4 ; 0 if RELATIVE
; or KEYCODE
; YLSB is ABSOLUTE
0 ; pad
0
The STATUS INQUIRY commands request the ikbd to return either the current mode
or the parameters associated with a given command. All status reports are
padded to form 8 byte long return packets. The responses to the status
requests are designed so that the host may store them away (after stripping
off the status report header byte) and later send them back as commands to
ikbd to restore its state. The 0 pad bytes will be treated as NOPs by the
ikbd.
Valid STATUS INQUIRY commands are:
0x87 mouse button action
0x88 mouse mode
0x89
0x8A
0x8B mnouse threshold
0x8C mouse scale
0x8F mouse vertical coordinates
0x90 ( returns 0x0F Y=0 at bottom
0x10 Y=0 at top )
0x92 mouse enable/disable
( returns 0x00 enabled)
0x12 disabled )
0x94 joystick mode
0x95
0x96
0x9A joystick enable/disable
( returns 0x00 enabled
0x1A disabled )
It is the (host) programmer's responsibility to have only one unanswered
inquiry in process at a time.
STATUS INQUIRY commands are not valid if the ikbd is in JOYSTICK MONITORING
mode or FIRE BUTTON MONITORING mode.
10. SCAN CODES
The key scan codes return by the ikbd are chosen to simplify the
implementaion of GSX.
GSX Standard Keyboard Mapping.
Hex Keytop
01 Esc
02 1
03 2
04 3
05 4
06 5
07 6
08 7
09 8
0A 9
0B 0
0C -
0D ==
0E BS
0F TAB
10 Q
11 W
12 E
13 R
14 T
15 Y
16 U
17 I
18 O
19 P
1A [
1B ]
1C RET
1D CTRL
1E A
1F S
20 D
21 F
22 G
23 H
24 J
25 K
26 L
27 ;
28 '
29 `
2A (LEFT) SHIFT
2B \
2C Z
2D X
2E C
2F V
30 B
31 N
32 M
33 ,
34 .
35 /
36 (RIGHT) SHIFT
37 { NOT USED }
38 ALT
39 SPACE BAR
3A CAPS LOCK
3B F1
3C F2
3D F3
3E F4
3F F5
40 F6
41 F7
42 F8
43 F9
44 F10
45 { NOT USED }
46 { NOT USED }
47 HOME
48 UP ARROW
49 { NOT USED }
4A KEYPAD -
4B LEFT ARROW
4C { NOT USED }
4D RIGHT ARROW
4E KEYPAD +
4F { NOT USED }
50 DOWN ARROW
51 { NOT USED }
52 INSERT
53 DEL
54 { NOT USED }
5F { NOT USED }
60 ISO KEY
61 UNDO
62 HELP
63 KEYPAD (
64 KEYPAD /
65 KEYPAD *
66 KEYPAD *
67 KEYPAD 7
68 KEYPAD 8
69 KEYPAD 9
6A KEYPAD 4
6B KEYPAD 5
6C KEYPAD 6
6D KEYPAD 1
6E KEYPAD 2
6F KEYPAD 3
70 KEYPAD 0
71 KEYPAD .
72 KEYPAD ENTER
I have written a small patch that let's me use my Amiga CD32
joypad connected to the parallel port. Thought I'd share it with you so
you can add it to the list of supported joysticks (hopefully someone will
find it useful).
It needs the following wiring:
CD32 pad | Parallel port
----------------------------
1 (Up) | 2 (D0)
2 (Down) | 3 (D1)
3 (Left) | 4 (D2)
4 (Right) | 5 (D3)
5 (Fire3) | 14 (AUTOFD)
6 (Fire1) | 17 (SELIN)
7 (+5V) | 1 (STROBE)
8 (Gnd) | 18 (Gnd)
9 (Fire2) | 7 (D5)
Force feedback for Linux.
By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
You can redistribute this file, provided you include shape.fig and
interactive.fig.
----------------------------------------------------------------------------
0. Introduction
......@@ -38,13 +39,10 @@ You also need inputattach.
You then need to insert the modules into the following order:
% modprobe joydev
% modprobe serport
% modprobe serport # Only for serial
% modprobe iforce
% modprobe evdev
% ./inputattach -ifor $2 & # Only for serial
For convenience, you may use the shell script named "ff" available from
the cvs tree of the Linux Console Project at sourceforge. You can also
retrieve it from http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/.
If you are using USB, you don't need the inputattach step.
Please check that you have all the /dev/input entries needed:
......@@ -68,7 +66,7 @@ mknod input/event3 c 13 67
2.1 Does it work ?
~~~~~~~~~~~~~~~~~~
There is an utility called fftest that will allow you to test the driver.
% fftest /dev/eventXX
% fftest /dev/input/eventXX
3. Instructions to the developper
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -81,22 +79,28 @@ and write() on /dev/input/eventXX.
#include <linux/input.h>
#include <sys/ioctl.h>
unsigned long features[1 + FF_MAX/sizeof(unsigned long)];
int ioctl(int file_descriptor, int request, unsigned long *features);
"request" must be EVIOCGBIT(EV_FF, sizeof(unsigned long))
"request" must be EVIOCGBIT(EV_FF, size of features array in bytes )
Returns the features supported by the device. features is a bitfield with the
following bits:
- FF_X has an X axis (should allways be the case)
- FF_Y has an Y axis (usually not the case for wheels)
- FF_X has an X axis (usually joysticks)
- FF_Y has an Y axis (usually joysticks)
- FF_WHEEL has a wheel (usually sterring wheels)
- FF_CONSTANT can render constant force effects
- FF_PERIODIC can render periodic effects (sine, ramp, square...)
- FF_SPRING can simulate the presence of a spring
- FF_FRICTION can simulate friction (aka drag, damper effect...)
- FF_FRICTION can simulate friction
- FF_DAMPER can simulate damper effects
- FF_RUMBLE rumble effects (normally the only effect supported by rumble
pads)
- 8 bits from FF_N_EFFECTS_0 containing the number of effects that can be
simultaneously played.
int ioctl(int fd, EVIOCGEFFECTS, int *n);
Returns the number of effects the device can keep in its memory.
3.2 Uploading effects to the device
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -112,7 +116,11 @@ uploaded, but not played.
The content of effect may be modified. In particular, its field "id" is set
to the unique id assigned by the driver. This data is required for performing
some operations (removing an effect, controlling the playback).
See <linux/input.h> for a description of the ff_effect stuct.
This if field must be set to -1 by the user in order to tell the driver to
allocate a new effect.
See <linux/input.h> for a description of the ff_effect stuct. You should also
find help in a few sketches, contained in files shape.fig and interactive.fig.
You need xfig to visualize these files.
3.3 Removing an effect from the device
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -187,8 +195,31 @@ A value of 0 means "no auto-center".
3.7 Dynamic update of an effect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This consists in changing some parameters of an effect while it's playing. The
driver currently does not support that. You still have the brute-force method,
which consists in erasing the effect and uploading the updated version. It
actually works pretty well. You don't need to stop-and-start the effect.
Proceed as if you wanted to upload a new effect, except that instead of
setting the id field to -1, you set it to the wanted effect id.
Normally, the effect is not stopped and restarted. However, depending on the
type of device, not all paramaters can be dynamically updated. For example,
the direction of an effect cannot be updated with iforce devices. In this
case, the driver stops the effect, up-load it, and restart it.
3.8 Information about the status of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Every time the status of an effect is changed, an event is sent. The values
and meanings of the fields of the event are as follows:
struct input_event {
/* When the status of the effect changed */
struct timeval time;
/* Set to EV_FF_STATUS */
unsigned short type;
/* Contains the id of the effect */
unsigned short code;
/* Indicates the status */
unsigned int value;
};
FF_STATUS_STOPPED The effect stopped playing
FF_STATUS_PLAYING The effect started to play
** Introduction
This document describes what I managed to discover about the protocol used to
specify force effects to I-Force 2.0 devices. None of this information comes
from Immerse. That's why you should not trust what is written in this
document. This document is intended to help understanding the protocol.
This is not a reference. Comments and corrections are welcome. To contact me,
send an email to: deneux@ifrance.com
** WARNING **
I may not be held responsible for any dammage or harm caused if you try to
send data to your I-Force device based on what you read in this document.
** Preliminary Notes:
All values are hexadecimal with big-endian encoding (msb on the left). Beware,
values inside packets are encoded using little-endian. Bytes whose roles are
unknown are marked ??? Information that needs deeper inspection is marked (?)
** General form of a packet **
This is how packets look when the device uses the rs232 to communicate.
2B OP LEN DATA CS
CS is the checksum. It is equal to the exclusive or of all bytes.
When using USB:
OP DATA
The 2B, LEN and CS fields have disappeared, probably because USB handles frames and
data corruption is handled or unsignificant.
First, I describe effects that are sent by the device to the computer
** Device input state
This packet is used to indicate the state of each button and the value of each
axis
OP= 01 for a joystick, 03 for a wheel
LEN= Varies from device to device
00 X-Axis lsb
01 X-Axis msb
02 Y-Axis lsb, or gas pedal for a wheel
03 Y-Axis msb, or brake pedal for a wheel
04 Throttle
05 Buttons
06 Lower 4 bits: Buttons
Upper 4 bits: Hat
07 Rudder
** Device effects states
OP= 02
LEN= Varies
00 ? Bit 1 (Value 2) is the value of the deadman switch
01 Bit 8 is set if the effect is playing. Bits 0 to 7 are the effect id.
02 ??
03 Address of parameter block changed (lsb)
04 Address of parameter block changed (msb)
05 Address of second parameter block changed (lsb)
... depending on the number of parameter blocks updated
** Force effect **
OP= 01
LEN= 0e
00 Channel (when playing several effects at the same time, each must be assigned a channel)
01 Wave form
Val 00 Constant
Val 20 Square
Val 21 Triangle
Val 22 Sine
Val 23 Sawtooth up
Val 24 Sawtooth down
Val 40 Spring (Force = f(pos))
Val 41 Friction (Force = f(velocity)) and Inertia (Force = f(acceleration))
02 Axes affected and trigger
Bits 4-7: Val 2 = effect along one axis. Byte 05 indicates direction
Val 4 = X axis only. Byte 05 must contain 5a
Val 8 = Y axis only. Byte 05 must contain b4
Val c = X and Y axes. Bytes 05 must contain 60
Bits 0-3: Val 0 = No trigger
Val x+1 = Button x triggers the effect
When the whole byte is 0, cancel the previously set trigger
03-04 Duration of effect (little endian encoding, in ms)
05 Direction of effect, if applicable. Else, see 02 for value to assign.
06-07 Minimum time between triggering.
08-09 Address of periodicity or magnitude parameters
0a-0b Address of attack and fade parameters, or ffff if none.
*or*
08-09 Address of interactive parameters for X-axis, or ffff if not applicable
0a-0b Address of interactive parameters for Y-axis, or ffff if not applicable
0c-0d Delay before execution of effect (little endian encoding, in ms)
** Time based parameters **
*** Attack and fade ***
OP= 02
LEN= 08
00-01 Address where to store the parameteres
02-03 Duration of attack (little endian encoding, in ms)
04 Level at end of attack. Signed byte.
05-06 Duration of fade.
07 Level at end of fade.
*** Magnitude ***
OP= 03
LEN= 03
00-01 Address
02 Level. Signed byte.
*** Periodicity ***
OP= 04
LEN= 07
00-01 Address
02 Magnitude. Signed byte.
03 Offset. Signed byte.
04 Phase. Val 00 = 0 deg, Val 40 = 90 degs.
05-06 Period (little endian encoding, in ms)
** Interactive parameters **
OP= 05
LEN= 0a
00-01 Address
02 Positive Coeff
03 Negative Coeff
04+05 Offset (center)
06+07 Dead band (Val 01F4 = 5000 (decimal))
08 Positive saturation (Val 0a = 1000 (decimal) Val 64 = 10000 (decimal))
09 Negative saturation
The encoding is a bit funny here: For coeffs, these are signed values. The
maximum value is 64 (100 decimal), the min is 9c.
For the offset, the minimum value is FE0C, the maximum value is 01F4.
For the deadband, the minimum value is 0, the max is 03E8.
** Controls **
OP= 41
LEN= 03
00 Channel
01 Start/Stop
Val 00: Stop
Val 01: Start and play once.
Val 41: Start and play n times (See byte 02 below)
02 Number of iterations n.
** Init **
*** Querying features ***
OP= ff
Query command. Length varies according to the query type.
The general format of this packet is:
ff 01 QUERY [INDEX] CHECKSUM
reponses are of the same form:
FF LEN QUERY VALUE_QUERIED CHECKSUM2
where LEN = 1 + length(VALUE_QUERIED)
**** Query ram size ****
QUERY = 42 ('B'uffer size)
The device should reply with the same packet plus two additionnal bytes
containing the size of the memory:
ff 03 42 03 e8 CS would mean that the device has 1000 bytes of ram available.
**** Query number of effects ****
QUERY = 4e ('N'umber of effects)
The device should respond by sending the number of effects that can be played
at the same time (one byte)
ff 02 4e 14 CS would stand for 20 effects.
**** Vendor's id ****
QUERY = 4d ('M'anufacturer)
Query the vendors'id (2 bytes)
**** Product id *****
QUERY = 50 ('P'roduct)
Query the product id (2 bytes)
**** Open device ****
QUERY = 4f ('O'pen)
No data returned.
**** Close device *****
QUERY = 43 ('C')lose
No data returned.
**** Query effect ****
QUERY = 45 ('E')
Send effect type.
Returns nonzero if supported (2 bytes)
**** Firmware Version ****
QUERY = 56 ('V'ersion)
Sends back 3 bytes - major, minor, subminor
*** Initialisation of the device ***
**** Set Control ****
!!! Device dependent, can be different on different models !!!
OP= 40 <idx> <val> [<val>]
LEN= 2 or 3
00 Idx
Idx 00 Set dead zone (0..2048)
Idx 01 Ignore Deadman sensor (0..1)
Idx 02 Enable comm watchdog (0..1)
Idx 03 Set the strength of the spring (0..100)
Idx 04 Enable or disable the spring (0/1)
Idx 05 Set axis saturation threshold (0..2048)
**** Set Effect State ****
OP= 42 <val>
LEN= 1
00 State
Bit 3 Pause force feedback
Bit 2 Enable force feedback
Bit 0 Stop all effects
**** Set overall gain ****
OP= 43 <val>
LEN= 1
00 Gain
Val 00 = 0%
Val 40 = 50%
Val 80 = 100%
** Parameter memory **
Each device has a certain amount of memory to store parameters of effects.
The amount of RAM may vary, I encountered values from 200 to 1000 bytes. Below
is the amount of memory apparently needed for every set of parameters:
- period : 0c
- magnitude : 02
- attack and fade : 0e
- interactive : 08
** Appendix: How to study the protocol ? **
1. Generate effects using the force editor provided with the DirectX SDK, or use Immersion Studio (freely available at their web site in the developer section: www.immersion.com)
2. Start a soft spying RS232 or USB (depending on where you connected your joystick/wheel). I used ComPortSpy from fCoder (alpha version!)
3. Play the effect, and watch what happens on the spy screen.
A few words about ComPortSpy:
At first glance, this soft seems, hum, well... buggy. In fact, data appear with a few seconds latency. Personnaly, I restart it every time I play an effect.
Remember it's free (as in free beer) and alpha!
** URLS **
Check www.immerse.com for Immersion Studio, and www.fcoder.com for ComPortSpy.
** Author of this document **
Johann Deneux <deneux@ifrance.com>
Home page at http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/
Additions by Vojtech Pavlik.
I-Force is trademark of Immersion Corp.
Linux Input drivers v1.0
(c) 1999-2001 Vojtech Pavlik <vojtech@suse.cz>
(c) 1999-2001 Vojtech Pavlik <vojtech@ucw.cz>
Sponsored by SuSE
$Id: input.txt,v 1.5 2001/06/06 11:05:33 vojtech Exp $
$Id: input.txt,v 1.8 2002/05/29 03:15:01 bradleym Exp $
----------------------------------------------------------------------------
0. Disclaimer
......@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA
Should you need to contact me, the author, you can do so either by e-mail
- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
Simunkova 1594, Prague 8, 182 00 Czech Republic
For your convenience, the GNU General Public License version 2 is included
......@@ -30,11 +30,12 @@ in the package: See the file COPYING.
1. Introduction
~~~~~~~~~~~~~~~
This is a collection of drivers that is designed to support all input
devices under Linux. However, in the current kernels, although it's
possibilities are much bigger, it's limited to USB devices only. This is
also why it resides in the drivers/usb subdirectory.
devices under Linux. While it is currently used only on for USB input
devices, future use (say 2.5/2.6) is expected to expand to replace
most of the existing input system, which is why it lives in
drivers/input/ instead of drivers/usb/.
The center of the input drivers is the input.o module, which must be
The centre of the input drivers is the input.o module, which must be
loaded before any other of the input modules - it serves as a way of
communication between two groups of modules:
......@@ -59,7 +60,7 @@ kernel):
mousedev.o
keybdev.o
usbcore.o
usb-[uo]hci.o
usb-uhci.o or usb-ohci.o or uhci.o
hid.o
After this, the USB keyboard will work straight away, and the USB mouse
......@@ -67,8 +68,8 @@ will be available as a character device on major 13, minor 63:
crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice
This device, has to be created, unless you use devfs, in which case it's
created automatically. The commands to do that are:
This device has to be created, unless you use devfs, in which case it's
created automatically. The commands to do create it by hand are:
cd /dev
mkdir input
......@@ -97,9 +98,9 @@ XFree to this device to use it - GPM should be called like:
however not useful without being handled, so you also will need to use some
of the modules from section 3.2.
3.1.1 hid.c
3.1.1 hid.o
~~~~~~~~~~~
Hid.c is the largest and most complex driver of the whole suite. It
hid.o is the largest and most complex driver of the whole suite. It
handles all HID devices, and because there is a very wide variety of them,
and because the USB HID specification isn't simple, it needs to be this big.
......@@ -120,59 +121,62 @@ detects it appropriately.
However, because the devices vary wildly, you might happen to have a
device that doesn't work well. In that case #define DEBUG at the beginning
of hid.c and send me the syslog traces.
of hid-core.c and send me the syslog traces.
3.1.2 usbmouse.c
3.1.2 usbmouse.o
~~~~~~~~~~~~~~~~
For embedded systems, for mice with broken HID descriptors and just any
other use when the big hid.c wouldn't be a good choice, there is the
other use when the big hid.o wouldn't be a good choice, there is the
usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
protocol. This also means the mice must support this simpler protocol. Not
all do. If you don't have any strong reason to use this module, use hid.c
all do. If you don't have any strong reason to use this module, use hid.o
instead.
3.1.3 usbkbd.c
3.1.3 usbkbd.o
~~~~~~~~~~~~~~
Much like usbmouse.c, this module talks to keyboards with a simpplified
Much like usbmouse.c, this module talks to keyboards with a simplified
HIDBP protocol. It's smaller, but doesn't support any extra special keys.
Use hid.c instead if there isn't any special reason to use this.
Use hid.o instead if there isn't any special reason to use this.
3.1.4 wacom.c
3.1.4 wacom.o
~~~~~~~~~~~~~
This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
PenPartner, that one is handled by the HID driver. Although the Intuos and
Graphire tablets claim that they are HID tablets as well, they are not and
thus need this specific driver.
3.1.5 iforce.c
3.1.5 iforce.o
~~~~~~~~~~~~~~~
A driver for I-Force joysticks and wheels, both over USB and RS232.
It includes ForceFeedback support now, even though Immersion Corp. considers
the protocol a trade secret and won't disclose a word about it.
It includes ForceFeedback support now, even though Immersion
Corp. considers the protocol a trade secret and won't disclose a word
about it.
3.2 Event handlers
~~~~~~~~~~~~~~~~~~
Event handlers distrubite the events from the devices to userland and
kernel, as needed.
3.2.1 keybdev.c
3.2.1 keybdev.o
~~~~~~~~~~~~~~~
Keybdev is currently a rather ugly hack that translates the input events
into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
passes them into the handle_scancode function of the keyboard.c module. This
works well enough on all architectures that keybdev can generate rawmode on,
other architectures can be added to it.
The right way would be to pass the events to keyboard.c directly, best if
keyboard.c would itself be an event handler. This is done in the input
patch, available on the webpage mentioned below.
3.2.2 mousedev.c
keybdev is currently a rather ugly hack that translates the input
events into architecture-specific keyboard raw mode (Xlated AT Set2 on
x86), and passes them into the handle_scancode function of the
keyboard.c module. This works well enough on all architectures that
keybdev can generate rawmode on, other architectures can be added to
it.
The right way would be to pass the events to keyboard.c directly,
best if keyboard.c would itself be an event handler. This is done in
the input patch, available on the webpage mentioned below.
3.2.2 mousedev.o
~~~~~~~~~~~~~~~~
Mousedev is also a hack to make programs that use mouse input work. It
takes events from either mice or digitizers/tablets and makes a PS/2-style
(a la /dev/psaux) mouse device available to the userland. Ideally, the
programs could use a more reasonable interface, for example evdev.c
mousedev is also a hack to make programs that use mouse input
work. It takes events from either mice or digitizers/tablets and makes
a PS/2-style (a la /dev/psaux) mouse device available to the
userland. Ideally, the programs could use a more reasonable interface,
for example evdev.o
Mousedev devices in /dev/input (as shown above) are:
......@@ -185,30 +189,31 @@ programs could use a more reasonable interface, for example evdev.c
crw-r--r-- 1 root root 13, 62 Apr 1 10:50 mouse30
crw-r--r-- 1 root root 13, 63 Apr 1 10:50 mice
Each 'mouse' device is assigned to a single mouse or digitizer, except the last
one - 'mice'. This single character device is shared by all mice and
digitizers, and even if none are connected, the device is present. This is
useful for hotplugging USB mice, so that programs can open the device even when
no mice are present.
Each 'mouse' device is assigned to a single mouse or digitizer, except
the last one - 'mice'. This single character device is shared by all
mice and digitizers, and even if none are connected, the device is
present. This is useful for hotplugging USB mice, so that programs
can open the device even when no mice are present.
CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
of your screen (in pixels) in XFree86. This is needed if you want to use
your digitizer in X, because it's movement is sent to X via a virtual PS/2
mouse and thus needs to be scaled accordingly. These values won't be used if
you use a mouse only.
CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are
the size of your screen (in pixels) in XFree86. This is needed if you
want to use your digitizer in X, because its movement is sent to X
via a virtual PS/2 mouse and thus needs to be scaled
accordingly. These values won't be used if you use a mouse only.
Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or
ExplorerPS/2 (IntelliMouse Explorer) protocols, depending on what the program
reading the data wishes. You can set GPM and X to any of these. You'll need
ImPS/2 if you want to make use of a wheel on a USB mouse and ExplorerPS/2 if you
want to use extra (up to 5) buttons.
ExplorerPS/2 (IntelliMouse Explorer) protocols, depending on what the
program reading the data wishes. You can set GPM and X to any of
these. You'll need ImPS/2 if you want to make use of a wheel on a USB
mouse and ExplorerPS/2 if you want to use extra (up to 5) buttons.
3.2.3 joydev.c
~~~~~~~~~~~~~~
Joydev implements v0.x and v1.x Linux joystick api, much like
drivers/char/joystick/joystick.c used to in earlier versions. See
joystick-api.txt in the Documentation subdirectory for details. As soon as
any joystick is connected, it can be accessed in /dev/input on:
joystick-api.txt in the Documentation subdirectory for details. As
soon as any joystick is connected, it can be accessed in /dev/input
on:
crw-r--r-- 1 root root 13, 0 Apr 1 10:50 js0
crw-r--r-- 1 root root 13, 1 Apr 1 10:50 js1
......@@ -218,16 +223,17 @@ any joystick is connected, it can be accessed in /dev/input on:
And so on up to js31.
3.2.4 evdev.c
3.2.4 evdev.o
~~~~~~~~~~~~~
Evdev is the generic input event interface. It passes the events generated
in the kernel straight to the program, with timestamps. The API is still
evolving, but should be useable now. It's described in section 5.
evdev is the generic input event interface. It passes the events
generated in the kernel straight to the program, with timestamps. The
API is still evolving, but should be useable now. It's described in
section 5.
This should be the way for GPM and X to get keyboard and mouse mouse
events. It allows for multihead in X without any specific multihead kernel
support. The event codes are the same on all architectures and are hardware
independent.
events. It allows for multihead in X without any specific multihead
kernel support. The event codes are the same on all architectures and
are hardware independent.
The devices are in /dev/input:
......@@ -237,40 +243,27 @@ independent.
crw-r--r-- 1 root root 13, 67 Apr 1 10:50 event3
...
3. Contacts
~~~~~~~~~~~
This effort has it's home page at:
http://www.suse.cz/development/input/
You'll find both the latest HID driver and the complete Input driver there
as well as information how to access the CVS repository for latest revisions
of the drivers.
There is also a mailing list for this:
majordomo@atrey.karlin.mff.cuni.cz
Send "subscribe linux-input" to subscribe to it.
And so on up to event31.
4. Verifying if it works
~~~~~~~~~~~~~~~~~~~~~~~~
Typing a couple keys on the keyboard should be enough to check that a USB
keyboard works and is correctly connected to the kernel keyboard driver.
Typing a couple keys on the keyboard should be enough to check that
a USB keyboard works and is correctly connected to the kernel keyboard
driver.
Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
emulated, characters should appear if you move it.
Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse
is also emulated, characters should appear if you move it.
You can test the joystick emulation with the 'jstest' utility, available
in the joystick package (see Documentation/joystick.txt).
You can test the joystick emulation with the 'jstest' utility,
available in the joystick package (see Documentation/joystick.txt).
You can test the event devics with the 'evtest' utitily available on the
input driver homepage (see the URL above).
You can test the event devices with the 'evtest' utility available
in the LinuxConsole project CVS archive (see the URL below).
5. Event interface
~~~~~~~~~~~~~~~~~~
Should you want to add event device support into any application (X, gpm,
svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
svgalib ...) I <vojtech@ucw.cz> will be happy to provide you any help I
can. Here goes a description of the current state of things, which is going
to be extended, but not changed incompatibly as time goes:
......@@ -295,3 +288,25 @@ list is in include/linux/input.h.
'value' is the value the event carries. Either a relative change for
EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
release, 1 for keypress and 2 for autorepeat.
6. Contacts
~~~~~~~~~~~
This effort has its home page at:
http://www.suse.cz/development/input/
You'll find both the latest HID driver and the complete Input driver
there as well as information how to access the CVS repository for
latest revisions of the drivers.
There is also a mailing list for this:
majordomo@atrey.karlin.mff.cuni.cz
Send "subscribe linux-input" to subscribe to it.
The input changes are also being worked on as part of the LinuxConsole
project, see:
http://sourceforge.net/projects/linuxconsole/
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 6
1200 3600 1800 3600 2400 4800 3000 4800 4200 5700 4800 5700
2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
1200 3150 4800 3150 4800 6300 1200 6300 1200 3150
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
1200 4800 4800 4800
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
2400 4800 2400 6525 1950 7125 1950 7800
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
3000 4800 3000 6525 3600 7125 3600 7800
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
0 0 1.00 60.00 120.00
3825 5400 4125 5100 5400 5100
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
0 0 1.00 60.00 120.00
2100 4200 2400 3900 5400 3900
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
4800 5700 5400 5700
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
1800 3600 5400 3600
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3
0 0 1.00 60.00 120.00
2700 4800 2700 4425 5400 4425
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
1950 7800 3600 7800
4 1 0 50 0 0 12 0.0000 4 135 810 2775 7725 Dead band\001
4 0 0 50 0 0 12 0.0000 4 180 1155 5400 5700 right saturation\001
4 0 0 50 0 0 12 0.0000 4 135 1065 5400 3600 left saturation\001
4 0 0 50 0 0 12 0.0000 4 180 2505 5400 3900 left coeff ( positive in that case )\001
4 0 0 50 0 0 12 0.0000 4 180 2640 5475 5100 right coeff ( negative in that case )\001
4 0 0 50 0 0 12 0.0000 4 105 480 5400 4425 center\001
Linux Joystick parport drivers v2.0
(c) 1998-2000 Vojtech Pavlik <vojtech@suse.cz>
(c) 1998-2000 Vojtech Pavlik <vojtech@ucw.cz>
(c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
Sponsored by SuSE
$Id: joystick-parport.txt,v 1.5 2001/05/15 06:41:00 vojtech Exp $
$Id: joystick-parport.txt,v 1.6 2001/09/25 09:31:32 vojtech Exp $
----------------------------------------------------------------------------
0. Disclaimer
......
Linux Joystick driver v2.0.0
(c) 1996-2000 Vojtech Pavlik <vojtech@suse.cz>
(c) 1996-2000 Vojtech Pavlik <vojtech@ucw.cz>
Sponsored by SuSE
$Id: joystick.txt,v 1.6 2001/06/05 09:57:01 vojtech Exp $
$Id: joystick.txt,v 1.12 2002/03/03 12:13:07 jdeneux Exp $
----------------------------------------------------------------------------
0. Disclaimer
......@@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA
Should you need to contact me, the author, you can do so either by e-mail
- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
Ucitelska 1576, Prague 8, 182 00 Czech Republic
- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
Simunkova 1594, Prague 8, 182 00 Czech Republic
For your convenience, the GNU General Public License version 2 is included
in the package: See the file COPYING.
......@@ -111,7 +111,7 @@ your needs:
alias tty-ldisc-2 serport
alias char-major-13 input
above input joydev ns558 analog
options analog js=gameport
options analog js=gamepad
2.5 Verifying that it works
~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -503,15 +503,16 @@ and the /dev/input/jsX device should become usable.
3.21 I-Force devices
~~~~~~~~~~~~~~~~~~~~
All I-Force devices are supported by the iforce.c module. This includes:
All I-Force devices are supported by the iforce.o module. This includes:
* AVB Mag Turbo Force
* AVB Top Shot Pegasus
* AVB Top Shot Force Feedback Racing Wheel
* Logitech WingMan Force
* Logitech WingMan Force 3D
* Logitech WingMan Force Wheel
* Logitech WingMan Strike Force 3D
* Guillemot Race Leader Force Feedback
* Guillemot Force Feedback Racing Wheel
* Thrustmaster Motor Sport GT
To use it, you need to attach the serial port to the driver using the
......@@ -525,6 +526,10 @@ isn't needed.
The I-Force driver now supports force feedback via the event interface.
Please note that Logitech WingMan *3D devices are _not_ supported by this
module, rather by hid. Force feedback is not supported for those devices.
Logitech gamepads are also hid devices.
3.22 Gravis Stinger gamepad
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Gravis Stinger serial port gamepad, designed for use with laptop
......
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 6
4200 3600 4200 3075 4950 2325 7425 2325 8250 3150 8250 3600
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
4200 3675 4200 5400
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
8250 3675 8250 5400
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
3675 3600 8700 3600
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
8775 3600 10200 3600
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
8325 3150 9075 3150
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
7500 2325 10200 2325
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
3600 3600 3000 3600
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
4125 3075 3000 3075
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
4200 5400 8175 5400
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
10125 2325 10125 3600
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
3000 3150 3000 3600
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
9075 3150 9075 3600
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
4950 2325 4950 1200
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2
7425 2325 7425 1200
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
4200 3075 4200 2400 3600 1800 3600 1200
2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4
8250 3150 8250 2475 8775 1950 8775 1200
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
3600 1275 4950 1275
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
0 0 1.00 60.00 120.00
7425 1275 8700 1275
4 1 0 50 0 0 12 0.0000 4 135 1140 6075 5325 Effect duration\001
4 0 0 50 0 0 12 0.0000 4 180 1305 10200 3000 Effect magnitude\001
4 0 0 50 0 0 12 0.0000 4 135 780 9150 3450 Fade level\001
4 1 0 50 0 0 12 0.0000 4 180 1035 4275 1200 Attack length\001
4 1 0 50 0 0 12 0.0000 4 180 885 8175 1200 Fade length\001
4 2 0 50 0 0 12 0.0000 4 135 930 2925 3375 Attack level\001
......@@ -283,11 +283,7 @@ void redwood_irkb_init(void)
{
extern struct machdep_calls ppc_md;
ppc_md.kbd_setkeycode = rawirkbd_setkeycode;
ppc_md.kbd_getkeycode = rawirkbd_getkeycode;
ppc_md.kbd_translate = rawirkbd_translate;
ppc_md.kbd_unexpected_up = rawirkbd_unexpected_up;
ppc_md.kbd_leds = NULL; /*rawirkbd_leds;*/
ppc_md.kbd_init_hw = rawirkbd_init_hw;
}
......@@ -321,19 +321,6 @@ CONFIG_CD_NO_IDESCSI
answer will get "defaulted" for you if you enable any of the Linux
CD-ROM drivers).
CONFIG_INPUT_ADBHID
Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
such as keyboards, mice, joysticks, or graphic tablets handled by
the input layer. If you say Y here, make sure to say Y to the
corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
"Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
support" (CONFIG_INPUT_EVDEV) as well.
If you say N here, you still have the option of using the old ADB
keyboard and mouse drivers.
If unsure, say Y.
CONFIG_PREP_RESIDUAL
Some PReP systems have residual data passed to the kernel by the
firmware. This allows detection of memory size, devices present and
......@@ -382,14 +369,26 @@ CONFIG_ADB_MACIO
also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
OpenPIC controller and two RS422/Geoports.)
CONFIG_ADB_KEYBOARD
This option allows you to use an ADB keyboard attached to your
machine. Note that this disables any other (ie. PS/2) keyboard
support, even if your machine is physically capable of using both at
the same time.
CONFIG_INPUT_ADBHID
Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
such as keyboards, mice, joysticks, trackpads or graphic tablets
handled by the input layer. If you say Y here, make sure to say Y to
the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
"Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
support" (CONFIG_INPUT_EVDEV) as well.
If unsure, say Y.
CONFIG_MAC_EMUMOUSEBTN
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
disabled by default. The emulation is controlled by these sysctl
entries:
/proc/sys/dev/mac_hid/mouse_button_emulation
/proc/sys/dev/mac_hid/mouse_button2_keycode
/proc/sys/dev/mac_hid/mouse_button3_keycode
If you use an ADB keyboard (4 pin connector), say Y here.
If you use a PS/2 keyboard (6 pin connector), say N here.
If you have an Apple machine with a 1-button mouse, say Y here.
CONFIG_SERIAL_CONSOLE
If you say Y here, it will be possible to use a serial port as the
......@@ -886,28 +885,6 @@ CONFIG_EST8260
End of life: -
URL: <http://www.microsys.de/html/cu824.html>
CONFIG_MAC_ADBKEYCODES
This provides support for sending ADB keycodes to console devices in
raw mode, rather than generic "Linux" keycodes. This is the default
up to 2.4.0, but in future this may be phased out in favor of
generic Linux keycodes. If you say Y here, you can dynamically
switch via the /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
sysctl and with the "keyboard_sends_linux_keycodes=" kernel
argument.
If unsure, say Y here.
CONFIG_MAC_EMUMOUSEBTN
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
disabled by default. The emulation is controlled by these sysctl
entries:
/proc/sys/dev/mac_hid/mouse_button_emulation
/proc/sys/dev/mac_hid/mouse_button2_keycode
/proc/sys/dev/mac_hid/mouse_button3_keycode
If you have an Apple machine with a 1-button mouse, say Y here.
CONFIG_PPC_RTC
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
......
......@@ -536,12 +536,9 @@ if [ "$CONFIG_ALL_PPC" = "y" ]; then
bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
if [ "$CONFIG_ADB" = "y" ]; then
bool ' Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO
dep_bool ' Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT
dep_bool ' Support for ADB input devices (keyboard, mice, ...)' CONFIG_INPUT_ADBHID $CONFIG_INPUT
if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
else
bool ' Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD
fi
fi
# This is for drivers/macintosh/mac_hid.o, which is needed if the input
......
......@@ -266,14 +266,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.find_end_of_memory = m8260_find_end_of_memory;
ppc_md.setup_io_mappings = m8260_map_io;
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
ppc_md.kbd_translate = NULL;
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
ppc_md.ppc_kbd_sysrq_xlate = NULL;
}
/* Mainly for ksyms.
......
......@@ -396,14 +396,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.find_end_of_memory = m8xx_find_end_of_memory;
ppc_md.setup_io_mappings = m8xx_map_io;
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
ppc_md.kbd_translate = NULL;
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
ppc_md.ppc_kbd_sysrq_xlate = NULL;
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
m8xx_ide_init();
#endif
......
......@@ -59,15 +59,6 @@
extern void abort(void);
extern void ppc4xx_find_bridges(void);
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern void ppc4xx_wdt_heartbeat(void);
extern int wdt_enable;
extern unsigned long wdt_period;
......@@ -357,13 +348,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#if defined(CONFIG_VT) && defined(CONFIG_PC_KEYBOARD)
#if defined(CONFIG_REDWOOD_4) && defined(CONFIG_STB_KB)
redwood_irkb_init();
#else
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#endif
#endif
......
......@@ -83,7 +83,7 @@ extern void chrp_init(unsigned long r3, unsigned long r4,
#endif /* CONFIG_ALL_PPC */
#ifdef CONFIG_MAGIC_SYSRQ
unsigned long SYSRQ_KEY;
unsigned long SYSRQ_KEY = 0x54;
#endif /* CONFIG_MAGIC_SYSRQ */
#ifdef CONFIG_VGA_CONSOLE
......
......@@ -854,13 +854,6 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
/* These should not be used for the APUS yet, since it uses
the M68K keyboard now. */
ppc_md.kbd_setkeycode = apus_kbd_setkeycode;
ppc_md.kbd_getkeycode = apus_kbd_getkeycode;
ppc_md.kbd_translate = amiga_kbd_translate;
ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
ppc_md.kbd_init_hw = apus_kbd_init_hw;
#ifdef CONFIG_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = amiga_sysrq_xlate;
SYSRQ_KEY = 0xff;
#endif
}
......@@ -69,14 +69,6 @@ void rtas_indicator_progress(char *, unsigned short);
void btext_progress(char *, unsigned short);
extern unsigned long pmac_find_end_of_memory(void);
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[128];
extern void select_adb_keyboard(void);
extern int of_show_percpuinfo(struct seq_file *, int);
......@@ -389,7 +381,7 @@ void __init chrp_init_IRQ(void)
int i;
unsigned long chrp_int_ack;
unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
struct device_node *kbd;
#endif
......@@ -417,7 +409,7 @@ void __init chrp_init_IRQ(void)
irq_desc[i].handler = &i8259_pic;
i8259_init(chrp_int_ack);
#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
......@@ -447,7 +439,7 @@ chrp_init2(void)
if (ppc_md.progress)
ppc_md.progress(" Have fun! ", 0x7777);
#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
#if defined(CONFIG_VT) && defined(CONFIG_INPUT)
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
{
......@@ -461,7 +453,7 @@ chrp_init2(void)
}
}
}
#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
#endif /* CONFIG_VT && CONFIG_INPUT */
}
void __init
......@@ -502,20 +494,6 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.find_end_of_memory = pmac_find_end_of_memory;
#ifdef CONFIG_VT
/* these are adjusted in chrp_init2 if we have an ADB keyboard */
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif /* CONFIG_MAGIC_SYSRQ */
#endif /* CONFIG_VT */
if (rtas_data) {
struct device_node *rtas;
unsigned int *p;
......
......@@ -576,14 +576,6 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.find_end_of_memory = gemini_find_end_of_memory;
ppc_md.setup_io_mappings = gemini_map_io;
/* no keyboard/mouse/video stuff yet.. */
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
ppc_md.kbd_translate = NULL;
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
ppc_md.ppc_kbd_sysrq_xlate = NULL;
ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
#ifdef CONFIG_SMP
......
......@@ -216,12 +216,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.progress = iSeries_progress;
ppc_md.find_end_of_memory = iSeries_find_end_of_memory;
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
ppc_md.kbd_translate = NULL;
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
#ifdef CONFIG_PCI
ppc_md.pcibios_fixup_bus = iSeries_fixup_bus;
ppc_md.pcibios_fixup = iSeries_fixup;
......@@ -230,10 +224,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.pcibios_fixup = NULL;
#endif /* CONFIG_PCI */
#if defined(CONFIG_MAGIC_SYSRQ)
ppc_md.ppc_kbd_sysrq_xlate = NULL;
#endif
#ifdef CONFIG_SMP
ppc_md.smp_ops = &iSeries_smp_ops;
#endif /* CONFIG_SMP */
......
......@@ -117,14 +117,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.set_rtc_time = oak_set_rtc_time;
ppc_md.get_rtc_time = oak_get_rtc_time;
ppc_md.calibrate_decr = oak_calibrate_decr;
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
ppc_md.kbd_translate = NULL;
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
ppc_md.ppc_kbd_sysrq_xlate = NULL;
}
/*
......
......@@ -88,26 +88,6 @@ extern void pmac_find_bridges(void);
extern int pmac_ide_check_base(ide_ioreg_t base);
extern ide_ioreg_t pmac_ide_get_base(int index);
extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int mackbd_getkeycode(unsigned int scancode);
extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
char raw_mode);
extern char mackbd_unexpected_up(unsigned char keycode);
extern void mackbd_leds(unsigned char leds);
extern void __init mackbd_init_hw(void);
extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
extern void mac_hid_init_hw(void);
extern unsigned char mac_hid_kbd_sysrq_xlate[];
extern unsigned char pckbd_sysrq_xlate[];
extern unsigned char mackbd_sysrq_xlate[];
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern int keyboard_sends_linux_keycodes;
extern void pmac_nvram_update(void);
extern unsigned char pmac_nvram_read_byte(int addr);
extern void pmac_nvram_write_byte(int addr, unsigned char val);
......@@ -641,37 +621,8 @@ void __init
select_adb_keyboard(void)
{
#ifdef CONFIG_VT
#ifdef CONFIG_INPUT
ppc_md.kbd_init_hw = mac_hid_init_hw;
ppc_md.kbd_translate = mac_hid_kbd_translate;
ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
ppc_md.kbd_setkeycode = 0;
ppc_md.kbd_getkeycode = 0;
ppc_md.kbd_leds = 0;
#ifdef CONFIG_MAGIC_SYSRQ
#ifdef CONFIG_MAC_ADBKEYCODES
if (!keyboard_sends_linux_keycodes) {
ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
SYSRQ_KEY = 0x69;
} else
#endif /* CONFIG_MAC_ADBKEYCODES */
{
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
}
#endif /* CONFIG_MAGIC_SYSRQ */
#elif defined(CONFIG_ADB_KEYBOARD)
ppc_md.kbd_setkeycode = mackbd_setkeycode;
ppc_md.kbd_getkeycode = mackbd_getkeycode;
ppc_md.kbd_translate = mackbd_translate;
ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
ppc_md.kbd_leds = mackbd_leds;
ppc_md.kbd_init_hw = mackbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate;
SYSRQ_KEY = 0x69;
#endif /* CONFIG_MAGIC_SYSRQ */
#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
#endif /* CONFIG_VT */
}
......
......@@ -77,15 +77,6 @@
TODC_ALLOC();
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[128];
extern void pplus_setup_hose(void);
extern void pplus_set_VIA_IDE_native(void);
......@@ -508,19 +499,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports;
#endif
#ifdef CONFIG_VT
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
#endif
#ifdef CONFIG_SMP
ppc_md.smp_ops = &pplus_smp_ops;
#endif /* CONFIG_SMP */
......
......@@ -79,15 +79,6 @@ extern void rs_nvram_write_val(int addr,
unsigned char val);
extern void ibm_prep_init(void);
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[];
extern void prep_find_bridges(void);
extern char saved_command_line[];
......@@ -895,19 +886,6 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_ide_md.default_io_base = prep_ide_default_io_base;
#endif
#ifdef CONFIG_VT
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
#endif
#ifdef CONFIG_SMP
ppc_md.smp_ops = &prep_smp_ops;
#endif /* CONFIG_SMP */
......
......@@ -97,15 +97,6 @@
extern u_int openpic_irq(void);
extern void openpic_eoi(void);
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[128];
static void sandpoint_halt(void);
......@@ -645,19 +636,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.progress = NULL;
#endif /* CONFIG_SERIAL_TEXT_DEBUG */
#ifdef CONFIG_VT
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
ppc_ide_md.default_irq = sandpoint_ide_default_irq;
ppc_ide_md.default_io_base = sandpoint_ide_default_io_base;
......
......@@ -64,13 +64,6 @@ extern void spruce_init_IRQ(void);
extern int spruce_get_irq(struct pt_regs *);
extern void spruce_setup_hose(void);
extern int pckbd_setkeycode(unsigned int, unsigned int);
extern int pckbd_getkeycode(unsigned int);
extern int pckbd_translate(unsigned char, unsigned char *, char);
extern char pckbd_unexpected_up(unsigned char);
extern void pckbd_leds(unsigned char);
extern void pckbd_init_hw(void);
extern unsigned char pckbd_sysrq_xlate[128];
extern char cmd_line[];
/*
......@@ -279,18 +272,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.nvram_read_val = todc_direct_read_val;
ppc_md.nvram_write_val = todc_direct_write_val;
#ifdef CONFIG_VT
/* Spruce has a PS2 style keyboard */
ppc_md.kbd_setkeycode = pckbd_setkeycode;
ppc_md.kbd_getkeycode = pckbd_getkeycode;
ppc_md.kbd_translate = pckbd_translate;
ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
#endif
}
......@@ -633,37 +633,6 @@ CONFIG_BUSMOUSE
The module will be called busmouse.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_MOUSE
This is for machines with a mouse which is neither a serial nor a
bus mouse. Examples are PS/2 mice (such as the track balls on some
laptops) and some digitizer pads. Most people have a regular serial
MouseSystem or Microsoft mouse (made by Logitech) that plugs into a
COM port (rectangular with 9 or 25 pins). These people say N here.
If you have something else, read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>. This HOWTO contains
information about all non-serial mice, not just bus mice.
If you have a laptop, you either have to check the documentation or
experiment a bit to find out whether the trackball is a serial mouse
or not; it's best to say Y here for you.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about non-serial mice. If unsure, say Y.
CONFIG_LOGIBUSMOUSE
Logitech mouse connected to a proprietary interface card. It's
generally a round connector with 9 pins. Note that the newer mice
made by Logitech don't use the Logitech protocol anymore; for those,
you don't need this option. You want to read the Busmouse-HOWTO,
available from <http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called busmouse.o. If you are unsure, say N and read the
HOWTO nevertheless: it will tell you what you have.
CONFIG_PSMOUSE
The PS/2 mouse connects to a special mouse port that looks much like
the keyboard port (small circular connector with 6 pins). This way,
......@@ -683,64 +652,6 @@ CONFIG_PSMOUSE
<ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
CONFIG_82C710_MOUSE
This is a certain kind of PS/2 mouse used on the TI Travelmate. If
you are unsure, try first to say N here and come back if the mouse
doesn't work. Read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
CONFIG_PC110_PAD
This drives the digitizer pad on the IBM PC110 palmtop. It can turn
the digitizer pad into a PS/2 mouse emulation with tap gestures or
into an absolute pad.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called pc110pad.o.
CONFIG_MS_BUSMOUSE
These animals (also called Inport mice) are connected to an
expansion board using a round connector with 9 pins. If this is what
you have, say Y and read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
If you are unsure, say N and read the HOWTO nevertheless: it will
tell you what you have. Also be aware that several vendors talk
about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
count the pins on the connector.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called msbusmouse.o.
CONFIG_ADBMOUSE
Say Y here if you have this type of bus mouse (4 pin connector) as
is common on Macintoshes. You may want to read the Busmouse-HOWTO,
available from <http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called adbmouse.o.
CONFIG_ATIXL_BUSMOUSE
This is a rare type of busmouse that is connected to the back of an
ATI video card. Say Y if you have one of those. Note however that
most mice by ATI are actually Microsoft busmice; you should say Y to
"Microsoft busmouse support" above if you have one of those. Read
the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called atixlmouse.o.
If you are unsure, say N and read the HOWTO nevertheless: it will
tell you what you have.
CONFIG_QIC02_TAPE
If you have a non-SCSI tape drive like that, say Y. Or, if you want
to compile this driver as a module ( = code which can be inserted in
......
......@@ -113,22 +113,8 @@ source drivers/i2c/Config.in
mainmenu_option next_comment
comment 'Mice'
tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
if [ "$CONFIG_BUSMOUSE" != "n" ]; then
dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then
dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
fi
fi
tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
if [ "$CONFIG_MOUSE" != "n" ]; then
bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD
fi
tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
endmenu
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
......
......@@ -155,8 +155,6 @@ obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_BUSMOUSE) += busmouse.o
......@@ -164,12 +162,7 @@ obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
obj-$(CONFIG_SONYPI) += sonypi.o
obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
obj-$(CONFIG_ADBMOUSE) += adbmouse.o
obj-$(CONFIG_PC110_PAD) += pc110pad.o
obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
......@@ -235,4 +228,4 @@ $(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
sed -e 's/^static *//' $@.tmp > $@
rm $@.tmp
endif
\ No newline at end of file
endif
/*
* Macintosh ADB Mouse driver for Linux
*
* 27 Oct 1997 Michael Schmitz
* logitech fixes by anthony tong
* further hacking by Paul Mackerras
*
* Apple mouse protocol according to:
*
* Device code shamelessly stolen from:
*/
/*
* Atari Mouse Driver for Linux
* by Robert de Vries (robert@and.nl) 19Jul93
*
* 16 Nov 1994 Andreas Schwab
* Compatibility with busmouse
* Support for three button mouse (shamelessly stolen from MiNT)
* third button wired to one of the joystick directions on joystick 1
*
* 1996/02/11 Andreas Schwab
* Module support
* Allow multiple open's
*
* Converted to use new generic busmouse code. 11 July 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/adb_mouse.h>
#ifdef __powerpc__
#include <asm/processor.h>
#endif
#if defined(__mc68000__) || defined(MODULE)
#include <asm/setup.h>
#endif
#include "busmouse.h"
static int msedev;
static unsigned char adb_mouse_buttons[16];
extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
extern int adb_emulate_buttons;
extern int adb_button2_keycode;
extern int adb_button3_keycode;
/*
* XXX: need to figure out what ADB mouse packets mean ...
* This is the stuff stolen from the Atari driver ...
*/
static void adb_mouse_interrupt(unsigned char *buf, int nb)
{
int buttons, id;
char dx, dy;
/*
Handler 1 -- 100cpi original Apple mouse protocol.
Handler 2 -- 200cpi original Apple mouse protocol.
For Apple's standard one-button mouse protocol the data array will
contain the following values:
BITS COMMENTS
data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
data[1] = bxxx xxxx First button and x-axis motion.
data[2] = byyy yyyy Second button and y-axis motion.
Handler 4 -- Apple Extended mouse protocol.
For Apple's 3-button mouse protocol the data array will contain the
following values:
BITS COMMENTS
data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
data[1] = bxxx xxxx Left button and x-axis motion.
data[2] = byyy yyyy Second button and y-axis motion.
data[3] = byyy bxxx Third button and fourth button.
Y is additiona. high bits of y-axis motion.
X is additional high bits of x-axis motion.
'buttons' here means 'button down' states!
Button 1 (left) : bit 2, busmouse button 3
Button 2 (right) : bit 0, busmouse button 1
Button 3 (middle): bit 1, busmouse button 2
*/
/* x/y and buttons swapped */
id = (buf[0] >> 4) & 0xf;
buttons = adb_mouse_buttons[id];
/* button 1 (left, bit 2) */
buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
/* button 2 (middle) */
buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
/* button 3 (right) present?
* on a logitech mouseman, the right and mid buttons sometimes behave
* strangely until they both have been pressed after booting. */
/* data valid only if extended mouse format ! */
if (nb >= 4)
buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
adb_mouse_buttons[id] = buttons;
/* a button is down if it is down on any mouse */
for (id = 0; id < 16; ++id)
buttons &= adb_mouse_buttons[id];
dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
if (console_loglevel >= 8)
printk(" %X %X %X dx %d dy %d \n",
buf[1], buf[2], buf[3], dx, dy);
}
static int release_mouse(struct inode *inode, struct file *file)
{
adb_mouse_interrupt_hook = NULL;
/*
* FIXME?: adb_mouse_interrupt_hook may still be executing
* on another CPU.
*/
return 0;
}
static int open_mouse(struct inode *inode, struct file *file)
{
adb_mouse_interrupt_hook = adb_mouse_interrupt;
return 0;
}
static struct busmouse adb_mouse =
{
ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init adb_mouse_init(void)
{
#ifdef __powerpc__
if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
return -ENODEV;
#endif
#ifdef __mc68000__
if (!MACH_IS_MAC)
return -ENODEV;
#endif
/* all buttons up */
memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons));
msedev = register_busmouse(&adb_mouse);
if (msedev < 0)
printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
else
printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
return msedev < 0 ? msedev : 0;
}
#ifndef MODULE
/*
* XXX this function is misnamed.
* It is called if the kernel is booted with the adb_buttons=xxx
* option, which is about using ADB keyboard buttons to emulate
* mouse buttons. -- paulus
*/
static int __init adb_mouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] >= 1) {
adb_emulate_buttons = ints[1];
if (ints[0] >= 2)
adb_button2_keycode = ints[2];
if (ints[0] >= 3)
adb_button3_keycode = ints[3];
}
return 1;
}
__setup("adb_buttons=", adb_mouse_setup);
#endif /* !MODULE */
static void __exit adb_mouse_cleanup(void)
{
unregister_busmouse(msedev);
}
module_init(adb_mouse_init);
module_exit(adb_mouse_cleanup);
MODULE_LICENSE("GPL");
/*
* Amiga Mouse Driver for Linux 68k by Michael Rausch
* based upon:
*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Mods by Matthew Dillon
* calls verify_area()
* tracks better when X is busy or paging
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_poll
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching poll code.
*
* Modified the poll() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* Modified by Johan Myreen to make room for other mice (9AUG92)
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
* renamed this file mouse.c => busmouse.c
*
* Modified for use in the 1.3 kernels by Jes Sorensen.
*
* Moved the isr-allocation to the mouse_{open,close} calls, as there
* is no reason to service the mouse in the vertical blank isr if
* the mouse is not in use. Jes Sorensen
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/logibusmouse.h>
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#include "busmouse.h"
#if AMIGA_OLD_INT
#define AMI_MSE_INT_ON() mouseint_allowed = 1
#define AMI_MSE_INT_OFF() mouseint_allowed = 0
static int mouseint_allowed;
#endif
static int msedev;
static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
static int lastx=0, lasty=0;
int dx, dy;
int nx, ny;
unsigned char buttons;
unsigned short joy0dat, potgor;
#if AMIGA_OLD_INT
if(!mouseint_allowed)
return;
AMI_MSE_INT_OFF();
#endif
/*
* This routine assumes, just like Kickstart, that the mouse
* has not moved more than 127 ticks since last VBL.
*/
joy0dat = custom.joy0dat;
nx = joy0dat & 0xff;
ny = joy0dat >> 8;
dx = nx - lastx;
if (dx < - 127)
dx = (256 + nx) - lastx;
if (dx > 127)
dx = (nx - 256) - lastx;
dy = ny - lasty;
if (dy < - 127)
dy = (256 + ny) - lasty;
if (dy > 127)
dy = (ny - 256) - lasty;
lastx = nx;
lasty = ny;
#if 0
dx = -lastdx;
dx += (lastdx = joy0dat & 0xff);
if (dx < -127)
dx = -255-dx; /* underrun */
else
if (dx > 127)
dx = 255-dx; /* overflow */
dy = -lastdy;
dy += (lastdy = joy0dat >> 8);
if (dy < -127)
dy = -255-dy;
else
if (dy > 127)
dy = 255-dy;
#endif
potgor = custom.potgor;
buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */
#if 1
(potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */
#endif
(potgor & 0x0400 ? 1 : 0); /* right button */
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
}
/*
* close access to the mouse
*/
static int release_mouse(struct inode * inode, struct file * file)
{
free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
#endif
return 0;
}
/*
* open access to the mouse, currently only one open is
* allowed.
*/
static int open_mouse(struct inode * inode, struct file * file)
{
/*
* use VBL to poll mouse deltas
*/
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
printk(KERN_INFO "Installing Amiga mouse failed.\n");
return -EIO;
}
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
return 0;
}
static struct busmouse amigamouse = {
AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init amiga_mouse_init(void)
{
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
return -ENODEV;
if (!request_mem_region(CUSTOM_PHYSADDR+10, 2, "amigamouse [Denise]"))
return -EBUSY;
custom.joytest = 0; /* reset counters */
#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
#endif
msedev = register_busmouse(&amigamouse);
if (msedev < 0)
printk(KERN_WARNING "Unable to install Amiga mouse driver.\n");
else
printk(KERN_INFO "Amiga mouse installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit amiga_mouse_exit(void)
{
unregister_busmouse(msedev);
release_mem_region(CUSTOM_PHYSADDR+10, 2);
}
module_init(amiga_mouse_init);
module_exit(amiga_mouse_exit);
MODULE_LICENSE("GPL");
/*
* ATI XL Bus Mouse Driver for Linux
* by Bob Harris (rth@sparta.com)
*
* Uses VFS interface for linux 0.98 (01OCT92)
*
* Modified by Chris Colohan (colohan@eecg.toronto.edu)
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*
* version 0.3a
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
/* ATI XL Inport Busmouse Definitions */
#define ATIXL_MSE_DATA_PORT 0x23d
#define ATIXL_MSE_SIGNATURE_PORT 0x23e
#define ATIXL_MSE_CONTROL_PORT 0x23c
#define ATIXL_MSE_READ_BUTTONS 0x00
#define ATIXL_MSE_READ_X 0x01
#define ATIXL_MSE_READ_Y 0x02
/* Some nice ATI XL macros */
/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */
#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7, Enable updates (INT ENABLED) */
#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7 - Mode Register, NO INTERRUPTS */
#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */
#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Same general mouse structure */
static int msedev;
static void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
char dx, dy, buttons;
ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */
outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */
dx = inb( ATIXL_MSE_DATA_PORT);
outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */
dy = inb( ATIXL_MSE_DATA_PORT);
outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
buttons = inb( ATIXL_MSE_DATA_PORT);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
ATIXL_MSE_ENABLE_UPDATE();
}
static int release_mouse(struct inode * inode, struct file * file)
{
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
free_irq(ATIXL_MOUSE_IRQ, NULL);
return 0;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
return -EBUSY;
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
return 0;
}
static struct busmouse atixlmouse = {
ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init atixl_busmouse_init(void)
{
unsigned char a,b,c;
/*
* We must request the resource and claim it atomically
* nowdays. We can throw it away on error. Otherwise we
* may race another module load of the same I/O
*/
if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
return -EIO;
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
b = inb( ATIXL_MSE_SIGNATURE_PORT );
c = inb( ATIXL_MSE_SIGNATURE_PORT );
if (( a != b ) && ( a == c ))
printk(KERN_INFO "\nATI Inport ");
else
{
release_region(ATIXL_MSE_DATA_PORT,3);
return -EIO;
}
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
msedev = register_busmouse(&atixlmouse);
if (msedev < 0)
{
printk("Bus mouse initialisation error.\n");
release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */
}
else
printk("Bus mouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit atixl_cleanup (void)
{
release_region(ATIXL_MSE_DATA_PORT, 3);
unregister_busmouse(msedev);
}
module_init(atixl_busmouse_init);
module_exit(atixl_cleanup);
MODULE_LICENSE("GPL");
/*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Mods by Matthew Dillon
* calls verify_area()
* tracks better when X is busy or paging
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_select
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching select code.
*
* Modified the select() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* Modified by Johan Myreen to make room for other mice (9AUG92)
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
* renamed this file mouse.c => busmouse.c
*
* Minor addition by Cliff Matthews
* added fasync support
*
* Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Replaced dumb busy loop with udelay() 16 Nov 95
* Nathan Laredo <laredo@gnu.ai.mit.edu>
*
* Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/logibusmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
static int msedev;
static int mouse_irq = MOUSE_IRQ;
MODULE_PARM(mouse_irq, "i");
#ifndef MODULE
static int __init bmouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0)
mouse_irq=ints[1];
return 1;
}
__setup("logi_busmouse=", bmouse_setup);
#endif /* !MODULE */
static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
char dx, dy;
unsigned char buttons;
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
dx = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
dy = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
buttons = inb(MSE_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ((buttons >> 5) & 0x07);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
MSE_INT_ON();
}
/*
* close access to the mouse
*/
static int close_mouse(struct inode * inode, struct file * file)
{
MSE_INT_OFF();
free_irq(mouse_irq, NULL);
return 0;
}
/*
* open access to the mouse
*/
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
return -EBUSY;
MSE_INT_ON();
return 0;
}
static struct busmouse busmouse = {
LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7
};
static int __init logi_busmouse_init(void)
{
if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse"))
return -EIO;
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
udelay(100L); /* wait for reply from mouse */
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
return -EIO;
}
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
msedev = register_busmouse(&busmouse);
if (msedev < 0) {
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
printk(KERN_WARNING "Unable to register busmouse driver.\n");
}
else
printk(KERN_INFO "Logitech busmouse installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit logi_busmouse_cleanup (void)
{
unregister_busmouse(msedev);
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
}
module_init(logi_busmouse_init);
module_exit(logi_busmouse_cleanup);
MODULE_LICENSE("GPL");
/*
* Microsoft busmouse driver based on Logitech driver (see busmouse.c)
*
* Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
*
* Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
* 8/28/92
*
* Microsoft Bus Mouse support folded into 0.97pl4 code
* by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
* Changes: Logitech and Microsoft support in the same kernel.
* Defined new constants in busmouse.h for MS mice.
* Added int mse_busmouse_type to distinguish busmouse types
* Added a couple of new functions to handle differences in using
* MS vs. Logitech (where the int variable wasn't appropriate).
*
* Modified by Peter Cervasio (address above) (26SEP92)
* Changes: Included code to (properly?) detect when a Microsoft mouse is
* really attached to the machine. Don't know what this does to
* Logitech bus mice, but all it does is read ports.
*
* Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
* Changes: Better interrupt-handler (like in busmouse.c).
* Some changes to reduce code-size.
* Changed detection code to use inb_p() instead of doing empty
* loops to delay i/o.
*
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*
* version 0.3b
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/logibusmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
static int msedev;
static int mouse_irq = MOUSE_IRQ;
MODULE_PARM(mouse_irq, "i");
#ifndef MODULE
static int __init msmouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0)
mouse_irq=ints[1];
return 1;
}
__setup("msmouse=",msmouse_setup);
#endif /* !MODULE */
static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
char dx, dy;
unsigned char buttons;
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT);
outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT);
dx = inb(MS_MSE_DATA_PORT);
outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT);
dy = inb(MS_MSE_DATA_PORT);
outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT);
buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07;
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
/* why did the original have:
* if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
* ((~buttons) & 0x07))
* ^^^^^^^^^^^^^^^^^^^ this?
*/
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
}
static int release_mouse(struct inode * inode, struct file * file)
{
MS_MSE_INT_OFF();
free_irq(mouse_irq, NULL);
return 0;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
return -EBUSY;
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
MS_MSE_INT_ON();
return 0;
}
static struct busmouse msbusmouse = {
MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init ms_bus_mouse_init(void)
{
int present = 0;
int mse_byte, i;
if (check_region(MS_MSE_CONTROL_PORT, 0x04))
return -ENODEV;
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
for (i = 0; i < 4; i++) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
present = 1;
else
present = 0;
} else
present = 0;
}
}
if (present == 0)
return -EIO;
if (!request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse"))
return -EIO;
MS_MSE_INT_OFF();
msedev = register_busmouse(&msbusmouse);
if (msedev < 0) {
printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
release_region(MS_MSE_CONTROL_PORT, 0x04);
}
else
printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit ms_bus_mouse_exit(void)
{
unregister_busmouse(msedev);
release_region(MS_MSE_CONTROL_PORT, 0x04);
}
module_init(ms_bus_mouse_init)
module_exit(ms_bus_mouse_exit)
MODULE_LICENSE("GPL");
/*
* Linux driver for the PC110 pad
*/
/**
* DOC: PC110 Digitizer Hardware
*
* The pad provides triples of data. The first byte has
* 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
* The second byte is bits 0-6 X
* The third is bits 0-6 Y
*
* This is read internally and used to synthesize a stream of
* triples in the form expected from a PS/2 device. Specialist
* applications can choose to obtain the pad data in other formats
* including a debugging mode.
*
* It would be good to add a joystick driver mode to this pad so
* that doom and other game playing are better. One possible approach
* would be to deactive the mouse mode while the joystick port is opened.
*/
/*
* History
*
* 0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
* 0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
* 0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
* 0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
* 0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
* 0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/ptrace.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/semaphore.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include "pc110pad.h"
static struct pc110pad_params default_params = {
mode: PC110PAD_PS2,
bounce_interval: 50 MS,
tap_interval: 200 MS,
irq: 10,
io: 0x15E0,
};
static struct pc110pad_params current_params;
/* driver/filesystem interface management */
static wait_queue_head_t queue;
static struct fasync_struct *asyncptr;
static int active_count = 0; /* number of concurrent open()s */
static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED;
/* this lock should be held when referencing active_count */
static struct semaphore reader_lock;
/**
* wake_readers:
*
* Take care of letting any waiting processes know that
* now would be a good time to do a read(). Called
* whenever a state transition occurs, real or synthetic. Also
* issue any SIGIO's to programs that use SIGIO on mice (eg
* Executor)
*/
static void wake_readers(void)
{
wake_up_interruptible(&queue);
kill_fasync(&asyncptr, SIGIO, POLL_IN);
}
/*****************************************************************************/
/*
* Deal with the messy business of synthesizing button tap and drag
* events.
*
* Exports:
* notify_pad_up_down()
* Must be called whenever debounced pad up/down state changes.
* button_pending
* Flag is set whenever read_button() has new values
* to return.
* read_button()
* Obtains the current synthetic mouse button state.
*/
/*
* These keep track of up/down transitions needed to generate the
* synthetic mouse button events. While recent_transition is set,
* up/down events cause transition_count to increment. tap_timer
* turns off the recent_transition flag and may cause some synthetic
* up/down mouse events to be created by incrementing synthesize_tap.
*/
static int button_pending;
static int recent_transition;
static int transition_count;
static int synthesize_tap;
static void tap_timeout(unsigned long data);
static struct timer_list tap_timer = { function: tap_timeout };
/**
* tap_timeout:
* @data: Unused
*
* This callback goes off a short time after an up/down transition;
* before it goes off, transitions will be considered part of a
* single PS/2 event and counted in transition_count. Once the
* timeout occurs the recent_transition flag is cleared and
* any synthetic mouse up/down events are generated.
*/
static void tap_timeout(unsigned long data)
{
if(!recent_transition)
{
printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n");
}
if( transition_count==2 || transition_count==4 || transition_count==6 )
{
synthesize_tap+=transition_count;
button_pending = 1;
wake_readers();
}
recent_transition=0;
}
/**
* notify_pad_up_down:
*
* Called by the raw pad read routines when a (debounced) up/down
* transition is detected.
*/
void notify_pad_up_down(void)
{
if(recent_transition)
{
transition_count++;
}
else
{
transition_count=1;
recent_transition=1;
}
mod_timer(&tap_timer, jiffies + current_params.tap_interval);
/* changes to transition_count can cause reported button to change */
button_pending = 1;
wake_readers();
}
/**
* read_button:
* @b: pointer to the button status.
*
* The actual button state depends on what we are seeing. We have to check
* for the tap gesture and also for dragging.
*/
static void read_button(int *b)
{
if(synthesize_tap)
{
*b=--synthesize_tap & 1;
}
else
{
*b=(!recent_transition && transition_count==3); /* drag */
}
button_pending=(synthesize_tap>0);
}
/*****************************************************************************/
/*
* Read pad absolute co-ordinates and debounced up/down state.
*
* Exports:
* pad_irq()
* Function to be called whenever the pad signals
* that it has new data available.
* read_raw_pad()
* Returns the most current pad state.
* xy_pending
* Flag is set whenever read_raw_pad() has new values
* to return.
* Imports:
* wake_readers()
* Called when movement occurs.
* notify_pad_up_down()
* Called when debounced up/down status changes.
*/
/*
* These are up/down state and absolute co-ords read directly from pad
*/
static int raw_data[3];
static int raw_data_count;
static int raw_x, raw_y; /* most recent absolute co-ords read */
static int raw_down; /* raw up/down state */
static int debounced_down; /* up/down state after debounce processing */
static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
/* set just after an up/down transition */
static int xy_pending; /* set if new data have not yet been read */
/*
* Timer goes off a short while after an up/down transition and copies
* the value of raw_down to debounced_down.
*/
static void bounce_timeout(unsigned long data);
static struct timer_list bounce_timer = { function: bounce_timeout };
/**
* bounce_timeout:
* @data: Unused
*
* No further up/down transitions happened within the
* bounce period, so treat this as a genuine transition.
*/
static void bounce_timeout(unsigned long data)
{
switch(bounce)
{
case NO_BOUNCE:
{
/*
* Strange; the timer callback should only go off if
* we were expecting to do bounce processing!
*/
printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n");
break;
}
case JUST_GONE_UP:
{
/*
* The last up we spotted really was an up, so set
* debounced state the same as raw state.
*/
bounce=NO_BOUNCE;
if(debounced_down==raw_down)
{
printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n");
}
debounced_down=raw_down;
notify_pad_up_down();
break;
}
case JUST_GONE_DOWN:
{
/*
* We don't debounce down events, but we still time
* out soon after one occurs so we can avoid the (x,y)
* skittering that sometimes happens.
*/
bounce=NO_BOUNCE;
break;
}
}
}
/**
* pad_irq:
* @irq: Interrupt number
* @ptr: Unused
* @regs: Unused
*
* Callback when pad's irq goes off; copies values in to raw_* globals;
* initiates debounce processing. This isn't SMP safe however there are
* no SMP machines with a PC110 touchpad on them.
*/
static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
{
/* Obtain byte from pad and prime for next byte */
{
int value=inb_p(current_params.io);
int handshake=inb_p(current_params.io+2);
outb_p(handshake | 1, current_params.io+2);
outb_p(handshake &~1, current_params.io+2);
inb_p(0x64);
raw_data[raw_data_count++]=value;
}
if(raw_data_count==3)
{
int new_down=raw_data[0]&0x01;
int new_x=raw_data[1];
int new_y=raw_data[2];
if(raw_data[0]&0x10) new_x+=128;
if(raw_data[0]&0x80) new_x+=256;
if(raw_data[0]&0x08) new_y+=128;
if( (raw_x!=new_x) || (raw_y!=new_y) )
{
raw_x=new_x;
raw_y=new_y;
xy_pending=1;
}
if(new_down != raw_down)
{
/* Down state has changed. raw_down always holds
* the most recently observed state.
*/
raw_down=new_down;
/* Forget any earlier bounce processing */
if(bounce)
{
del_timer(&bounce_timer);
bounce=NO_BOUNCE;
}
if(new_down)
{
if(debounced_down)
{
/* pad gone down, but we were reporting
* it down anyway because we suspected
* (correctly) that the last up was just
* a bounce
*/
}
else
{
bounce=JUST_GONE_DOWN;
mod_timer(&bounce_timer,
jiffies+current_params.bounce_interval);
/* start new stroke/tap */
debounced_down=new_down;
notify_pad_up_down();
}
}
else /* just gone up */
{
if(recent_transition)
{
/* early bounces are probably part of
* a multi-tap gesture, so process
* immediately
*/
debounced_down=new_down;
notify_pad_up_down();
}
else
{
/* don't trust it yet */
bounce=JUST_GONE_UP;
mod_timer(&bounce_timer,
jiffies+current_params.bounce_interval);
}
}
}
wake_readers();
raw_data_count=0;
}
}
/**
* read_raw_pad:
* @down: set if the pen is down
* @debounced: set if the debounced pen position is down
* @x: X position
* @y: Y position
*
* Retrieve the data saved by the interrupt handler and indicate we
* have no more pending XY to do.
*
* FIXME: We should switch to a spinlock for this.
*/
static void read_raw_pad(int *down, int *debounced, int *x, int *y)
{
disable_irq(current_params.irq);
{
*down=raw_down;
*debounced=debounced_down;
*x=raw_x;
*y=raw_y;
xy_pending = 0;
}
enable_irq(current_params.irq);
}
/*****************************************************************************/
/*
* Filesystem interface
*/
/*
* Read returns byte triples, so we need to keep track of
* how much of a triple has been read. This is shared across
* all processes which have this device open---not that anything
* will make much sense in that case.
*/
static int read_bytes[3];
static int read_byte_count;
/**
* sample_raw:
* @d: sample buffer
*
* Retrieve a triple of sample data.
*/
static void sample_raw(int d[3])
{
d[0]=raw_data[0];
d[1]=raw_data[1];
d[2]=raw_data[2];
}
/**
* sample_rare:
* @d: sample buffer
*
* Retrieve a triple of sample data and sanitize it. We do the needed
* scaling and masking to get the current status.
*/
static void sample_rare(int d[3])
{
int thisd, thisdd, thisx, thisy;
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
d[0]=(thisd?0x80:0)
| (thisx/256)<<4
| (thisdd?0x08:0)
| (thisy/256)
;
d[1]=thisx%256;
d[2]=thisy%256;
}
/**
* sample_debug:
* @d: sample buffer
*
* Retrieve a triple of sample data and mix it up with the state
* information in the gesture parser. Not useful for normal users but
* handy when debugging
*/
static void sample_debug(int d[3])
{
int thisd, thisdd, thisx, thisy;
int b;
unsigned long flags;
spin_lock_irqsave(&pc110_lock, flags);
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
d[1]=(recent_transition?0x80:0)+transition_count;
read_button(&b);
d[2]=(synthesize_tap<<4) | (b?0x01:0);
spin_unlock_irqrestore(&pc110_lock, flags);
}
/**
* sample_ps2:
* @d: sample buffer
*
* Retrieve a triple of sample data and turn the debounced tap and
* stroke information into what appears to be a PS/2 mouse. This means
* the PC110 pad needs no funny application side support.
*/
static void sample_ps2(int d[3])
{
static int lastx, lasty, lastd;
int thisd, thisdd, thisx, thisy;
int dx, dy, b;
/*
* Obtain the current mouse parameters and limit as appropriate for
* the return data format. Interrupts are only disabled while
* obtaining the parameters, NOT during the puts_fs_byte() calls,
* so paging in put_user() does not affect mouse tracking.
*/
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
read_button(&b);
/* Now compare with previous readings. Note that we use the
* raw down flag rather than the debounced one.
*/
if( (thisd && !lastd) /* new stroke */
|| (bounce!=NO_BOUNCE) )
{
dx=0;
dy=0;
}
else
{
dx = (thisx-lastx);
dy = -(thisy-lasty);
}
lastx=thisx;
lasty=thisy;
lastd=thisd;
/*
d[0]= ((dy<0)?0x20:0)
| ((dx<0)?0x10:0)
| 0x08
| (b? 0x01:0x00)
;
*/
d[0]= ((dy<0)?0x20:0)
| ((dx<0)?0x10:0)
| (b? 0x00:0x08)
;
d[1]=dx;
d[2]=dy;
}
/**
* fasync_pad:
* @fd: file number for the file
* @filp: file handle
* @on: 1 to add, 0 to remove a notifier
*
* Update the queue of asynchronous event notifiers. We can use the
* same helper the mice do and that does almost everything we need.
*/
static int fasync_pad(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &asyncptr);
if (retval < 0)
return retval;
return 0;
}
/**
* close_pad:
* @inode: inode of pad
* @file: file handle to pad
*
* Close access to the pad. We turn the pad power off if this is the
* last user of the pad. I've not actually measured the power draw but
* the DOS driver is careful to do this so we follow suit.
*/
static int close_pad(struct inode * inode, struct file * file)
{
unsigned long flags;
fasync_pad(-1, file, 0);
spin_lock_irqsave(&pc110_lock, flags);
if (!--active_count)
outb(0x30, current_params.io+2); /* switch off digitiser */
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
/**
* open_pad:
* @inode: inode of pad
* @file: file handle to pad
*
* Open access to the pad. We turn the pad off first (we turned it off
* on close but if this is the first open after a crash the state is
* indeterminate). The device has a small fifo so we empty that before
* we kick it back into action.
*/
static int open_pad(struct inode * inode, struct file * file)
{
unsigned long flags;
spin_lock_irqsave(&pc110_lock, flags);
if (active_count++)
{
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
outb(0x30, current_params.io+2); /* switch off digitiser */
pad_irq(0,0,0); /* read to flush any pending bytes */
pad_irq(0,0,0); /* read to flush any pending bytes */
pad_irq(0,0,0); /* read to flush any pending bytes */
outb(0x38, current_params.io+2); /* switch on digitiser */
current_params = default_params;
raw_data_count=0; /* re-sync input byte counter */
read_byte_count=0; /* re-sync output byte counter */
button_pending=0;
recent_transition=0;
transition_count=0;
synthesize_tap=0;
del_timer(&bounce_timer);
del_timer(&tap_timer);
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
/**
* write_pad:
* @file: File handle to the pad
* @buffer: Unused
* @count: Unused
* @ppos: Unused
*
* Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
* seems happy with this and not faking the write modes.
*/
static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
/*
* new_sample:
* @d: sample buffer
*
* Fetch a new sample according the current mouse mode the pad is
* using.
*/
void new_sample(int d[3])
{
switch(current_params.mode)
{
case PC110PAD_RAW: sample_raw(d); break;
case PC110PAD_RARE: sample_rare(d); break;
case PC110PAD_DEBUG: sample_debug(d); break;
case PC110PAD_PS2: sample_ps2(d); break;
}
}
/**
* read_pad:
* @file: File handle to pad
* @buffer: Target for the mouse data
* @count: Buffer length
* @ppos: Offset (unused)
*
* Read data from the pad. We use the reader_lock to avoid mess when there are
* two readers. This shouldnt be happening anyway but we play safe.
*/
static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
int r;
down(&reader_lock);
for(r=0; r<count; r++)
{
if(!read_byte_count)
new_sample(read_bytes);
if(put_user(read_bytes[read_byte_count], buffer+r))
{
r = -EFAULT;
break;
}
read_byte_count = (read_byte_count+1)%3;
}
up(&reader_lock);
return r;
}
/**
* pad_poll:
* @file: File of the pad device
* @wait: Poll table
*
* The pad is ready to read if there is a button or any position change
* pending in the queue. The reading and interrupt routines maintain the
* required state for us and do needed wakeups.
*/
static unsigned int pad_poll(struct file *file, poll_table * wait)
{
poll_wait(file, &queue, wait);
if(button_pending || xy_pending)
return POLLIN | POLLRDNORM;
return 0;
}
/**
* pad_ioctl;
* @inode: Inode of the pad
* @file: File handle to the pad
* @cmd: Ioctl command
* @arg: Argument pointer
*
* The PC110 pad supports two ioctls both of which use the pc110pad_params
* structure. GETP queries the current pad status. SETP changes the pad
* configuration. Changing configuration during normal mouse operations
* may give momentarily odd results as things like tap gesture state
* may be lost.
*/
static int pad_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct pc110pad_params new;
if (!inode)
return -EINVAL;
switch (cmd) {
case PC110PADIOCGETP:
new = current_params;
if(copy_to_user((void *)arg, &new, sizeof(new)))
return -EFAULT;
return 0;
case PC110PADIOCSETP:
if(copy_from_user(&new, (void *)arg, sizeof(new)))
return -EFAULT;
if( (new.mode<PC110PAD_RAW)
|| (new.mode>PC110PAD_PS2)
|| (new.bounce_interval<0)
|| (new.tap_interval<0)
)
return -EINVAL;
current_params.mode = new.mode;
current_params.bounce_interval = new.bounce_interval;
current_params.tap_interval = new.tap_interval;
return 0;
}
return -ENOTTY;
}
static struct file_operations pad_fops = {
owner: THIS_MODULE,
read: read_pad,
write: write_pad,
poll: pad_poll,
ioctl: pad_ioctl,
open: open_pad,
release: close_pad,
fasync: fasync_pad,
};
static struct miscdevice pc110_pad = {
minor: PC110PAD_MINOR,
name: "pc110 pad",
fops: &pad_fops,
};
/**
* pc110pad_init_driver:
*
* We configure the pad with the default parameters (that is PS/2
* emulation mode. We then claim the needed I/O and interrupt resources.
* Finally as a matter of paranoia we turn the pad off until we are
* asked to open it by an application.
*/
static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n";
static int __init pc110pad_init_driver(void)
{
init_MUTEX(&reader_lock);
current_params = default_params;
if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
printk(KERN_ERR "pc110pad: Unable to get IRQ.\n");
return -EBUSY;
}
if (!request_region(current_params.io, 4, "pc110pad")) {
printk(KERN_ERR "pc110pad: I/O area in use.\n");
free_irq(current_params.irq,0);
return -EBUSY;
}
init_waitqueue_head(&queue);
printk(banner, current_params.io, current_params.irq);
misc_register(&pc110_pad);
outb(0x30, current_params.io+2); /* switch off digitiser */
return 0;
}
/*
* pc110pad_exit_driver:
*
* Free the resources we acquired when the module was loaded. We also
* turn the pad off to be sure we don't leave it using power.
*/
static void __exit pc110pad_exit_driver(void)
{
outb(0x30, current_params.io+2); /* switch off digitiser */
if (current_params.irq)
free_irq(current_params.irq, 0);
current_params.irq = 0;
release_region(current_params.io, 4);
misc_deregister(&pc110_pad);
}
module_init(pc110pad_init_driver);
module_exit(pc110pad_exit_driver);
MODULE_AUTHOR("Alan Cox, Robin O'Leary");
MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
MODULE_LICENSE("GPL");
#ifndef _PC110PAD_H
#define _PC110PAD_H
#include <linux/ioctl.h>
enum pc110pad_mode {
PC110PAD_RAW, /* bytes as they come out of the hardware */
PC110PAD_RARE, /* debounced up/down and absolute x,y */
PC110PAD_DEBUG, /* up/down, debounced, transitions, button */
PC110PAD_PS2, /* ps2 relative (default) */
};
struct pc110pad_params {
enum pc110pad_mode mode;
int bounce_interval;
int tap_interval;
int irq;
int io;
};
#define MS *HZ/1000
/* Appears as device major=10 (MISC), minor=PC110_PAD */
#define PC110PAD_IOCTL_TYPE 0x9a
#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
#endif /* _PC110PAD_H */
......@@ -912,6 +912,8 @@ static char * __init initialize_kbd(void)
void __init pckbd_init_hw(void)
{
#ifndef CONFIG_SERIO_I8042
kbd_request_region();
/* Flush any pending input. */
......@@ -935,6 +937,7 @@ void __init pckbd_init_hw(void)
/* Ok, finally allocate the IRQ, and off we go.. */
kbd_request_irq(keyboard_interrupt);
#endif
}
#if defined CONFIG_PSMOUSE
......@@ -1213,6 +1216,7 @@ static struct miscdevice psaux_mouse = {
static int __init psaux_init(void)
{
#ifndef CONFIG_SERIO_I8042
int retval;
if (!detect_auxiliary_port())
......@@ -1241,6 +1245,7 @@ static int __init psaux_init(void)
#endif /* INITIALIZE_MOUSE */
kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
#endif
return 0;
}
......
/*
* linux/drivers/char/qpmouse.c
*
* Driver for a 82C710 C&T mouse interface chip.
*
* Based on the PS/2 driver by Johan Myreen.
*
* Corrections in device setup for some laptop mice & trackballs.
* 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
*
* Modified by Johan Myreen (jem@iki.fi) 04Aug93
* to include support for QuickPort mouse.
*
* Changed references to "QuickPort" with "82C710" since "QuickPort"
* is not what this driver is all about -- QuickPort is just a
* connector type, and this driver is for the mouse port on the Chips
* & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi
*
* Added support for SIGIO. 28Jul95 jem@iki.fi
*
* Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
*
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/semaphore.h>
#include <linux/pc_keyb.h> /* mouse enable command.. */
/*
* We use the same minor number as the PS/2 mouse for (bad) historical
* reasons..
*/
#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */
#define QP_BUF_SIZE 2048
struct qp_queue {
unsigned long head;
unsigned long tail;
wait_queue_head_t proc_list;
struct fasync_struct *fasync;
unsigned char buf[QP_BUF_SIZE];
};
static struct qp_queue *queue;
static unsigned int get_from_queue(void)
{
unsigned int result;
unsigned long flags;
save_flags(flags);
cli();
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1);
restore_flags(flags);
return result;
}
static inline int queue_empty(void)
{
return queue->head == queue->tail;
}
static int fasync_qp(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &queue->fasync);
if (retval < 0)
return retval;
return 0;
}
/*
* 82C710 Interface
*/
#define QP_DATA 0x310 /* Data Port I/O Address */
#define QP_STATUS 0x311 /* Status Port I/O Address */
#define QP_DEV_IDLE 0x01 /* Device Idle */
#define QP_RX_FULL 0x02 /* Device Char received */
#define QP_TX_IDLE 0x04 /* Device XMIT Idle */
#define QP_RESET 0x08 /* Device Reset */
#define QP_INTS_ON 0x10 /* Device Interrupt On */
#define QP_ERROR_FLAG 0x20 /* Device Error */
#define QP_CLEAR 0x40 /* Device Clear */
#define QP_ENABLE 0x80 /* Device Enable */
#define QP_IRQ 12
static int qp_present;
static int qp_count;
static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED;
static int qp_data = QP_DATA;
static int qp_status = QP_STATUS;
static int poll_qp_status(void);
static int probe_qp(void);
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
int head = queue->head;
int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1);
add_mouse_randomness(queue->buf[head] = inb(qp_data));
if (head != maxhead) {
head++;
head &= QP_BUF_SIZE-1;
}
queue->head = head;
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
static int release_qp(struct inode * inode, struct file * file)
{
unsigned char status;
fasync_qp(-1, file, 0);
spin_lock( &qp_count_lock );
if (!--qp_count) {
if (!poll_qp_status())
printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
status = inb_p(qp_status);
outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
if (!poll_qp_status())
printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
free_irq(QP_IRQ, NULL);
}
spin_unlock( &qp_count_lock );
return 0;
}
/*
* Install interrupt handler.
* Enable the device, enable interrupts.
*/
static int open_qp(struct inode * inode, struct file * file)
{
unsigned char status;
if (!qp_present)
return -EINVAL;
spin_lock( &qp_count_lock );
if (qp_count++)
{
spin_unlock( &qp_count_lock );
return 0;
}
spin_unlock( &qp_count_lock );
if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
qp_count--;
return -EBUSY;
}
status = inb_p(qp_status);
status |= (QP_ENABLE|QP_RESET);
outb_p(status, qp_status);
status &= ~(QP_RESET);
outb_p(status, qp_status);
queue->head = queue->tail = 0; /* Flush input queue */
status |= QP_INTS_ON;
outb_p(status, qp_status); /* Enable interrupts */
while (!poll_qp_status()) {
printk(KERN_ERR "Error: Mouse device busy in open_qp()\n");
qp_count--;
status &= ~(QP_ENABLE|QP_INTS_ON);
outb_p(status, qp_status);
free_irq(QP_IRQ, NULL);
return -EBUSY;
}
outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
return 0;
}
/*
* Write to the 82C710 mouse device.
*/
static ssize_t write_qp(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
ssize_t i = count;
while (i--) {
char c;
if (!poll_qp_status())
return -EIO;
get_user(c, buffer++);
outb_p(c, qp_data);
}
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
return count;
}
static unsigned int poll_qp(struct file *file, poll_table * wait)
{
poll_wait(file, &queue->proc_list, wait);
if (!queue_empty())
return POLLIN | POLLRDNORM;
return 0;
}
/*
* Wait for device to send output char and flush any input char.
*/
#define MAX_RETRIES (60)
static int poll_qp_status(void)
{
int retries=0;
while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
!= (QP_DEV_IDLE|QP_TX_IDLE)
&& retries < MAX_RETRIES) {
if (inb_p(qp_status)&(QP_RX_FULL))
inb_p(qp_data);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((5*HZ + 99) / 100);
retries++;
}
return !(retries==MAX_RETRIES);
}
/*
* Put bytes from input queue to buffer.
*/
static ssize_t read_qp(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
DECLARE_WAITQUEUE(wait, current);
ssize_t i = count;
unsigned char c;
if (queue_empty()) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
add_wait_queue(&queue->proc_list, &wait);
repeat:
set_current_state(TASK_INTERRUPTIBLE);
if (queue_empty() && !signal_pending(current)) {
schedule();
goto repeat;
}
current->state = TASK_RUNNING;
remove_wait_queue(&queue->proc_list, &wait);
}
while (i > 0 && !queue_empty()) {
c = get_from_queue();
put_user(c, buffer++);
i--;
}
if (count-i) {
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
return count-i;
}
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
}
struct file_operations qp_fops = {
owner: THIS_MODULE,
read: read_qp,
write: write_qp,
poll: poll_qp,
open: open_qp,
release: release_qp,
fasync: fasync_qp,
};
/*
* Initialize driver.
*/
static struct miscdevice qp_mouse = {
minor: PSMOUSE_MINOR,
name: "QPmouse",
fops: &qp_fops,
};
/*
* Function to read register in 82C710.
*/
static inline unsigned char read_710(unsigned char index)
{
outb_p(index, 0x390); /* Write index */
return inb_p(0x391); /* Read the data */
}
/*
* See if we can find a 82C710 device. Read mouse address.
*/
static int __init probe_qp(void)
{
outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
outb_p(0xaa, 0x3fa); /* Inverse of 55 */
outb_p(0x36, 0x3fa); /* Address the chip */
outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
outb_p(0x1b, 0x2fa); /* Inverse of e4 */
if (read_710(0x0f) != 0xe4) /* Config address found? */
return 0; /* No: no 82C710 here */
qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
qp_status = qp_data+1;
outb_p(0x0f, 0x390);
outb_p(0x0f, 0x391); /* Close config mode */
return 1;
}
static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n";
static char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n";
static int __init qpmouse_init_driver(void)
{
if (!probe_qp())
return -EIO;
printk(msg_banner);
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
if (queue == NULL) {
printk(msg_nomem);
return -ENOMEM;
}
qp_present = 1;
misc_register(&qp_mouse);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
init_waitqueue_head(&queue->proc_list);
return 0;
}
static void __exit qpmouse_exit_driver(void)
{
misc_deregister(&qp_mouse);
kfree(queue);
}
module_init(qpmouse_init_driver);
module_exit(qpmouse_exit_driver);
MODULE_LICENSE("GPL");
......@@ -98,3 +98,12 @@ CONFIG_INPUT_EVBUG
inserted in and removed from the running kernel whenever you want).
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_UINPUT
Say Y here if you want to support user level drivers for input
subsystem accessible under char device 10:223 - /dev/input/uinput.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called uinput.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
......@@ -23,6 +23,7 @@ if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then
fi
dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
dep_tristate ' Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
dep_tristate ' User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_EXPERIMENTAL
comment 'Input I/O drivers'
source drivers/input/gameport/Config.in
......
......@@ -16,6 +16,7 @@ obj-$(CONFIG_INPUT_EVDEV) += evdev.o
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
obj-$(CONFIG_INPUT_POWER) += power.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_INPUT_MOUSE) += mouse/
......
......@@ -37,6 +37,8 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL");
static char evbug_name[] = "evbug";
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
......@@ -52,6 +54,7 @@ static struct input_handle *evbug_connect(struct input_handler *handler, struct
handle->dev = dev;
handle->handler = handler;
handle->name = evbug_name;
input_open_device(handle);
......
......@@ -34,7 +34,7 @@ CONFIG_GAMEPORT_L4
The module will be called lightning.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_EMU10K1
CONFIG_GAMEPORT_EMU10K1
Say Y here if you have a SoundBlaster Live! or SoundBlaster
Audigy card and want to use its gameport.
......@@ -52,7 +52,7 @@ CONFIG_GAMEPORT_VORTEX
The module will be called vortex.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_GAMEPORT_CS461x
CONFIG_GAMEPORT_CS461X
Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
PCI audio accelerator and want to use its gameport.
......
......@@ -13,7 +13,7 @@ fi
dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
dep_tristate ' SB Live and Audigy gameport support' CONFIG_GAMEPORT_EMU10K1 $CONFIG_GAMEPORT
dep_tristate ' Aureal Vortex, Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT
dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
......@@ -103,24 +103,6 @@ CONFIG_JOYSTICK_TMDC
The module will be called tmdc.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_IFORCE_USB
Say Y here if you have an I-Force joystick or steering wheel
connected to your USB port.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called iforce.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_IFORCE_232
Say Y here if you have an I-Force joystick or steering wheel
connected to your serial (COM) port.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called iforce.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_WARRIOR
Say Y here if you have a Logitech WingMan Warrior joystick connected
to your computer's serial port.
......
......@@ -14,9 +14,7 @@ dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CON
dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_USB
dep_tristate ' I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
source drivers/input/joystick/iforce/Config.in
dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_JOYSTICK_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
......
......@@ -2,24 +2,6 @@
# Makefile for the input core drivers.
#
# I-Force may need both USB and RS-232
CONFIG_JOYSTICK_IFORCE := n
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
CONFIG_JOYSTICK_IFORCE := y
endif
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
CONFIG_JOYSTICK_IFORCE := m
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
CONFIG_JOYSTICK_IFORCE := m
endif
# Each configuration option enables a list of files.
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
......
CONFIG_JOYSTICK_IFORCE
Say Y here if you have an I-Force joystick or steering wheel
You also must choose at least one of the two options below.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called iforce.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_JOYSTICK_IFORCE_USB
Say Y here if you have an I-Force joystick or steering wheel
connected to your USB port.
CONFIG_JOYSTICK_IFORCE_232
Say Y here if you have an I-Force joystick or steering wheel
connected to your serial (COM) port.
You will need an additional utility called inputattach, see
Documentation/input/joystick.txt and ff.txt.
#
# I-Force driver configuration
#
dep_tristate ' I-Force devices' CONFIG_JOYSTICK_IFORCE $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_JOYSTICK_IFORCE" = "y" ]; then
if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_USB" = "y" ]; then
dep_mbool ' I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_USB
fi
if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_SERIO" = "y" ]; then
dep_mbool ' I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_SERIO
fi
fi
#
# Makefile for the I-Force driver
#
# By Johann Deneux <deneux@ifrance.com>
#
# I-Force may need both USB and RS-232
# Goal definition
list-multi := iforce.o
iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o
CONFIG_JOYSTICK_IFORCE := n
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
CONFIG_JOYSTICK_IFORCE := y
endif
iforce-objs += iforce-serio.o
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
CONFIG_JOYSTICK_IFORCE := m
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
iforce-objs += iforce-usb.o
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
CONFIG_JOYSTICK_IFORCE := m
endif
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
EXTRA_CFLAGS = -Werror-implicit-function-declaration
# The global Rules.make.
include $(TOPDIR)/Rules.make
# iforce.o is a multipart module.
IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o
ifneq ($(CONFIG_JOYSTICK_IFORCE_232),)
IFORCEOBJS += iforce-serio.o
endif
ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),)
IFORCEOBJS += iforce-usb.o
endif
# Additional rules
iforce.o: $(iforce-objs)
$(LD) -r -o $@ $(iforce-objs)
iforce.o: $(IFORCEOBJS)
$(LD) -i $(IFORCEOBJS) -o $@
/*
* $Id: iforce-main.c,v 1.18 2002/06/09 11:03:03 jdeneux Exp $
* $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
......@@ -248,7 +248,7 @@ static int iforce_open(struct input_dev *dev)
struct iforce *iforce = dev->private;
switch (iforce->bus) {
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
iforce->irq->dev = iforce->usbdev;
if (usb_submit_urb(iforce->irq, GFP_KERNEL))
......@@ -305,7 +305,7 @@ static void iforce_release(struct input_dev *dev)
iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
switch (iforce->bus) {
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
usb_unlink_urb(iforce->irq);
......@@ -323,12 +323,12 @@ static void iforce_release(struct input_dev *dev)
void iforce_delete_device(struct iforce *iforce)
{
switch (iforce->bus) {
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
iforce_usb_delete(iforce);
break;
#endif
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
case IFORCE_232:
//TODO: Wait for the last packets to be sent
break;
......@@ -520,10 +520,10 @@ int iforce_init_device(struct iforce *iforce)
static int __init iforce_init(void)
{
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
usb_register(&iforce_usb_driver);
#endif
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
serio_register_device(&iforce_serio_dev);
#endif
return 0;
......@@ -531,10 +531,10 @@ static int __init iforce_init(void)
static void __exit iforce_exit(void)
{
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
usb_deregister(&iforce_usb_driver);
#endif
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
serio_unregister_device(&iforce_serio_dev);
#endif
}
......
/*
* $Id: iforce-packets.c,v 1.15 2002/06/09 11:08:04 jdeneux Exp $
* $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
......@@ -101,13 +101,13 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
*/
switch (iforce->bus) {
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
case IFORCE_232:
if (empty)
iforce_serial_xmit(iforce);
break;
#endif
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
if (iforce->usbdev && empty &&
......@@ -161,7 +161,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
being_used++;
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
if (HI(iforce->expect_packet) == HI(cmd)) {
iforce->expect_packet = 0;
iforce->ecmd = cmd;
......@@ -251,7 +251,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
case IFORCE_USB:
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
iforce->cr.bRequest = packet[0];
iforce->ctrl->dev = iforce->usbdev;
......@@ -281,7 +281,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
case IFORCE_232:
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
iforce->expect_packet = FF_CMD_QUERY;
iforce_send_packet(iforce, FF_CMD_QUERY, packet);
......
/*
* $Id: iforce.h,v 1.12 2002/06/09 11:08:04 jdeneux Exp $
* $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
......@@ -39,7 +39,7 @@
#include <linux/circ_buf.h>
#include <asm/semaphore.h>
/* FF: This module provides arbitrary resource management routines.
/* This module provides arbitrary resource management routines.
* I use it to manage the device's memory.
* Despite the name of this module, I am *not* going to access the ioports.
*/
......@@ -47,12 +47,9 @@
#define IFORCE_MAX_LENGTH 16
#if defined(CONFIG_JOYSTICK_IFORCE_232)
/* iforce::bus */
#define IFORCE_232 1
#endif
#if defined(CONFIG_JOYSTICK_IFORCE_USB)
#define IFORCE_USB 2
#endif
#define FALSE 0
#define TRUE 1
......@@ -129,12 +126,12 @@ struct iforce {
u16 ecmd;
u16 expect_packet;
#ifdef IFORCE_232
#ifdef CONFIG_JOYSTICK_IFORCE_232
struct serio *serio; /* RS232 transfer */
int idx, pkt, len, id;
unsigned char csum;
#endif
#ifdef IFORCE_USB
#ifdef CONFIG_JOYSTICK_IFORCE_USB
struct usb_device *usbdev; /* USB transfer */
struct urb *irq, *out, *ctrl;
struct usb_ctrlrequest cr;
......
......@@ -46,6 +46,14 @@ CONFIG_KEYBOARD_XTKBD
The module will be called xtkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_NEWTON
Say Y here if you have a Newton keyboard on a serial port.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called maple_keyb.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_KEYBOARD_MAPLE
Say Y here if you have a DreamCast console running Linux and have
a keyboard attached to its Maple bus.
......
......@@ -8,6 +8,7 @@ dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG
dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
dep_tristate ' Newton keyboard' CONFIG_KEYBOARD_NEWTON $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
dep_tristate ' Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_PS2SERKBD) += ps2serkbd.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
# The global Rules.make.
......
......@@ -121,14 +121,12 @@ struct atkbd {
struct serio *serio;
char name[64];
char phys[32];
struct tq_struct tq;
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
char release;
char ack;
char emul;
char error;
unsigned char release;
signed char ack;
unsigned char emul;
unsigned short id;
};
......@@ -162,8 +160,7 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in
switch (atkbd->keycode[code]) {
case ATKBD_KEY_BAT:
queue_task(&atkbd->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
serio_rescan(atkbd->serio);
return;
case ATKBD_KEY_EMUL0:
atkbd->emul = 1;
......@@ -431,21 +428,6 @@ static void atkbd_disconnect(struct serio *serio)
kfree(atkbd);
}
/*
* atkbd_powerup() is called when the keyboard sends the 0xaa character,
* meaning that it was disconnected and reconnected. We close the port
* in that case and let the upper layer find an appropriate driver for
* the device that was connected. It may be a mouse, or a keyboard, we
* don't know yet.
*/
static void atkbd_powerup(void *data)
{
struct atkbd *atkbd = data;
mdelay(40); /* FIXME!!! Wait some nicer way */
serio_rescan(atkbd->serio);
}
/*
* atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
......@@ -477,9 +459,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.event = atkbd_event;
atkbd->dev.private = atkbd;
atkbd->tq.routine = atkbd_powerup;
atkbd->tq.data = atkbd;
serio->private = atkbd;
if (serio_open(serio, dev)) {
......@@ -504,7 +483,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
if (atkbd->set == 4) {
atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
sprintf(atkbd->name, "AT Set 2 Extended keyboard");
} else
sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
......
/*
* Copyright (c) 2000 Justin Cormack
*/
/*
* Newton keyboard driver for Linux
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail:
* Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK.
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
#define NKBD_KEY 0x7f
#define NKBD_PRESS 0x80
static unsigned char nkbd_keycode[128] = {
KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O,
KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE,
KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT,
KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA,
KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
};
static char *nkbd_name = "Newton Keyboard";
struct nkbd {
unsigned char keycode[128];
struct input_dev dev;
struct serio *serio;
char phys[32];
};
void nkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
struct nkbd *nkbd = serio->private;
/* invalid scan codes are probably the init sequence, so we ignore them */
if (nkbd->keycode[data & NKBD_KEY])
input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
else if (data == 0xe7) /* end of init sequence */
printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
}
void nkbd_connect(struct serio *serio, struct serio_dev *dev)
{
struct nkbd *nkbd;
int i;
if (serio->type != (SERIO_RS232 | SERIO_NEWTON))
return;
if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL)))
return;
memset(nkbd, 0, sizeof(struct nkbd));
nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
nkbd->serio = serio;
nkbd->dev.keycode = nkbd->keycode;
nkbd->dev.private = nkbd;
serio->private = nkbd;
if (serio_open(serio, dev)) {
kfree(nkbd);
return;
}
memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
for (i = 0; i < 128; i++)
set_bit(nkbd->keycode[i], nkbd->dev.keybit);
clear_bit(0, nkbd->dev.keybit);
sprintf(nkbd->phys, "%s/input0", serio->phys);
nkbd->dev.name = nkbd_name;
nkbd->dev.phys = nkbd->phys;
nkbd->dev.idbus = BUS_RS232;
nkbd->dev.idvendor = SERIO_NEWTON;
nkbd->dev.idproduct = 0x0001;
nkbd->dev.idversion = 0x0100;
input_register_device(&nkbd->dev);
printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
}
void nkbd_disconnect(struct serio *serio)
{
struct nkbd *nkbd = serio->private;
input_unregister_device(&nkbd->dev);
serio_close(serio);
kfree(nkbd);
}
struct serio_dev nkbd_dev = {
interrupt: nkbd_interrupt,
connect: nkbd_connect,
disconnect: nkbd_disconnect
};
int __init nkbd_init(void)
{
serio_register_device(&nkbd_dev);
return 0;
}
void __exit nkbd_exit(void)
{
serio_unregister_device(&nkbd_dev);
}
module_init(nkbd_init);
module_exit(nkbd_exit);
/*
* $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $
* Amiga mouse driver for Linux/m68k
*
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000-2002 Vojtech Pavlik
*
* Based on the work of:
* Michael Rausch James Banks
* Matther Dillon David Giller
* Nathan Laredo Linus Torvalds
* Johan Myreen Jes Sorensen
* Russel King
* Russell King
*/
/*
* Amiga mouse driver for Linux/m68k
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation
*/
#include <linux/module.h>
......@@ -70,10 +52,10 @@ static void amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
dx = nx - amimouse_lastx;
dy = ny - amimouse_lasty;
if (dx < -127) dx = (256 + nx) - lastx;
if (dx > 127) dx = (nx - 256) - lastx;
if (dy < -127) dy = (256 + ny) - lasty;
if (dy > 127) dy = (ny - 256) - lasty;
if (dx < -127) dx = (256 + nx) - amimouse_lastx;
if (dx > 127) dx = (nx - 256) - amimouse_lastx;
if (dy < -127) dy = (256 + ny) - amimouse_lasty;
if (dy > 127) dy = (ny - 256) - amimouse_lasty;
amimouse_lastx = nx;
amimouse_lasty = ny;
......
......@@ -216,8 +216,7 @@ static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned
}
if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
queue_task(&psmouse->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
serio_rescan(serio);
return;
}
}
......@@ -557,22 +556,6 @@ static void psmouse_disconnect(struct serio *serio)
kfree(psmouse);
}
/*
* psmouse_powerup() is called when we get the powerup
* sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
*/
static void psmouse_powerup(void *data)
{
struct psmouse *psmouse = data;
if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
(psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
mdelay(40); /* FIXME!!! Wait some nicer way */
serio_rescan(psmouse->serio);
}
}
/*
* psmouse_connect() is a callback form the serio module when
* an unhandled serio port is found.
......@@ -596,8 +579,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->serio = serio;
psmouse->dev.private = psmouse;
psmouse->tq.routine = psmouse_powerup;
psmouse->tq.data = psmouse;
serio->private = psmouse;
......
/*
* $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
* Acorn RiscPC mouse driver for Linux/ARM
*
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2000-2002 Vojtech Pavlik
* Copyright (C) 1996-1998 Russell King
*
* Based on the work of:
* Russel King
*/
/*
* Acorn RiscPC mouse driver for Linux/ARM
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
* This handles the Acorn RiscPCs mouse. We basically have a couple of
* hardware registers that track the sensor count for the X-Y movement and
* another register holding the button state. On every VSYNC interrupt we read
* the complete state and then work out if something has changed.
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
......@@ -41,14 +26,12 @@
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/iomd.h>
#include <asm/hardware/iomd.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
MODULE_LICENSE("GPL");
#define IOMD_MOUSEBTN 0x800C4000
static short rpcmouse_lastx, rpcmouse_lasty;
static struct input_dev rpcmouse_dev = {
......@@ -57,7 +40,7 @@ static struct input_dev rpcmouse_dev = {
relbit: { BIT(REL_X) | BIT(REL_Y) },
name: "Acorn RiscPC Mouse",
phys: "rpcmouse/input0",
idbus: BUS_ISA,
idbus: BUS_HOST,
idvendor: 0x0005,
idproduct: 0x0001,
idversion: 0x0100,
......@@ -67,9 +50,9 @@ static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
{
short x, y, dx, dy, b;
x = (short) inl(IOMD_MOUSEX);
y = (short) inl(IOMD_MOUSEY);
b = (short) inl(IOMD_MOUSEBTN);
x = (short) iomd_readl(IOMD_MOUSEX);
y = (short) iomd_readl(IOMD_MOUSEY);
b = (short) (__raw_readl(0xe0310000) >> 4) & 7;
dx = x - rpcmouse_lastx;
dy = y - rpcmouse_lasty;
......@@ -80,15 +63,15 @@ static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
input_report_rel(&rpcmouse_dev, REL_X, dx);
input_report_rel(&rpcmouse_dev, REL_Y, dy);
input_report_key(&amimouse_dev, BTN_LEFT, buttons & 0x10);
input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20);
input_report_key(&amimouse_dev, BTN_RIGHT, buttons & 0x40);
input_report_key(&rpcmouse_dev, BTN_LEFT, buttons & 0x10);
input_report_key(&rpcmouse_dev, BTN_MIDDLE, buttons & 0x20);
input_report_key(&rpcmouse_dev, BTN_RIGHT, buttons & 0x40);
}
static int __init rpcmouse_init(void)
{
rpcmouse_lastx = (short) inl(IOMD_MOUSEX);
rpcmouse_lasty = (short) inl(IOMD_MOUSEY);
rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
......@@ -96,7 +79,7 @@ static int __init rpcmouse_init(void)
}
input_register_device(&rpcmouse_dev);
printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
printk(KERN_INFO "input: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
return 0;
}
......
......@@ -4,14 +4,15 @@
tristate 'Serial i/o support' CONFIG_SERIO
dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA
dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO
if [ "$CONFIG_SERIO_I8042" != "n" ]; then
hex ' Register Base Address' CONFIG_I8042_REG_BASE 60
int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1
int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12
fi
dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO
dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA
dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO
dep_tristate ' Q40 keyboard controller' CONFIG_SERIO_Q40KBD $CONFIG_SERIO
dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT
if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
......
......@@ -14,6 +14,7 @@ obj-$(CONFIG_SERIO_PARKBD) += parkbd.o
obj-$(CONFIG_SERIO_SERPORT) += serport.o
obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
# The global Rules.make.
......
......@@ -156,8 +156,7 @@ static struct serio ct82c710_port =
static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
if (ct82c710_port.dev)
ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0);
serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0);
}
/*
......
#ifndef _I8042_IO_H
#define _I8042_IO_H
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
/*
* Names.
*/
#define I8042_KBD_PHYS_DESC "isa0060/serio0"
#define I8042_AUX_PHYS_DESC "isa0060/serio1"
/*
* IRQs.
*/
#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ
#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
/*
* Register numbers.
*/
#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4
#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4
#define I8042_DATA_REG CONFIG_I8042_REG_BASE
static inline int i8042_read_data(void)
{
return inb(I8042_DATA_REG);
}
static inline int i8042_read_status(void)
{
return inb(I8042_STATUS_REG);
}
static inline void i8042_write_data(int val)
{
outb(val, I8042_DATA_REG);
return;
}
static inline void i8042_write_command(int val)
{
outb(val, I8042_COMMAND_REG);
return;
}
static inline int i8042_platform_init(void)
{
/*
* On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes.
*/
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return 0;
#endif
return 1;
}
static inline void i8042_platform_exit(void)
{
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
release_region(I8042_DATA_REG, 16);
#endif
}
#endif /* _I8042_IO_H */
#ifndef _I8042_PPCIO_H
#define _I8042_PPCIO_H
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#if defined(CONFIG_WALNUT)
#define I8042_KBD_IRQ 25
#define I8042_AUX_IRQ 26
#define I8042_KBD_PHYS_DESC "walnutps2/serio0"
#define I8042_AUX_PHYS_DESC "walnutps2/serio1"
extern void *kb_cs;
extern void *kb_data;
static inline int i8042_read_data(void)
{
return readb(kb_data);
}
static inline int i8042_read_status(void)
{
return readb(kb_cs);
}
static inline void i8042_write_data(int val)
{
writeb(val, kb_data);
return;
}
static inline void i8042_write_command(int val)
{
writeb(val, kb_cs);
return;
}
static inline int i8042_platform_init(void)
{
return 1;
}
static inline void i8042_platform_exit(void)
{
}
#elif defined(CONFIG_SPRUCE)
#define I8042_KBD_IRQ 22
#define I8042_AUX_IRQ 21
#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
static inline int i8042_read_data(void)
{
unsigned long kbd_data;
__raw_writel(0x00000088, 0xff500008);
eieio();
__raw_writel(0x03000000, 0xff50000c);
eieio();
asm volatile("lis 7,0xff88 \n\
lswi 6,7,0x8 \n\
mr %0,6"
: "=r" (kbd_data) :: "6", "7");
__raw_writel(0x00000000, 0xff50000c);
eieio();
return (unsigned char)(kbd_data >> 24);
}
static inline int i8042_read_status(void)
{
unsigned long kbd_status;
__raw_writel(0x00000088, 0xff500008);
eieio();
__raw_writel(0x03000000, 0xff50000c);
eieio();
asm volatile("lis 7,0xff88 \n\
ori 7,7,0x8 \n\
lswi 6,7,0x8 \n\
mr %0,6"
: "=r" (kbd_status) :: "6", "7");
__raw_writel(0x00000000, 0xff50000c);
eieio();
return (unsigned char)(kbd_status >> 24);
}
static inline void i8042_write_data(int val)
{
*((unsigned char *)0xff810000) = (char)val;
return;
}
static inline void i8042_write_command(int val)
{
*((unsigned char *)0xff810001) = (char)val;
return;
}
static inline int i8042_platform_init(void)
{
return 1;
}
static inline void i8042_platform_exit(void)
{
}
#else
#include "i8042-io.h"
#endif
#endif /* _I8042_PPCIO_H */
/*
* $Id: i8042.c,v 1.21 2002/03/01 22:09:27 jsimmons Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <asm/io.h>
......@@ -70,6 +52,7 @@ static struct serio i8042_kbd_port;
static struct serio i8042_aux_port;
static unsigned char i8042_initial_ctr;
static unsigned char i8042_ctr;
struct timer_list i8042_timer;
#ifdef I8042_DEBUG_IO
static unsigned long i8042_start;
......@@ -97,7 +80,7 @@ static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int i8042_wait_read(void)
{
int i = 0;
while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
}
......@@ -107,7 +90,7 @@ static int i8042_wait_read(void)
static int i8042_wait_write(void)
{
int i = 0;
while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
}
......@@ -126,12 +109,12 @@ static int i8042_flush(void)
spin_lock_irqsave(&i8042_lock, flags);
while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
#ifdef I8042_DEBUG_IO
printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n",
inb(I8042_DATA_REG), (int) (jiffies - i8042_start));
i8042_read_data(), (int) (jiffies - i8042_start));
#else
inb(I8042_DATA_REG);
i8042_read_data();
#endif
spin_unlock_irqrestore(&i8042_lock, flags);
......@@ -160,7 +143,7 @@ static int i8042_command(unsigned char *param, int command)
printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n",
command & 0xff, (int) (jiffies - i8042_start));
#endif
outb(command & 0xff, I8042_COMMAND_REG);
i8042_write_command(command & 0xff);
}
if (!retval)
......@@ -170,16 +153,16 @@ static int i8042_command(unsigned char *param, int command)
printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n",
param[i], (int) (jiffies - i8042_start));
#endif
outb(param[i], I8042_DATA_REG);
i8042_write_data(param[i]);
}
if (!retval)
for (i = 0; i < ((command >> 8) & 0xf); i++) {
if ((retval = i8042_wait_read())) break;
if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA)
param[i] = ~inb(I8042_DATA_REG);
if (i8042_read_status() & I8042_STR_AUXDATA)
param[i] = ~i8042_read_data();
else
param[i] = inb(I8042_DATA_REG);
param[i] = i8042_read_data();
#ifdef I8042_DEBUG_IO
printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n",
param[i], (int) (jiffies - i8042_start));
......@@ -216,7 +199,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n",
c, (int) (jiffies - i8042_start));
#endif
outb(c, I8042_DATA_REG);
i8042_write_data(c);
}
spin_unlock_irqrestore(&i8042_lock, flags);
......@@ -243,7 +226,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c)
* mode tend to trash their CTR when doing the AUX_SEND command.
*/
retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
retval |= i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
/*
* Make sure the interrupt happens and the character is received even
......@@ -251,7 +234,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c)
* characters later.
*/
i8042_interrupt(0, port, NULL);
i8042_interrupt(0, NULL, NULL);
return retval;
}
......@@ -269,28 +252,23 @@ static int i8042_open(struct serio *port)
*/
if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name);
printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
values->exists = 0;
serio_unregister_port(port);
return -1;
}
/*
* Enable the device and its interrupt.
* Enable the interrupt.
*/
i8042_ctr |= values->irqen;
i8042_ctr &= ~values->disable;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
return -1;
}
/*
* Flush buffers
*/
i8042_flush();
return 0;
}
......@@ -304,11 +282,10 @@ static void i8042_close(struct serio *port)
struct i8042_values *values = port->driver;
/*
* Disable the device and its interrupt.
* Disable the interrupt.
*/
i8042_ctr &= ~values->irqen;
i8042_ctr |= values->disable;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
......@@ -342,7 +319,7 @@ static struct serio i8042_kbd_port =
close: i8042_close,
driver: &i8042_kbd_values,
name: "i8042 Kbd Port",
phys: "isa0060/serio0",
phys: I8042_KBD_PHYS_DESC,
};
static struct i8042_values i8042_aux_values = {
......@@ -361,7 +338,7 @@ static struct serio i8042_aux_port =
close: i8042_close,
driver: &i8042_aux_values,
name: "i8042 Aux Port",
phys: "isa0060/serio1",
phys: I8042_AUX_PHYS_DESC,
};
/*
......@@ -374,27 +351,29 @@ static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char str, data;
unsigned int dfl;
spin_lock_irqsave(&i8042_lock, flags);
while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) {
while ((str = i8042_read_status()) & I8042_STR_OBF) {
data = inb(I8042_DATA_REG);
data = i8042_read_data();
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
#ifdef I8042_DEBUG_IO
printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n",
data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start));
printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s, %d) [%d]\n",
data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, (int) (jiffies - i8042_start));
#endif
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
if (i8042_aux_port.dev)
i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0);
serio_interrupt(&i8042_aux_port, data, dfl);
} else {
if (i8042_kbd_values.exists && i8042_kbd_port.dev) {
if (i8042_kbd_values.exists) {
if (!i8042_direct) {
if (data > 0x7f) {
if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0);
serio_interrupt(&i8042_kbd_port, 0xf0, dfl);
data = i8042_unxlate_table[data & 0x7f];
}
} else {
......@@ -402,7 +381,7 @@ static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
data = i8042_unxlate_table[data];
}
}
i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0);
serio_interrupt(&i8042_kbd_port, data, dfl);
}
}
}
......@@ -477,7 +456,7 @@ static int __init i8042_controller_init(void)
* Handle keylock.
*/
if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) {
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock) {
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
......@@ -525,6 +504,8 @@ static int __init i8042_controller_init(void)
void i8042_controller_cleanup(void)
{
i8042_flush();
/*
* Reset the controller.
*/
......@@ -566,6 +547,19 @@ static int __init i8042_check_aux(struct i8042_values *values, struct serio *por
{
unsigned char param;
/*
* Check if AUX irq is available. If it isn't, then there is no point
* in trying to detect AUX presence.
*/
if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL))
return -1;
free_irq(values->irq, NULL);
/*
* Get rid of bytes in the queue.
*/
i8042_flush();
/*
......@@ -638,6 +632,32 @@ static int __init i8042_port_register(struct i8042_values *values, struct serio
return 0;
}
static void i8042_timer_func(unsigned long data)
{
i8042_interrupt(0, NULL, NULL);
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
}
static void __init i8042_start_polling(void)
{
i8042_ctr &= ~I8042_CTR_KBDDIS;
if (i8042_aux_values.exists)
i8042_ctr &= ~I8042_CTR_AUXDIS;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_WARNING "i8042.c: Can't write CTR while starting polling.\n");
return;
}
i8042_timer.function = i8042_timer_func;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
}
static void __exit i8042_stop_polling(void)
{
del_timer(&i8042_timer);
}
/*
* Module init and cleanup functions.
*/
......@@ -678,6 +698,9 @@ int __init i8042_init(void)
i8042_start = jiffies;
#endif
if (!i8042_platform_init())
return -EBUSY;
if (i8042_controller_init())
return -ENODEV;
......@@ -686,20 +709,18 @@ int __init i8042_init(void)
if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port))
i8042_port_register(&i8042_aux_values, &i8042_aux_port);
/*
* On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes.
*/
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
request_region(I8042_DATA_REG, 16, "i8042");
#endif
i8042_start_polling();
register_reboot_notifier(&i8042_notifier);
return 0;
}
void __exit i8042_exit(void)
{
unregister_reboot_notifier(&i8042_notifier);
i8042_stop_polling();
if (i8042_kbd_values.exists)
serio_unregister_port(&i8042_kbd_port);
......@@ -708,9 +729,8 @@ void __exit i8042_exit(void)
serio_unregister_port(&i8042_aux_port);
i8042_controller_cleanup();
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
release_region(I8042_DATA_REG, 16);
#endif
i8042_platform_exit();
}
module_init(i8042_init);
......
......@@ -2,36 +2,22 @@
#define _I8042_H
/*
* $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $
* Copyright (c) 1999-2002 Vojtech Pavlik
*
* Copyright (c) 1999-2001 Vojtech Pavlik
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
* Arch-dependent inline functions and defines.
*/
/*
* If you want to reset your i8042 upon boot, define this.
*/
#undef I8042_RESET
#if defined(CONFIG_PPC)
#include "i8042-ppcio.h"
#else
#include "i8042-io.h"
#endif
/*
* If you want to trace all the i/o the i8042 module does for
......@@ -40,20 +26,6 @@
#undef I8042_DEBUG_IO
/*
* On most PC based systems the keyboard IRQ is 1.
*/
#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ
/*
* On most PC based systems the aux port IRQ is 12. There are exceptions,
* though. Unfortunately IRQ probing is not possible without touching
* the device attached to the port.
*/
#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
/*
* This is in 50us units, the time we wait for the i8042 to react. This
* has to be long enough for the i8042 itself to timeout on sending a byte
......@@ -63,12 +35,13 @@
#define I8042_CTL_TIMEOUT 10000
/*
* Register numbers.
* When the device isn't opened and it's interrupts aren't used, we poll it at
* regular intervals to see if any characters arrived. If yes, we can start
* probing for any mouse / keyboard connected. This is the period of the
* polling.
*/
#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4
#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4
#define I8042_DATA_REG CONFIG_I8042_REG_BASE
#define I8042_POLL_PERIOD HZ/20
/*
* Status register bits.
......
......@@ -135,10 +135,8 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
if (parkbd_counter == parkbd_mode + 10) {
if (parkbd_port.dev)
parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
}
if (parkbd_counter == parkbd_mode + 10)
serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
}
parkbd_last = jiffies;
......
/*
* $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* Richard Zidlicky <Richard.Zidlicky@stud.informatik.uni-erlangen.de>
*/
/*
* Q40 PS/2 keyboard controller driver for Linux/m68k
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/q40_master.h>
#include <asm/irq.h>
#include <asm/q40ints.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
static struct serio q40kbd_port =
{
type: SERIO_8042,
write: NULL,
name: "Q40 PS/2 kbd port",
phys: "isa0060/serio0",
};
static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
if (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
if (q40kbd_port.dev)
q40kbd_port.dev->interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0);
master_outb(-1, KEYBOARD_UNLOCK_REG);
}
void __init q40kbd_init(void)
{
int maxread = 100;
/* Get the keyboard controller registers (incomplete decode) */
request_region(0x60, 16, "q40kbd");
/* allocate the IRQ */
request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL);
/* flush any pending input. */
while (maxread-- && (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
master_inb(KEYCODE_REG);
/* off we go */
master_outb(-1,KEYBOARD_UNLOCK_REG);
master_outb(1,KEY_IRQ_ENABLE_REG);
register_serio_port(&q40kbd_port);
printk(KERN_INFO "serio: Q40 PS/2 kbd port irq %d\n", Q40_IRQ_KEYBOARD);
}
void __exit q40kbd_exit(void)
{
unregister_serio_port(&q40kbd_port);
free_irq(Q40_IRQ_KEYBOARD, NULL);
release_region(0x60, 16);
}
module_init(q40kbd_init);
module_exit(q40kbd_exit);
......@@ -64,8 +64,7 @@ static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
kbd_pt_regs = regs;
while (inb(IOMD_KCTRL) & (1 << 5))
if (rpckbd_port.dev)
rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
serio_interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
}
......
......@@ -32,6 +32,11 @@
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/suspend.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
......@@ -47,6 +52,7 @@ EXPORT_SYMBOL(serio_rescan);
static struct serio *serio_list;
static struct serio_dev *serio_dev;
static int serio_pid;
static void serio_find_dev(struct serio *serio)
{
......@@ -59,11 +65,58 @@ static void serio_find_dev(struct serio *serio)
}
}
#define SERIO_RESCAN 1
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
void serio_handle_events(void)
{
struct serio *serio = serio_list;
while (serio) {
if (serio->event & SERIO_RESCAN) {
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
serio_find_dev(serio);
}
serio->event = 0;
serio = serio->next;
}
}
static int serio_thread(void *nothing)
{
lock_kernel();
daemonize();
strcpy(current->comm, "kseriod");
do {
serio_handle_events();
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
interruptible_sleep_on(&serio_wait);
} while (!signal_pending(current));
printk(KERN_DEBUG "serio: kseriod exiting");
unlock_kernel();
complete_and_exit(&serio_exited, 0);
}
void serio_rescan(struct serio *serio)
{
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
serio_find_dev(serio);
serio->event |= SERIO_RESCAN;
wake_up(&serio_wait);
}
void serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
if (serio->dev && serio->dev->interrupt)
serio->dev->interrupt(serio, data, flags);
else
serio_rescan(serio);
}
void serio_register_port(struct serio *serio)
......@@ -127,3 +180,29 @@ void serio_close(struct serio *serio)
serio->close(serio);
serio->dev = NULL;
}
int serio_init(void)
{
int pid;
pid = kernel_thread(serio_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (!pid) {
printk(KERN_WARNING "serio: Failed to start kseriod\n");
return -1;
}
serio_pid = pid;
return 0;
}
void serio_exit(void)
{
kill_proc(serio_pid, SIGTERM, 1);
wait_for_completion(&serio_exited);
}
module_init(serio_init);
module_exit(serio_exit);
......@@ -138,8 +138,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
struct serport *serport = (struct serport*) tty->disc_data;
int i;
for (i = 0; i < count; i++)
if (serport->serio.dev)
serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
serio_interrupt(&serport->serio, cp[i], 0);
}
/*
......
......@@ -14,3 +14,13 @@ CONFIG_TOUCHSCREEN_GUNZE
inserted in and removed from the running kernel whenever you want).
The module will be called gunze.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_TOUCHSCREEN_BITSY
Say Y here if you have the h3600 (Bitsy) touchscreen.
If unsure, say N.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called gunze.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
......@@ -4,4 +4,7 @@
bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
if [ "$CONFIG_SA1100_BITSY" = "y" ]; then
dep_tristate ' Compaq iPAQ H3600 (Bitsy) touchscreen input driver' CONFIG_TOUCHSCREEN_BITSY $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
fi
dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
......@@ -4,6 +4,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
# The global Rules.make.
......
/*
* $Id: h3600_ts_input.c,v 1.4 2002/01/23 06:39:37 jsimmons Exp $
*
* Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
*
* Sponsored by Transvirtual Technology.
*
* Derived from the code in h3600_ts.[ch] by Charles Flynn
*/
/*
* Driver for the h3600 Touch Screen and other Atmel controlled devices.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so by
* e-mail - mail your message to <jsimmons@transvirtual.com>.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
/* SA1100 serial defines */
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>
/*
* Definitions & global arrays.
*/
/* The start and end of frame characters SOF and EOF */
#define CHAR_SOF 0x02
#define CHAR_EOF 0x03
#define FRAME_OVERHEAD 3 /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */
/*
Atmel events and response IDs contained in frame.
Programmer has no control over these numbers.
TODO there are holes - specifically 1,7,0x0a
*/
#define VERSION_ID 0 /* Get Version (request/respose) */
#define KEYBD_ID 2 /* Keyboard (event) */
#define TOUCHS_ID 3 /* Touch Screen (event)*/
#define EEPROM_READ_ID 4 /* (request/response) */
#define EEPROM_WRITE_ID 5 /* (request/response) */
#define THERMAL_ID 6 /* (request/response) */
#define NOTIFY_LED_ID 8 /* (request/response) */
#define BATTERY_ID 9 /* (request/response) */
#define SPI_READ_ID 0x0b /* ( request/response) */
#define SPI_WRITE_ID 0x0c /* ( request/response) */
#define FLITE_ID 0x0d /* backlight ( request/response) */
#define STX_ID 0xa1 /* extension pack status (req/resp) */
#define MAX_ID 14
#define H3600_MAX_LENGTH 16
#define H3600_KEY 0xf
#define H3600_SCANCODE_RECORD 1 /* 1 -> record button */
#define H3600_SCANCODE_CALENDAR 2 /* 2 -> calendar */
#define H3600_SCANCODE_CONTACTS 3 /* 3 -> contact */
#define H3600_SCANCODE_Q 4 /* 4 -> Q button */
#define H3600_SCANCODE_START 5 /* 5 -> start menu */
#define H3600_SCANCODE_UP 6 /* 6 -> up */
#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
static char *h3600_name = "H3600 TouchScreen";
/*
* Per-touchscreen data.
*/
struct h3600_dev {
struct input_dev dev;
struct serio *serio;
unsigned char event; /* event ID from packet */
unsigned char chksum;
unsigned char len;
unsigned char idx;
unsigned char buf[H3600_MAX_LENGTH];
char phys[32];
};
static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
input_report_key(dev, KEY_ENTER, down);
}
static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
/*
* This interrupt is only called when we release the key. So we have
* to fake a key press.
*/
input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down);
}
#ifdef CONFIG_PM
static int flite_brightness = 25;
enum flite_pwr {
FLITE_PWR_OFF = 0,
FLITE_PWR_ON = 1
};
/*
* h3600_flite_power: enables or disables power to frontlight, using last bright */
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{
unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness);
struct h3600_dev *ts = dev->private;
/* Must be in this order */
ts->serio->write(ts->serio, 1);
ts->serio->write(ts->serio, pwr);
ts->serio->write(ts->serio, brightness);
return 0;
}
static int suspended = 0;
static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
void *data)
{
struct input_dev *dev = (struct input_dev *) data;
switch (req) {
case PM_SUSPEND: /* enter D1-D3 */
suspended = 1;
h3600_flite_power(dev, FLITE_PWR_OFF);
break;
case PM_BLANK:
if (!suspended)
h3600_flite_power(dev, FLITE_PWR_OFF);
break;
case PM_RESUME: /* enter D0 */
/* same as unblank */
case PM_UNBLANK:
if (suspended) {
//initSerial();
suspended = 0;
}
h3600_flite_power(dev, FLITE_PWR_ON);
break;
}
return 0;
}
#endif
/*
* This function translates the native event packets to linux input event
* packets. Some packets coming from serial are not touchscreen related. In
* this case we send them off to be processed elsewhere.
*/
static void h3600ts_process_packet(struct h3600_dev *ts)
{
struct input_dev *dev = &ts->dev;
static int touched = 0;
int key, down = 0;
switch (ts->event) {
/*
Buttons - returned as a single byte
7 6 5 4 3 2 1 0
S x x x N N N N
S switch state ( 0=pressed 1=released)
x Unused.
NNNN switch number 0-15
Note: This is true for non interrupt generated key events.
*/
case KEYBD_ID:
down = (ts->buf[0] & 0x80) ? 0 : 1;
switch (ts->buf[0] & 0x7f) {
case H3600_SCANCODE_RECORD:
key = KEY_RECORD;
break;
case H3600_SCANCODE_CALENDAR:
key = KEY_PROG1;
break;
case H3600_SCANCODE_CONTACTS:
key = KEY_PROG2;
break;
case H3600_SCANCODE_Q:
key = KEY_Q;
break;
case H3600_SCANCODE_START:
key = KEY_PROG3;
break;
case H3600_SCANCODE_UP:
key = KEY_UP;
break;
case H3600_SCANCODE_RIGHT:
key = KEY_RIGHT;
break;
case H3600_SCANCODE_LEFT:
key = KEY_LEFT;
break;
case H3600_SCANCODE_DOWN:
key = KEY_DOWN;
break;
default:
key = 0;
}
if (key)
input_report_key(dev, key, down);
break;
/*
* Native touchscreen event data is formatted as shown below:-
*
* +-------+-------+-------+-------+
* | Xmsb | Xlsb | Ymsb | Ylsb |
* +-------+-------+-------+-------+
* byte 0 1 2 3
*/
case TOUCHS_ID:
if (!touched) {
input_report_key(dev, BTN_TOUCH, 1);
touched = 1;
}
if (ts->len) {
unsigned short x, y;
x = ts->buf[0]; x <<= 8; x += ts->buf[1];
y = ts->buf[2]; y <<= 8; y += ts->buf[3];
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
} else {
input_report_key(dev, BTN_TOUCH, 0);
touched = 0;
}
break;
default:
/* Send a non input event elsewhere */
break;
}
}
/*
* h3600ts_event() handles events from the input module.
*/
static int h3600ts_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct h3600_dev *ts = dev->private;
switch (type) {
case EV_LED: {
// ts->serio->write(ts->serio, SOME_CMD);
return 0;
}
}
return -1;
}
/*
Frame format
byte 1 2 3 len + 4
+-------+---------------+---------------+--=------------+
|SOF |id |len | len bytes | Chksum |
+-------+---------------+---------------+--=------------+
bit 0 7 8 11 12 15 16
+-------+---------------+-------+
|SOF |id |0 |Chksum | - Note Chksum does not include SOF
+-------+---------------+-------+
bit 0 7 8 11 12 15 16
*/
static int state;
/* decode States */
#define STATE_SOF 0 /* start of FRAME */
#define STATE_ID 1 /* state where we decode the ID & len */
#define STATE_DATA 2 /* state where we decode data */
#define STATE_EOF 3 /* state where we decode checksum or EOF */
static void h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags)
{
struct h3600_dev *ts = serio->private;
/*
* We have a new frame coming in.
*/
switch (state) {
case STATE_SOF:
if (data == CHAR_SOF)
state = STATE_ID;
return;
case STATE_ID:
ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf);
ts->idx = 0;
if (ts->event >= MAX_ID) {
state = STATE_SOF;
break;
}
ts->chksum = data;
state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF;
break;
case STATE_DATA:
ts->chksum += data;
ts->buf[ts->idx]= data;
if(++ts->idx == ts->len)
state = STATE_EOF;
break;
case STATE_EOF:
state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum )
h3600ts_process_packet(ts);
break;
default:
printk("Error3\n");
break;
}
}
/*
* h3600ts_connect() is the routine that is called when someone adds a
* new serio device. It looks whether it was registered as a H3600 touchscreen
* and if yes, registers it as an input device.
*/
static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
{
struct h3600_dev *ts;
if (serio->type != (SERIO_RS232 | SERIO_H3600))
return;
if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL)))
return;
memset(ts, 0, sizeof(struct h3600_dev));
/* Device specific stuff */
set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE );
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
kfree(ts);
return;
}
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_suspend", &ts->dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
kfree(ts);
return;
}
/* Now we have things going we setup our input device */
ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
ts->dev.ledbit[0] = BIT(LED_SLEEP);
ts->dev.absmin[ABS_X] = 60; ts->dev.absmin[ABS_Y] = 35;
ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024;
ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0;
ts->serio = serio;
serio->private = ts;
set_bit(KEY_RECORD, ts->dev.keybit);
set_bit(KEY_Q, ts->dev.keybit);
set_bit(KEY_PROG1, ts->dev.keybit);
set_bit(KEY_PROG2, ts->dev.keybit);
set_bit(KEY_PROG3, ts->dev.keybit);
set_bit(KEY_UP, ts->dev.keybit);
set_bit(KEY_RIGHT, ts->dev.keybit);
set_bit(KEY_LEFT, ts->dev.keybit);
set_bit(KEY_DOWN, ts->dev.keybit);
set_bit(KEY_ENTER, ts->dev.keybit);
ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
sprintf(ts->phys, "%s/input0", serio->phys);
ts->dev.event = h3600ts_event;
ts->dev.private = ts;
ts->dev.name = h3600_name;
ts->dev.phys = ts->phys;
ts->dev.idbus = BUS_RS232;
ts->dev.idvendor = SERIO_H3600;
ts->dev.idproduct = 0x0666; /* FIXME !!! We can ask the hardware */
ts->dev.idversion = 0x0100;
if (serio_open(serio, dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
kfree(ts);
return;
}
//h3600_flite_control(1, 25); /* default brightness */
#ifdef CONFIG_PM
ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT,
h3600ts_pm_callback);
printk("registered pm callback\n");
#endif
input_register_device(&ts->dev);
printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys);
}
/*
* h3600ts_disconnect() is the opposite of h3600ts_connect()
*/
static void h3600ts_disconnect(struct serio *serio)
{
struct h3600_dev *ts = serio->private;
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
input_unregister_device(&ts->dev);
serio_close(serio);
kfree(ts);
}
/*
* The serio device structure.
*/
static struct serio_dev h3600ts_dev = {
interrupt: h3600ts_interrupt,
connect: h3600ts_connect,
disconnect: h3600ts_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init h3600ts_init(void)
{
serio_register_device(&h3600ts_dev);
return 0;
}
static void __exit h3600ts_exit(void)
{
serio_unregister_device(&h3600ts_dev);
}
module_init(h3600ts_init);
module_exit(h3600ts_exit);
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.1 20/06/2002
* - first public version
*/
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uinput.h>
static int uinput_dev_open(struct input_dev *dev)
{
return 0;
}
static void uinput_dev_close(struct input_dev *dev)
{
}
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct uinput_device *udev;
udev = (struct uinput_device *)dev->private;
udev->head = (udev->head + 1) & 0xF;
udev->buff[udev->head].type = type;
udev->buff[udev->head].code = code;
udev->buff[udev->head].value = value;
do_gettimeofday(&udev->buff[udev->head].time);
wake_up_interruptible(&udev->waitq);
return 0;
}
static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
{
return 0;
}
static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
{
return 0;
}
static int uinput_create_device(struct uinput_device *udev)
{
if (!udev->dev->name) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
return -EINVAL;
}
udev->dev->open = uinput_dev_open;
udev->dev->close = uinput_dev_close;
udev->dev->event = uinput_dev_event;
udev->dev->upload_effect = uinput_dev_upload_effect;
udev->dev->erase_effect = uinput_dev_erase_effect;
init_waitqueue_head(&(udev->waitq));
input_register_device(udev->dev);
udev->state |= UIST_CREATED;
return 0;
}
static int uinput_destroy_device(struct uinput_device *udev)
{
if (!(udev->state & UIST_CREATED)) {
printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
return -EINVAL;
}
input_unregister_device(udev->dev);
clear_bit(UIST_CREATED, &(udev->state));
return 0;
}
static int uinput_open(struct inode *inode, struct file *file)
{
struct uinput_device *newdev;
struct input_dev *newinput;
MOD_INC_USE_COUNT;
newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
if (!newdev)
goto error;
memset(newdev, 0, sizeof(struct uinput_device));
newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
if (!newinput)
goto cleanup;
memset(newinput, 0, sizeof(struct input_dev));
newdev->dev = newinput;
file->private_data = newdev;
return 0;
cleanup:
kfree(newdev);
error:
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
{
struct uinput_user_dev user_dev;
struct input_dev *dev;
struct uinput_device *udev;
int size,
retval;
retval = count;
if (copy_from_user(&user_dev, buffer, sizeof(struct uinput_user_dev))) {
retval = -EFAULT;
goto exit;
}
udev = (struct uinput_device *)file->private_data;
dev = udev->dev;
size = strnlen(user_dev.name, UINPUT_MAX_NAME_SIZE);
dev->name = kmalloc(size + 1, GFP_KERNEL);
if (!dev->name) {
retval = -ENOMEM;
goto exit;
}
strncpy(dev->name, user_dev.name, size);
dev->name[size] = '\0';
dev->idbus = user_dev.idbus;
dev->idvendor = user_dev.idvendor;
dev->idproduct = user_dev.idproduct;
dev->idversion = user_dev.idversion;
dev->ff_effects_max = user_dev.ff_effects_max;
size = sizeof(unsigned long) * NBITS(ABS_MAX + 1);
memcpy(dev->absmax, user_dev.absmax, size);
memcpy(dev->absmin, user_dev.absmin, size);
memcpy(dev->absfuzz, user_dev.absfuzz, size);
memcpy(dev->absflat, user_dev.absflat, size);
/* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) {
unsigned int cnt;
for (cnt = 1; cnt < ABS_MAX; cnt++)
if (test_bit(cnt, dev->absbit) &&
(!dev->absmin[cnt] ||
!dev->absmax[cnt] ||
!dev->absfuzz[cnt] ||
!dev->absflat[cnt])) {
printk(KERN_DEBUG "%s: set abs fields "
"first\n", UINPUT_NAME);
retval = -EINVAL;
goto free_name;
}
}
exit:
return retval;
free_name:
kfree(dev->name);
goto exit;
}
static int uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct uinput_device *udev = file->private_data;
if (udev->state & UIST_CREATED) {
struct input_event ev;
if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
return -EFAULT;
input_event(udev->dev, ev.type, ev.code, ev.value);
}
else
count = uinput_alloc_device(file, buffer, count);
return count;
}
static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct uinput_device *udev;
int retval = 0;
DECLARE_WAITQUEUE(waitq, current);
udev = (struct uinput_device *)file->private_data;
if (udev->head == udev->tail) {
add_wait_queue(&udev->waitq, &waitq);
current->state = TASK_INTERRUPTIBLE;
while (udev->head == udev->tail) {
if (!(udev->state & UIST_CREATED)) {
retval = -ENODEV;
break;
}
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
schedule();
}
current->state = TASK_RUNNING;
remove_wait_queue(&udev->waitq, &waitq);
}
if (retval)
return retval;
while (udev->head != udev->tail && retval + sizeof(struct uinput_device) <= count) {
if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
sizeof(struct input_event)))
return -EFAULT;
udev->tail = (udev->tail + 1)%(UINPUT_BUFFER_SIZE - 1);
retval += sizeof(struct input_event);
}
return retval;
}
static unsigned int uinput_poll(struct file *file, poll_table *wait)
{
struct uinput_device *udev = file->private_data;
poll_wait(file, &udev->waitq, wait);
if (udev->head != udev->tail)
return POLLIN | POLLRDNORM;
return 0;
}
static int uinput_burn_device(struct uinput_device *udev)
{
if (udev->state & UIST_CREATED)
uinput_destroy_device(udev);
kfree(udev->dev);
kfree(udev);
return 0;
}
static int uinput_close(struct inode *inode, struct file *file)
{
int retval;
retval = uinput_burn_device((struct uinput_device *)file->private_data);
MOD_DEC_USE_COUNT;
return retval;
}
static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
struct uinput_device *udev;
udev = (struct uinput_device *)file->private_data;
if (cmd >= UI_SET_EVBIT && (udev->state & UIST_CREATED))
return -EINVAL;
switch (cmd) {
case UI_DEV_CREATE:
retval = uinput_create_device(udev);
break;
case UI_DEV_DESTROY:
retval = uinput_destroy_device(udev);
break;
case UI_SET_EVBIT:
set_bit(arg, udev->dev->evbit);
break;
case UI_SET_KEYBIT:
set_bit(arg, udev->dev->keybit);
break;
case UI_SET_RELBIT:
set_bit(arg, udev->dev->relbit);
break;
case UI_SET_ABSBIT:
set_bit(arg, udev->dev->absbit);
break;
case UI_SET_MSCBIT:
set_bit(arg, udev->dev->mscbit);
break;
case UI_SET_LEDBIT:
set_bit(arg, udev->dev->ledbit);
break;
case UI_SET_SNDBIT:
set_bit(arg, udev->dev->sndbit);
break;
case UI_SET_FFBIT:
set_bit(arg, udev->dev->ffbit);
break;
default:
retval = -EFAULT;
}
return retval;
}
struct file_operations uinput_fops = {
owner: THIS_MODULE,
open: uinput_open,
release: uinput_close,
read: uinput_read,
write: uinput_write,
poll: uinput_poll,
// fasync: uinput_fasync,
ioctl: uinput_ioctl,
};
static struct miscdevice uinput_misc = {
fops: &uinput_fops,
minor: UINPUT_MINOR,
name: UINPUT_NAME,
};
static int __init uinput_init(void)
{
int retval;
retval = misc_register(&uinput_misc);
if (!retval) {
printk(KERN_INFO "%s: User level driver support for input subsystem loaded\n", UINPUT_NAME);
printk(KERN_INFO "%s: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>\n", UINPUT_NAME);
}
return retval;
}
static void __exit uinput_exit(void)
{
misc_deregister(&uinput_misc);
}
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
module_init(uinput_init);
module_exit(uinput_exit);
......@@ -77,6 +77,7 @@ struct adbhid {
int mouse_kind;
unsigned char *keycode;
char name[64];
char phys[32];
};
static struct adbhid *adbhid[16] = { 0 };
......@@ -273,12 +274,37 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
switch (adbhid[id]->original_handler_id) {
default:
case 0x02: /* Adjustable keyboard button device */
printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
data[0], data[1], data[2], data[3]);
break;
{
int down = (data[1] == (data[1] & 0xf));
switch (data[1] & 0x0f) {
case 0x0: /* microphone */
input_report_key(&adbhid[id]->input, KEY_SOUND, down);
break;
case 0x1: /* mute */
input_report_key(&adbhid[id]->input, KEY_MUTE, down);
break;
case 0x2: /* volume decrease */
input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down);
break;
case 0x3: /* volume increase */
input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down);
break;
default:
printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
data[0], data[1], data[2], data[3]);
break;
}
}
break;
case 0x1f: /* Powerbook button device */
{
int down = (data[1] == (data[1] & 0xf));
int down = (data[1] == (data[1] & 0xf));
#ifdef CONFIG_PMAC_BACKLIGHT
int backlight = get_backlight_level();
#endif
......@@ -298,11 +324,12 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x6: /* volume increase */
input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down);
break;
break;
case 0xb: /* eject */
input_report_key(&adbhid[id]->input, KEY_EJECTCD, down);
break;
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
if (!disable_kernel_backlight) {
......@@ -317,6 +344,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
#endif /* CONFIG_PMAC_BACKLIGHT */
input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
break;
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
if (!disable_kernel_backlight) {
......@@ -442,6 +470,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
return;
memset(adbhid[id], 0, sizeof(struct adbhid));
sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
adbhid[id]->id = default_id;
adbhid[id]->original_handler_id = original_handler_id;
......@@ -449,6 +478,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
adbhid[id]->mouse_kind = mouse_kind;
adbhid[id]->input.private = adbhid[id];
adbhid[id]->input.name = adbhid[id]->name;
adbhid[id]->input.phys = adbhid[id]->phys;
adbhid[id]->input.idbus = BUS_ADB;
adbhid[id]->input.idvendor = 0x0001;
adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id;
......@@ -461,8 +491,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
return;
}
sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x",
id, default_id, original_handler_id);
sprintf(adbhid[id]->name, "ADB keyboard");
memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
......@@ -509,8 +538,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
break;
case ADB_MOUSE:
sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x",
id, default_id, original_handler_id);
sprintf(adbhid[id]->name, "ADB mouse");
adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
......@@ -520,12 +548,15 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
case ADB_MISC:
switch (original_handler_id) {
case 0x02: /* Adjustable keyboard button device */
sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x",
id, default_id, original_handler_id);
sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons");
adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
set_bit(KEY_SOUND, adbhid[id]->input.keybit);
set_bit(KEY_MUTE, adbhid[id]->input.keybit);
set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit);
set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit);
break;
case 0x1f: /* Powerbook button device */
sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x",
id, default_id, original_handler_id);
sprintf(adbhid[id]->name, "ADB Powerbook buttons");
adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
set_bit(KEY_MUTE, adbhid[id]->input.keybit);
set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit);
......@@ -549,8 +580,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
input_register_device(&adbhid[id]->input);
printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n",
adbhid[id]->input.number, id, default_id, original_handler_id);
printk(KERN_INFO "input: %s on %s\n",
adbhid[id]->name, adbhid[id]->phys);
if (default_id == ADB_KEYBOARD) {
/* HACK WARNING!! This should go away as soon there is an utility
......@@ -580,11 +611,11 @@ adbhid_input_reregister(int id, int default_id, int org_handler_id,
((id << 12)|(default_id << 8)|org_handler_id)) {
adbhid_input_unregister(id);
adbhid_input_register(id, default_id, org_handler_id,
cur_handler_id, mk);
cur_handler_id, mk);
}
} else
adbhid_input_register(id, default_id, org_handler_id,
cur_handler_id, mk);
cur_handler_id, mk);
return 1<<id;
}
......@@ -593,10 +624,10 @@ adbhid_input_devcleanup(u16 exist)
{
int i;
for(i=1; i<16; i++)
if (adbhid[i] && !(exist&(1<<i)))
adbhid_input_unregister(i);
if (adbhid[i] && !(exist&(1<<i)))
adbhid_input_unregister(i);
}
static void
adbhid_probe(void)
{
......@@ -631,14 +662,16 @@ adbhid_probe(void)
printk("ADB keyboard at %d, handler 1\n", id);
adb_get_infos(id, &default_id, &cur_handler_id);
reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, 0);
reg |= adbhid_input_reregister(id, default_id, org_handler_id,
cur_handler_id, 0);
}
for (i = 0; i < buttons_ids.nids; i++) {
int id = buttons_ids.id[i];
adb_get_infos(id, &default_id, &org_handler_id);
reg |= adbhid_input_reregister(id, default_id, org_handler_id, org_handler_id, 0);
reg |= adbhid_input_reregister(id, default_id, org_handler_id,
org_handler_id, 0);
}
/* Try to switch all mice to handler 4, or 2 for three-button
......@@ -728,8 +761,8 @@ adbhid_probe(void)
adb_get_infos(id, &default_id, &cur_handler_id);
reg |= adbhid_input_reregister(id, default_id, org_handler_id,
cur_handler_id, mouse_kind);
}
cur_handler_id, mouse_kind);
}
adbhid_input_devcleanup(reg);
}
......@@ -742,7 +775,7 @@ init_trackpad(int id)
printk(" (trackpad)");
adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
ADB_READREG(id,1));
ADB_READREG(id,1));
if (req.reply_len < 8)
printk("bad length for reg. 1\n");
else
......@@ -782,7 +815,7 @@ init_trackpad(int id)
0x03, /*r1_buffer[6],*/
r1_buffer[7]);
/* Without this flush, the trackpad may be locked up */
/* Without this flush, the trackpad may be locked up */
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
}
}
......
......@@ -5,8 +5,6 @@
*
* Copyright (C) 2000 Franz Sirl.
*
* Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all
* major distributions are using the Linux keycodes.
* Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
*/
......@@ -17,184 +15,6 @@
#include <linux/input.h>
#include <linux/module.h>
#ifdef CONFIG_MAC_ADBKEYCODES
#include <linux/keyboard.h>
#include <asm/keyboard.h>
#include <asm/machdep.h>
#endif
#ifdef CONFIG_MAC_ADBKEYCODES
/* Simple translation table for the SysRq keys */
#ifdef CONFIG_MAGIC_SYSRQ
unsigned char mac_hid_kbd_sysrq_xlate[128] =
"asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
"yt123465=97-80o]" /* 0x10 - 0x1f */
"u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
/* 0x30 - 0x3f */
"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
/* 0x40 - 0x4f */
"\000\0000123456789\000\000\000" /* 0x50 - 0x5f */
"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
/* 0x60 - 0x6f */
extern unsigned char pckbd_sysrq_xlate[128];
#endif
static u_short macplain_map[NR_KEYS] = {
0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static u_short macshift_map[NR_KEYS] = {
0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static u_short macaltgr_map[NR_KEYS] = {
0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static u_short macctrl_map[NR_KEYS] = {
0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static u_short macshift_ctrl_map[NR_KEYS] = {
0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c,
};
static u_short macalt_map[NR_KEYS] = {
0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static u_short macctrl_alt_map[NR_KEYS] = {
0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
};
static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = {
macplain_map, macshift_map, macaltgr_map, 0,
macctrl_map, macshift_ctrl_map, 0, 0,
macalt_map, 0, 0, 0,
macctrl_alt_map, 0
};
static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS];
int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
char raw_mode);
static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
char mac_hid_kbd_unexpected_up(unsigned char keycode);
static int keyboard_lock_keycodes = 0;
int keyboard_sends_linux_keycodes = 0;
#else
int keyboard_sends_linux_keycodes = 1;
#endif
static unsigned char e0_keys[128] = {
0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */
......@@ -225,25 +45,10 @@ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
static int mouse_last_keycode = 0;
#endif
extern void pckbd_init_hw(void);
#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
/* file(s) in /proc/sys/dev/mac_hid */
ctl_table mac_hid_files[] =
{
#ifdef CONFIG_MAC_ADBKEYCODES
{
DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
"keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
0644, NULL, &mac_hid_sysctl_keycodes
},
{
DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
"keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
0644, NULL, &proc_dointvec
},
#endif
#ifdef CONFIG_MAC_EMUMOUSEBTN
{
DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
"mouse_button_emulation", &mouse_emulate_buttons, sizeof(int),
......@@ -259,7 +64,6 @@ ctl_table mac_hid_files[] =
"mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
0644, NULL, &proc_dointvec
},
#endif
{ 0 }
};
......@@ -279,148 +83,72 @@ ctl_table mac_hid_root_dir[] =
static struct ctl_table_header *mac_hid_sysctl_header;
#ifdef CONFIG_MAC_ADBKEYCODES
static
int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp)
{
int val = keyboard_sends_linux_keycodes;
int ret = 0;
if (!write
|| (write && !keyboard_lock_keycodes))
ret = proc_dointvec(ctl, write, filp, buffer, lenp);
if (write
&& keyboard_sends_linux_keycodes != val) {
if (!keyboard_sends_linux_keycodes) {
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
SYSRQ_KEY = 0x69;
#endif
memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
} else {
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
memcpy(key_maps, pc_key_maps_save, sizeof(key_maps));
}
}
return ret;
}
#endif
#endif /* endif CONFIG_SYSCTL */
int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode)
{
#ifdef CONFIG_MAC_ADBKEYCODES
if (!keyboard_sends_linux_keycodes) {
if (!raw_mode) {
/*
* Convert R-shift/control/option to L version.
*/
switch (scancode) {
case 0x7b: scancode = 0x38; break; /* R-shift */
case 0x7c: scancode = 0x3a; break; /* R-option */
case 0x7d: scancode = 0x36; break; /* R-control */
}
}
*keycode = scancode;
return 1;
} else
#endif
{
/* This code was copied from char/pc_keyb.c and will be
* superflous when the input layer is fully integrated.
* We don't need the high_keys handling, so this part
* has been removed.
*/
static int prev_scancode = 0;
/* special prefix scancodes.. */
if (scancode == 0xe0 || scancode == 0xe1) {
prev_scancode = scancode;
return 0;
}
/* This code was copied from char/pc_keyb.c and will be
* superflous when the input layer is fully integrated.
* We don't need the high_keys handling, so this part
* has been removed.
*/
static int prev_scancode = 0;
/* special prefix scancodes.. */
if (scancode == 0xe0 || scancode == 0xe1) {
prev_scancode = scancode;
return 0;
}
scancode &= 0x7f;
scancode &= 0x7f;
if (prev_scancode) {
if (prev_scancode != 0xe0) {
if (prev_scancode == 0xe1 && scancode == 0x1d) {
prev_scancode = 0x100;
return 0;
} else if (prev_scancode == 0x100 && scancode == 0x45) {
*keycode = KEY_PAUSE;
prev_scancode = 0;
} else {
if (!raw_mode)
printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
prev_scancode = 0;
return 0;
}
} else {
if (prev_scancode) {
if (prev_scancode != 0xe0) {
if (prev_scancode == 0xe1 && scancode == 0x1d) {
prev_scancode = 0x100;
return 0;
} else if (prev_scancode == 0x100 && scancode == 0x45) {
*keycode = KEY_PAUSE;
prev_scancode = 0;
if (scancode == 0x2a || scancode == 0x36)
return 0;
}
if (e0_keys[scancode])
*keycode = e0_keys[scancode];
else {
} else {
if (!raw_mode)
printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
scancode);
printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
prev_scancode = 0;
return 0;
}
} else {
switch (scancode) {
case 91: scancode = KEY_LINEFEED; break;
case 92: scancode = KEY_KPEQUAL; break;
case 125: scancode = KEY_INTL1; break;
}
*keycode = scancode;
prev_scancode = 0;
if (scancode == 0x2a || scancode == 0x36)
return 0;
}
return 1;
if (e0_keys[scancode])
*keycode = e0_keys[scancode];
else {
if (!raw_mode)
printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
scancode);
return 0;
}
} else {
switch (scancode) {
case 91: scancode = KEY_LINEFEED; break;
case 92: scancode = KEY_KPEQUAL; break;
case 125: scancode = KEY_INTL1; break;
}
*keycode = scancode;
}
return 1;
}
char mac_hid_kbd_unexpected_up(unsigned char keycode)
{
if (keyboard_sends_linux_keycodes && keycode == KEY_F13)
if (keycode == KEY_F13)
return 0;
else
return 0x80;
}
#ifdef CONFIG_MAC_ADBKEYCODES
int mac_hid_keyboard_sends_linux_keycodes(void)
{
return keyboard_sends_linux_keycodes;
}
EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes);
static int __init mac_hid_setup(char *str)
{
int ints[2];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] == 1) {
keyboard_sends_linux_keycodes = ints[1] != 0;
keyboard_lock_keycodes = 1;
}
return 1;
}
__setup("keyboard_sends_linux_keycodes=", mac_hid_setup);
#endif
#ifdef CONFIG_MAC_EMUMOUSEBTN
int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
{
......@@ -439,15 +167,6 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
mouse_last_keycode = down ? keycode : 0;
}
break;
case 2:
/* Called from mousedev.c */
if (mouse_emulate_buttons == 2 && keycode == 0) {
if (mouse_last_keycode == mouse_button2_keycode)
return 1; /* map to middle button */
if (mouse_last_keycode == mouse_button3_keycode)
return 2; /* map to right button */
}
return keycode; /* keep button */
}
return 0;
}
......@@ -469,40 +188,22 @@ static void emumousebtn_input_register(void)
input_register_device(&emumousebtn);
printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number);
printk(KERN_INFO "input: Macintosh mouse button emulation\n");
}
#endif
void __init mac_hid_init_hw(void)
int __init mac_hid_init(void)
{
#ifdef CONFIG_MAC_ADBKEYCODES
memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
if (!keyboard_sends_linux_keycodes) {
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
SYSRQ_KEY = 0x69;
#endif
memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
} else {
#ifdef CONFIG_MAGIC_SYSRQ
ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
SYSRQ_KEY = 0x54;
#endif
}
#endif /* CONFIG_MAC_ADBKEYCODES */
#ifdef CONFIG_MAC_EMUMOUSEBTN
emumousebtn_input_register();
#endif
#if CONFIG_PPC
if (_machine != _MACH_Pmac)
pckbd_init_hw();
#endif
#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
#if defined(CONFIG_SYSCTL) && defined(CONFIG_MAC_EMUMOUSEBTN)
mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
#endif /* CONFIG_SYSCTL */
return 0;
}
device_initcall(mac_hid_init);
......@@ -36,20 +36,22 @@
#define DISABLE_KBD_DURING_INTERRUPTS 0
#define INIT_KBD
extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode);
extern char pckbd_unexpected_up(unsigned char keycode);
extern unsigned char pckbd_sysrq_xlate[128];
static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
{
if ( ppc_md.kbd_setkeycode )
return ppc_md.kbd_setkeycode(scancode, keycode);
else
return 0;
return 0;
}
static inline int kbd_getkeycode(unsigned int scancode)
{
if ( ppc_md.kbd_getkeycode )
return ppc_md.kbd_getkeycode(scancode);
else
return 0;
return 0;
}
static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
......@@ -58,7 +60,7 @@ static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
if ( ppc_md.kbd_translate )
return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
else
return 0;
return pckbd_translate(keycode, keycodep, raw_mode);
}
static inline int kbd_unexpected_up(unsigned char keycode)
......@@ -66,22 +68,18 @@ static inline int kbd_unexpected_up(unsigned char keycode)
if ( ppc_md.kbd_unexpected_up )
return ppc_md.kbd_unexpected_up(keycode);
else
return 0;
return pckbd_unexpected_up(keycode);
}
static inline void kbd_leds(unsigned char leds)
{
if ( ppc_md.kbd_leds )
ppc_md.kbd_leds(leds);
}
static inline void kbd_init_hw(void)
{
if ( ppc_md.kbd_init_hw )
ppc_md.kbd_init_hw();
}
#define kbd_sysrq_xlate (ppc_md.ppc_kbd_sysrq_xlate)
#define kbd_sysrq_xlate pckbd_sysrq_xlate
extern unsigned long SYSRQ_KEY;
......
......@@ -57,16 +57,10 @@ struct machdep_calls {
void (*nvram_write_val)(int addr, unsigned char val);
/* Tons of keyboard stuff. */
int (*kbd_setkeycode)(unsigned int scancode,
unsigned int keycode);
int (*kbd_getkeycode)(unsigned int scancode);
int (*kbd_translate)(unsigned char scancode,
unsigned char *keycode,
char raw_mode);
char (*kbd_unexpected_up)(unsigned char keycode);
void (*kbd_leds)(unsigned char leds);
void (*kbd_init_hw)(void);
unsigned char *ppc_kbd_sysrq_xlate;
/*
* optional PCI "hooks"
......
......@@ -38,7 +38,6 @@ struct gameport {
void *driver; /* Private pointer for gameport drivers */
char *name;
char *phys;
int number;
unsigned short idbus;
unsigned short idvendor;
......
......@@ -399,6 +399,73 @@ struct input_event {
#define BTN_GEAR_DOWN 0x150
#define BTN_GEAR_UP 0x151
#define KEY_OK 0x160
#define KEY_SELECT 0x161
#define KEY_GOTO 0x162
#define KEY_CLEAR 0x163
#define KEY_POWER2 0x164
#define KEY_OPTION 0x165
#define KEY_INFO 0x166
#define KEY_TIME 0x167
#define KEY_VENDOR 0x168
#define KEY_ARCHIVE 0x169
#define KEY_PROGRAM 0x16a
#define KEY_CHANNEL 0x16b
#define KEY_FAVORITES 0x16c
#define KEY_EPG 0x16d
#define KEY_PVR 0x16e
#define KEY_MHP 0x16f
#define KEY_LANGUAGE 0x170
#define KEY_TITLE 0x171
#define KEY_SUBTITLE 0x172
#define KEY_ANGLE 0x173
#define KEY_ZOOM 0x174
#define KEY_MODE 0x175
#define KEY_KEYBOARD 0x176
#define KEY_SCREEN 0x177
#define KEY_PC 0x178
#define KEY_TV 0x179
#define KEY_TV2 0x17a
#define KEY_VCR 0x17b
#define KEY_VCR2 0x17c
#define KEY_SAT 0x17d
#define KEY_SAT2 0x17e
#define KEY_CD 0x17f
#define KEY_TAPE 0x180
#define KEY_RADIO 0x181
#define KEY_TUNER 0x182
#define KEY_PLAYER 0x183
#define KEY_TEXT 0x184
#define KEY_DVD 0x185
#define KEY_AUX 0x186
#define KEY_MP3 0x187
#define KEY_AUDIO 0x188
#define KEY_VIDEO 0x189
#define KEY_DIRECTORY 0x18a
#define KEY_LIST 0x18b
#define KEY_MEMO 0x18c
#define KEY_CALENDAR 0x18d
#define KEY_RED 0x18e
#define KEY_GREEN 0x18f
#define KEY_YELLOW 0x190
#define KEY_BLUE 0x191
#define KEY_CHANNELUP 0x192
#define KEY_CHANNELDOWN 0x193
#define KEY_FIRST 0x194
#define KEY_LAST 0x195
#define KEY_AB 0x196
#define KEY_PLAY 0x197
#define KEY_RESTART 0x198
#define KEY_SLOW 0x199
#define KEY_SHUFFLE 0x19a
#define KEY_FASTFORWARD 0x19b
#define KEY_PREVIOUS 0x19c
#define KEY_NEXT 0x19d
#define KEY_DIGITS 0x19e
#define KEY_TEEN 0x19f
#define KEY_TWEN 0x1a0
#define KEY_BREAK 0x1a1
#define KEY_MAX 0x1ff
/*
......@@ -507,6 +574,7 @@ struct input_event {
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
/*
* Values describing the status of an effect
......
......@@ -50,6 +50,7 @@ struct serio {
unsigned short idversion;
unsigned long type;
unsigned long event;
int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *);
......@@ -75,6 +76,7 @@ struct serio_dev {
int serio_open(struct serio *serio, struct serio_dev *dev);
void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio);
void serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);
void serio_register_port(struct serio *serio);
void serio_unregister_port(struct serio *serio);
......@@ -88,9 +90,8 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
static __inline__ void serio_dev_write_wakeup(struct serio *serio)
{
if (serio->dev && serio->dev->write_wakeup) {
if (serio->dev && serio->dev->write_wakeup)
serio->dev->write_wakeup(serio);
}
}
#define SERIO_TIMEOUT 1
......
#ifndef __UINPUT_H_
#define __UINPUT_H_
/*
* User level driver support for input subsystem
*
* Heavily based on evdev.c by Vojtech Pavlik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
* 0.1 20/06/2002
* - first public version
*/
#ifdef __KERNEL__
#define UINPUT_MINOR 223
#define UINPUT_NAME "uinput"
#define UINPUT_BUFFER_SIZE 16
#define U_MAX_NAME_SIZE 50
#define UIST_CREATED 1
struct uinput_device {
struct input_dev *dev;
unsigned long state;
wait_queue_head_t waitq;
unsigned char ready,
head,
tail;
struct input_event buff[UINPUT_BUFFER_SIZE];
};
#endif /* __KERNEL__ */
/* ioctl */
#define UINPUT_IOCTL_BASE 'U'
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
#ifndef NBITS
#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
#endif /* NBITS */
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
unsigned short idversion;
int ff_effects_max;
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
};
#endif /* __UINPUT_H_ */
......@@ -48,7 +48,7 @@ fi
if [ "$CONFIG_DDB5477" = "y" ]; then
dep_tristate ' NEC Vrc5477 AC97 sound' CONFIG_SOUND_VRC5477 $CONFIG_SOUND
fi
dep_tristate ' Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
dep_tristate ' Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
dep_tristate ' Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
......@@ -134,7 +134,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
dep_tristate ' Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS
dep_tristate ' MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND_OSS
dep_tristate ' NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
dep_tristate ' OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS
dep_tristate ' OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS $CONFIG_SOUND_GAMEPORT
if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then
bool ' Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD
fi
......
......@@ -23,11 +23,6 @@
*
*
* Module command line parameters:
* joystick if 1 enables the joystick interface on the card; but it still
* needs a driver for joysticks connected to a standard IBM-PC
* joyport. It is tested with the joy-analog driver. This
* module must be loaded before the joystick driver. Kmod will
* not ensure that.
* lineout if 1 the LINE jack is used as an output instead of an input.
* LINE then contains the unmixed dsp output. This can be used
* to make the card a four channel one: use dsp to output two
......@@ -2529,14 +2524,11 @@ static /*const*/ struct file_operations es1370_midi_fops = {
/* maximum number of devices; only used for command line params */
#define NR_DEVICE 5
static int joystick[NR_DEVICE] = { 0, };
static int lineout[NR_DEVICE] = { 0, };
static int micbias[NR_DEVICE] = { 0, };
static unsigned int devindex = 0;
MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)");
MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
MODULE_PARM(micbias, "1-" __MODULE_STRING(NR_DEVICE) "i");
......@@ -2617,13 +2609,11 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
* mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
s->gameport.io = 0;
if (joystick[devindex]) {
if (!request_region(0x200, JOY_EXTENT, "es1370"))
printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
else {
s->ctrl |= CTRL_JYSTK_EN;
s->gameport.io = 0x200;
}
if (!request_region(0x200, JOY_EXTENT, "es1370"))
printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
else {
s->ctrl |= CTRL_JYSTK_EN;
s->gameport.io = 0x200;
}
if (lineout[devindex])
s->ctrl |= CTRL_XCTL0;
......@@ -2765,7 +2755,7 @@ module_exit(cleanup_es1370);
#ifndef MODULE
/* format is: es1370=[joystick[,lineout[,micbias]]] */
/* format is: es1370=lineout[,micbias]] */
static int __init es1370_setup(char *str)
{
......@@ -2775,9 +2765,8 @@ static int __init es1370_setup(char *str)
return 0;
(void)
( (get_option(&str,&joystick[nr_dev]) == 2)
&& (get_option(&str,&lineout [nr_dev]) == 2)
&& get_option(&str,&micbias [nr_dev])
((get_option(&str,&lineout [nr_dev]) == 2)
&& get_option(&str,&micbias [nr_dev])
);
nr_dev++;
......
......@@ -21,12 +21,6 @@
*
* Special thanks to Ensoniq
*
*
* Module command line parameters:
* joystick must be set to the base I/O-Port to be used for
* the gameport. Legal values are 0x200, 0x208, 0x210 and 0x218.
* The gameport is mirrored eight times.
*
* Supported devices:
* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
......@@ -2744,20 +2738,17 @@ static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, in
/* maximum number of devices; only used for command line params */
#define NR_DEVICE 5
static int joystick[NR_DEVICE] = { 0, };
static int spdif[NR_DEVICE] = { 0, };
static int nomix[NR_DEVICE] = { 0, };
static int amplifier[NR_DEVICE] = { 0, };
static unsigned int devindex = 0;
static int amplifier = 0;
MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode");
MODULE_PARM(nomix, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output");
MODULE_PARM(amplifier, "i");
MODULE_PARM(amplifier, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(amplifier, "Set to 1 if the machine needs the amp control enabling (many laptops)");
MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
......@@ -2856,8 +2847,8 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
printk(KERN_ERR PFX "irq %u in use\n", s->irq);
goto err_irq;
}
printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n"
KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u joystick %#x\n",
s->rev, s->io, s->irq, s->gameport.io);
/* register devices */
if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1))<0))
goto err_dev1;
......@@ -2877,7 +2868,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* Check amplifier requirements */
if(amplifier)
if (amplifier[devindex])
s->ctrl |= CTRL_GPIO_OUT0;
else for(idx = 0; amplifier_needed[idx].svid != PCI_ANY_ID; idx++)
{
......@@ -2889,24 +2880,16 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
}
}
s->gameport.io = 0;
if ((joystick[devindex] & ~0x18) == 0x200) {
if (!request_region(joystick[devindex], JOY_EXTENT, "es1371"))
printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]);
else {
s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
s->gameport.io = joystick[devindex];
}
} else if (joystick[devindex] == 1) {
for (i = 0x218; i >= 0x200; i -= 0x08) {
if (request_region(i, JOY_EXTENT, "es1371")) {
s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
s->gameport.io = i;
break;
}
for (i = 0x218; i >= 0x200; i -= 0x08) {
if (request_region(i, JOY_EXTENT, "es1371")) {
s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
s->gameport.io = i;
break;
}
if (!s->gameport.io)
printk(KERN_ERR PFX "no free joystick address found\n");
}
if (!s->gameport.io)
printk(KERN_ERR PFX "no free joystick address found\n");
s->sctrl = 0;
cssr = 0;
s->spdif_volume = -1;
......@@ -2926,7 +2909,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* initialize the chips */
outl(s->ctrl, s->io+ES1371_REG_CONTROL);
outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
outl(0, s->io+ES1371_REG_LEGACY);
outl(LEGACY_JFAST, s->io+ES1371_REG_LEGACY);
pci_set_master(pcidev); /* enable bus mastering */
/* if we are a 5880 turn on the AC97 */
if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
......@@ -3070,7 +3053,7 @@ module_exit(cleanup_es1371);
#ifndef MODULE
/* format is: es1371=[joystick] */
/* format is: es1371=[spdif,[nomix,[amplifier]]] */
static int __init es1371_setup(char *str)
{
......@@ -3078,8 +3061,12 @@ static int __init es1371_setup(char *str)
if (nr_dev >= NR_DEVICE)
return 0;
if (get_option(&str, &joystick[nr_dev]) == 2)
(void)get_option(&str, &spdif[nr_dev]);
(void)
((get_option(&str, &spdif[nr_dev]) == 2)
&& (get_option(&str, &nomix[nr_dev]) == 2)
&& (get_option(&str, &amplifier[nr_dev])));
nr_dev++;
return 1;
}
......
......@@ -881,7 +881,7 @@ static int __initdata cdirq = 0;
static int __initdata cdport = 0x340;
static int __initdata cddma = -1;
static int __initdata opl4 = 0;
static int __initdata joystick = 0;
static int __initdata joystick = 1;
MODULE_PARM(mpu_io, "i");
MODULE_PARM(mpu_irq, "i");
......
......@@ -36,6 +36,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* History
* v0.14.9e
* January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport
* support to avoid resource conflict with pcigame.c
* v0.14.9d
* October 8 2001 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* use set_current_state, properly release resources on failure in
......@@ -171,6 +174,7 @@
#include <linux/bitops.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/gameport.h>
#if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC
#include <asm/hwrpb.h>
......@@ -180,7 +184,7 @@
#include <linux/pm.h>
#define DRIVER_VERSION "0.14.9d"
#define DRIVER_VERSION "0.14.9e"
/* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
......@@ -382,6 +386,9 @@ struct trident_card {
/* Added for hardware volume control */
int hwvolctl;
struct timer_list timer;
/* Game port support */
struct gameport gameport;
};
/* table to map from CHANNELMASK to channel attribute for SiS 7018 */
......@@ -3938,6 +3945,55 @@ static int __init trident_ac97_init(struct trident_card *card)
return num_ac97+1;
}
/* Gameport functions for the cards ADC gameport */
static unsigned char trident_game_read(struct gameport *gameport)
{
struct trident_card *card = gameport->driver;
return inb(TRID_REG(card, T4D_GAME_LEG));
}
static void trident_game_trigger(struct gameport *gameport)
{
struct trident_card *card = gameport->driver;
outb(0xff, TRID_REG(card, T4D_GAME_LEG));
}
static int trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
struct trident_card *card = gameport->driver;
int i;
*buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
for (i = 0; i < 4; i++) {
axes[i] = inw(TRID_REG(card, T4D_GAME_AXD) + i * sizeof(u16));
if (axes[i] == 0xffff) axes[i] = -1;
}
return 0;
}
static int trident_game_open(struct gameport *gameport, int mode)
{
struct trident_card *card = gameport->driver;
switch (mode) {
case GAMEPORT_MODE_COOKED:
outb(0x80, TRID_REG(card, T4D_GAME_CR));
wait_ms(20);
return 0;
case GAMEPORT_MODE_RAW:
outb(0x00, TRID_REG(card, T4D_GAME_CR));
return 0;
default:
return -1;
}
return 0;
}
/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
......@@ -3998,6 +4054,13 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
card->banks[BANK_B].addresses = &bank_b_addrs;
card->banks[BANK_B].bitmap = 0UL;
card->gameport.driver = card;
card->gameport.fuzz = 64;
card->gameport.read = trident_game_read;
card->gameport.trigger = trident_game_trigger;
card->gameport.cooked_read = trident_game_cooked_read;
card->gameport.open = trident_game_open;
init_MUTEX(&card->open_sem);
spin_lock_init(&card->lock);
init_timer(&card->timer);
......@@ -4131,6 +4194,10 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device
/* Enable Address Engine Interrupts */
trident_enable_loop_interrupts(card);
/* Register gameport */
gameport_register_port(&card->gameport);
out: return rc;
out_unregister_sound_dsp:
unregister_sound_dsp(card->dev_audio);
......@@ -4172,6 +4239,9 @@ static void __devexit trident_remove(struct pci_dev *pci_dev)
#endif
}
/* Unregister gameport */
gameport_unregister_port(&card->gameport);
/* Kill interrupts, and SP/DIF */
trident_disable_loop_interrupts(card);
......
......@@ -79,6 +79,8 @@
/* operational registers common to DX, NX, 7018 */
enum trident_op_registers {
T4D_GAME_CR = 0x30, T4D_GAME_LEG = 0x31,
T4D_GAME_AXD = 0x34,
T4D_REC_CH = 0x70,
T4D_START_A = 0x80, T4D_STOP_A = 0x84,
T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c,
......@@ -333,7 +335,7 @@ enum miscint_bits {
#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
extern __inline__ unsigned ld2(unsigned int x)
static inline unsigned ld2(unsigned int x)
{
unsigned r = 0;
......
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