M|.ykA<D /*
!0X"^VB * Copyright (c) 2000-2001 Vojtech Pavlik
yaI jXv *
=k!F`H`/%' * Based on the work of:
3[kl` *` * Alan Cox Robin O'Leary
)Z:maz */
J,`I>^G IPY[x| /*
&b19s=Z, * IBM PC110 touchpad driver for Linux
FlH=Pqc */
AX{yfL K}LF ${bS /*
7'{Y7]+z+ * This program is free software; you can redistribute it and/or modify
C*Y0GfW= * it under the terms of the GNU General Public License as published by
URyY^+s * the Free Software Foundation; either version 2 of the License, or
*^\u%Ir" * (at your option) any later version.
3-![%u *
_ [hVGCSB * This program is distributed in the hope that it will be useful,
uKT\\1Jrq * but WITHOUT ANY WARRANTY; without even the implied warranty of
0gKSjTqo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
evyA#~o * GNU General Public License for more details.
A6Wtzt2i *
#W L>ha
v * You should have received a copy of the GNU General Public License
KZ/2W9r_, * along with this program; if not, write to the Free Software
0 n)UvJ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
=vKSvQP@) *
5PKdMEK|q * Should you need to contact me, the author, you can do so either by
G^\.xk] * e-mail - mail your message to <
vojtech@ucw.cz>, or by paper mail:
oJ0
#U * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
? ,!C0t s */
YtT:\#D B o[aiT #include <linux/module.h>
:\#/T,K" #include <linux/kernel.h>
=I)Ex) #include <linux/errno.h>
Y}Nd2 #include <linux/ioport.h>
^0"[l { #include <linux/input.h>
I9jzR~T #include <linux/init.h>
1uc;:N G= #include <linux/interrupt.h>
@0%^\Qf2 #include <linux/pci.h>
kc"SUiy/ #include <linux/delay.h>
-$j|&l Io)@u~yz #include <asm/io.h>
M7AUY#) #include <asm/irq.h>
a#P{ [ fh}j)*K8 MODULE_AUTHOR("Vojtech Pavlik <
vojtech@ucw.cz>");
t=r*/DxX= MODULE_DESCRIPTION("IBM PC110 touchpad driver");
%R*-oQ1T MODULE_LICENSE("GPL");
+dK;\wT \;Q:a
/ur9 #define PC110PAD_OFF 0x30
=a./HCF #define PC110PAD_ON 0x38
:#spL*FIx :]IYw!_-p static int pc110pad_irq = 10;
pGSS
static int pc110pad_io = 0x15e0;
k*= #XbX ~YrO>H` B static struct input_dev *pc110pad_dev;
oyo
V1jO static int pc110pad_data[3];
#j${R={ static int pc110pad_count;
%>k$'UWzK Q>>II|~;J static irqreturn_t pc110pad_interrupt(int irq, void *ptr)
1bJrEXHXy {
|jyoT%SQ int value = inb_p(pc110pad_io);
Q|:qs\6q5 int handshake = inb_p(pc110pad_io + 2);
!5[5l!{x SH M@H93 outb(handshake | 1, pc110pad_io + 2);
R9lb<` udelay(2);
ioS(;2F outb(handshake & ~1, pc110pad_io + 2);
;_=+h,n udelay(2);
G>c:+`KS inb_p(0x64);
si3@R?WR6* .uu[MzMIu pc110pad_data[pc110pad_count++] = value;
G![JRJxQ 4BAG GD2 if (pc110pad_count < 3)
Q96^rjY return IRQ_HANDLED;
;R{ffS6 :B]yreg input_report_key(pc110pad_dev, BTN_TOUCH,
)Fh5*UC pc110pad_data[0] & 0x01);
E >lW' input_report_abs(pc110pad_dev, ABS_X,
B1Cu?k);. pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
*.F4?i2D input_report_abs(pc110pad_dev, ABS_Y,
ua>YI pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
M[7$cfp-Y~ input_sync(pc110pad_dev);
'?MT"G /#I~iYPe pc110pad_count = 0;
^26}j uQ return IRQ_HANDLED;
JE.s?k }
tEHgQto x 2Cp{+} static void pc110pad_close(struct input_dev *dev)
%T'<vw0 {
r:Rk!z* outb(PC110PAD_OFF, pc110pad_io + 2);
~zT7 43 }
2h5L#\H" <mX EX`? static int pc110pad_open(struct input_dev *dev)
g<$q#l~4xH {
R;EdYbiF b pc110pad_interrupt(0, NULL);
n(tx'&U"R pc110pad_interrupt(0, NULL);
bL]NSD pc110pad_interrupt(0, NULL);
X(*MHBd outb(PC110PAD_ON, pc110pad_io + 2);
6#DDMP8;I pc110pad_count = 0;
9S]]KEGn4 s'Wu \r' return 0;
%d"d<pvx }
r>ca17 r`GA5}M /*
7F @#6 * We try to avoid enabling the hardware if it's not
}*9mNE * there, but we don't know how to test. But we do know
5VR=D\j * that the PC110 is not a PCI system. So if we find any
qaZQ1<e * PCI devices in the machine, we don't have a PC110.
YecV+K'p: */
w=feXA3-S static int __init pc110pad_init(void)
&Y3r'" {
pW4$$2S?9 int err;
%29lDd(< aT"0tn^LO if (!no_pci_devices())
JOFQyhY0>m return -ENODEV;
?0J&U4 7/b\NLeJ' if (!request_region(pc110pad_io, 4, "pc110pad")) {
y0_z_S#gO printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n",
:ExCGS[ pc110pad_io, pc110pad_io + 4);
C
5
xsh return -EBUSY;
Jwt_d}ns }
G3_HX<|f* I )wc&>Lc outb(PC110PAD_OFF, pc110pad_io + 2);
^9fY%98 Vc*"Q8aZ~ if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) {
,zVS}!jRhy printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
S";c7s err = -EBUSY;
&ku.Q3xGs goto err_release_region;
f6k=ew }
d.Ep#4 bAS/cuZs pc110pad_dev = input_allocate_device();
wlsq[xP if (!pc110pad_dev) {
Ev>P|kV&A printk(KERN_ERR "pc110pad: Not enough memory.\n");
1 3K|=6si err = -ENOMEM;
3}kG ]# goto err_free_irq;
d`9ofw~3= }
X([p0W
9V( L~|_C Rw pc110pad_dev->name = "IBM PC110 TouchPad";
(j?ckah%V pc110pad_dev->phys = "isa15e0/input0";
oF L7dL pc110pad_dev->id.bustype = BUS_ISA;
DA_}pS" pc110pad_dev->id.vendor = 0x0003;
Ym|%ka pc110pad_dev->id.product = 0x0001;
GW,RE\Q: pc110pad_dev->id.version = 0x0100;
'@dk3:3t 9oQ$w?=#$ pc110pad_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
)0?u_Z]w9 pc110pad_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
Q4ZKgcC pc110pad_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
AjD?_DPc <%?!3 n* input_abs_set_max(pc110pad_dev, ABS_X, 0x1ff);
QERj`/g input_abs_set_max(pc110pad_dev, ABS_Y, 0x0ff);
;u;_\k<qK 9%Qlg4~<s pc110pad_dev->open = pc110pad_open;
:Lu 9w0>f pc110pad_dev->close = pc110pad_close;
F4PWL|1 V@o#" gZ err = input_register_device(pc110pad_dev);
~$d(@T& if (err)
COA*Q goto err_free_dev;
Ruv`yfQ N"8'=wB return 0;
_E2W%N #
11<=3Yj err_free_dev:
ek1<9"y input_free_device(pc110pad_dev);
RA1K$D ?A err_free_irq:
XwIKpr8 free_irq(pc110pad_irq, NULL);
|eI!wgQx err_release_region:
. ZP$, release_region(pc110pad_io, 4);
ZRj/lQ2D 0K4A0s_R` return err;
MO%+rf0~w }
9AJ"C7 Yk0/f|>O static void __exit pc110pad_exit(void)
#'dNSez5 {
q.VZ P outb(PC110PAD_OFF, pc110pad_io + 2);
aC94g7)` free_irq(pc110pad_irq, NULL);
[ J4n% input_unregister_device(pc110pad_dev);
@%jY release_region(pc110pad_io, 4);
>i"WKd= }
o .*t XtqhK"f% module_init(pc110pad_init);
+GncQs
y module_exit(pc110pad_exit);
=q}Z2 OoYh