OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [obmouse.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* obmouse.c -- HP omnibook 600C/CT pop-up mouse driver
2
 *
3
 *  Copyright (C) 1999 Olivier Florent
4
 *  Copyright (C) 1999 Chuck Slivkoff <chuck_slivkoff_AT_hp.com>
5
 *  Copyright (C) 1999-2004 Grant Grundler <grundler_at_parisc-linux.org>
6
 *
7
 * OB600C/CT mouse can be compared to a tablet, as absolute coordinates
8
 * are given by the hardware.  This driver emulates a basic serial mouse
9
 * protocol by translating absolute coordinates to relative moves.
10
 * This works with gpm -t pnp and Xfree86 as a standard Micro$oft mouse.
11
 *
12
 * FIXME:  This driver lacks a detection routine.
13
 *         i.e you must know that you have a 600C/CT before using it.
14
 *
15
 *
16
 *  This program is free software; you can redistribute it and/or modify
17
 *  it under the terms of the GNU General Public License as published by
18
 *  the Free Software Foundation; either version 2 of the License, or
19
 *  (at your option) any later version.
20
 *
21
 *  This program is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  You should have received a copy of the GNU General Public License
27
 *  along with this program; if not, write to the Free Software
28
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 *
30
 *
31
 * 0.7  January 2004      grant
32
 *      convert to /dev/input
33
 *
34
 * 0.6  2 January 2004      grant
35
 *      converted to busmouse
36
 *
37
 * 0.5  27 december 2003    grant
38
 *      fix "built-in" code - added module_* calls
39
 *
40
 * 0.4  27 december 2002 grant grundler
41
 *      Add MODULES_ stuff (author, license, etc)
42
 *      fix read to return 0 if no change.
43
 *
44
 * 0.3  26 november 1999 grant grundler
45
 *      removed ifdefs for EMULATE_SERIAL_MOUSE  and EMULATE_NCR_PEN.
46
 *      Only support "basic serial mouse protocol (gpm -t pnp)" which
47
 *      is also supported directly by Xfree.
48
 *
49
 *      Moved delta(x,y) calculations into ob_interrupt.
50
 *      If we only get interrupts when the mouse moves,
51
 *      then only need to update delta(x,y) then too.
52
 *
53
 * 0.2  22 november 1999, grant grundler
54
 *      "man 4 mouse" explains really well how PNP mouse works. Read it.
55
 *
56
 *      Fixed algorithm which generated delta(x,y) from current-last
57
 *      position reported. Now handles "roll-over" properly and
58
 *      speed scales _inversely_ (ie bigger number is slower).
59
 *      "speed" parameter can be set with "insmod obmouse speed=5" (default).
60
 *
61
 * 0.1a 16 november 1999, charles_slivkoff_at_hp.com
62
 *      File did not compile as received.
63
 *      Modified ob_write,ob_read parameters to match 2.2.x kernel.
64
 *      Added uaccess.h. Tried to fix ob_interrupt.
65
 *
66
 * 0.1  17 february 1999, olivier_florent_AT_hp.com
67
 *      original author.
68
 */
69
 
70
#include <linux/module.h>
71
 
72
#include <linux/errno.h>
73
#include <linux/kmod.h>
74
#include <linux/input.h>
75
#include <linux/kernel.h>
76
#include <linux/ioport.h>
77
 
78
#include <asm/io.h>
79
#include <asm/irq.h>
80
 
81
#undef OBMOUSE_DEBUG            /* define to enable lots of printf */
82
 
83
#define OBMOUSE_NAME     "HP omnibook 600C/CT pop-up mouse"
84
#define OBMOUSE_DEV_NAME "obmouse"
85
#define OBMOUSE_VERSION  "v0.7"
86
 
87
 
88
/*
89
** "speed" of the mouse. Determines how "fast" the mouse "moves".
90
** Similar (but not the same) as acceleration. Using slower acceleration
91
** together with lower speed value might result in better mouse control.
92
** I've only used the default acceleration.
93
*/
94
int speed = 4;  /* my personal preference */
95
 
96
/*
97
** OB 600 mouse doesn't completely act like a tablet.
98
** The xy-coordinates do in fact roll over which would
99
** not happen on a tablet.
100
*/
101
#define OB_ROLL_LIMIT 0xd00
102
 
103
/*
104
** obmouse HW specific data
105
*/
106
#define OBMOUSE_BASE           (0x238)  /* base address of the hardware */
107
#define OBMOUSE_EXTENT         (3)      /* from 0x238 to 0x23b          */
108
#define OBMOUSE_IRQ            (12)     /* irq 12                       */
109
 
110
/* The 4 high bits of OBMOUSE_INTR_CTL */
111
#define OBMOUSE_BTN_IRQ_MASK   (0x10)    /* WR: enable/disable button irq   */
112
#define OBMOUSE_MOV_IRQ_MASK   (0x20)    /* WR: enable/disable movement irq */
113
#define OBMOUSE_BUTTON1_MASK   (0x40)    /* RD: status of button 1 */
114
#define OBMOUSE_BUTTON2_MASK   (0x80)    /* RD: status of button 2 */
115
 
116
#define OBMOUSE_COORD_ONLY(v)  ((v) & 0xfff)  /* ignore high 4 bits */
117
 
118
#define OBMOUSE_INTR_CTL   (OBMOUSE_BASE+3)
119
#define OBMOUSE_INTR_BITS  (OBMOUSE_BTN_IRQ_MASK | OBMOUSE_MOV_IRQ_MASK)
120
 
121
/* Enable/disable both button and movement interrupt */
122
#define OBMOUSE_ENABLE_INTR()  outb(OBMOUSE_INTR_BITS,  OBMOUSE_INTR_CTL)
123
#define OBMOUSE_DISABLE_INTR() outb(~OBMOUSE_INTR_BITS, OBMOUSE_INTR_CTL)
124
 
125
/* Amount mouse has to move before the hardware launchs a new
126
** interrupt (I think). 0x08 is the standard value.
127
** Write value to OBMOUSE_BASE each time an interrupt is handled to
128
** enable the next one.
129
*/
130
#define OBMOUSE_SENSITIVITY    (0x08)
131
 
132
/* reset the sensitivity to enable next interrupt */
133
#define OBMOUSE_ENABLE_SENSE() outb(OBMOUSE_SENSITIVITY,OBMOUSE_BASE) 
134
#define OBMOUSE_DISABLE_SENSE() outb(0,OBMOUSE_BASE) 
135
 
136
 
137
static unsigned short lastx;    /* last reported normalized coords */
138
static unsigned short lasty;
139
static unsigned char ob_opened = 0; /* 0=closed, 1=opened  */
140
static struct input_dev obdev;
141
 
142
 
143
/*
144
** Omnibook 600 mouse ISR.
145
** Read the HW state and resets "SENSITIVITY" in order to re-arm
146
** the interrupt.
147
*/
148
static void
149
ob_interrupt(int irq, void *dev_id, struct pt_regs *regs)
150
{
151
        short dx, dy;
152
        unsigned short rawx, rawy;
153
 
154
        rawx = inb(OBMOUSE_BASE+0) + (inb(OBMOUSE_BASE+1) << 8);
155
        rawy = inb(OBMOUSE_BASE+2) + (inb(OBMOUSE_BASE+3) << 8);
156
 
157
#ifdef OBMOUSE_DEBUG
158
/* This printk is really useful for learning how the mouse actually behaves. */
159
printk("ob_intr: %4x,%4x\n", rawx, rawy);
160
#endif
161
 
162
        /* reset the sensitivity */
163
        OBMOUSE_ENABLE_SENSE();
164
 
165
        /* ------------------------------------
166
        **  update delta(x,y) values.
167
        ** ------------------------------------
168
        */
169
        dx = (short) rawx - (short) lastx ;
170
        lastx = rawx;
171
 
172
        {
173
                register unsigned short coordY = OBMOUSE_COORD_ONLY(rawy);
174
                dy = (short) coordY - (short) lasty ;
175
                lasty = coordY;
176
        }
177
 
178
        /*
179
        ** determine if the reading "rolled" over.
180
        ** Not fool-proof but should be good enough.
181
        */
182
        if (dx > OB_ROLL_LIMIT) {
183
                /* 0xf80 - 0x80 = 0xf00 (and we want 0x100) */
184
                dx = 0x1000 - dx;
185
        } else if (-dx > OB_ROLL_LIMIT) {
186
                /*
187
                ** 0x80 - 0xf80 = -0xf00 (and we want -0x100)
188
                ** -0x1000 - (-0xf00) = -0x1000 + 0xf00 = -0x100
189
                */
190
                dx = -0x1000 - dx;
191
        }
192
 
193
        /* Same story with the Y-coordinate */
194
        if      ( dy > OB_ROLL_LIMIT)  dy =  0x1000 - dy;
195
        else if (-dy > OB_ROLL_LIMIT)  dy = -0x1000 - dy;
196
 
197
        dx /= speed;    /* scale */
198
        dy /= speed;
199
 
200
        rawy = ~rawy;   /* invert mouse buttons */
201
        input_report_key(&obdev, BTN_LEFT, (rawy & 0x8000));
202
        input_report_key(&obdev, BTN_RIGHT, (rawy & 0x4000));
203
 
204
        /* obmouse acts like a table *EXCEPT* for the "roll-over". */
205
        if (dx) input_report_rel(&obdev, REL_X, -dx);
206
        if (dy) input_report_rel(&obdev, REL_Y, dy);
207
}
208
 
209
 
210
static int ob_open(struct input_dev *dev)
211
{
212
        /* device is already opened */
213
        if (ob_opened)
214
                return -EBUSY;
215
 
216
#ifdef OBMOUSE_DEBUG
217
printk(OBMOUSE_DEV_NAME ": attempt request irq %d\n",OBMOUSE_IRQ);
218
#endif
219
 
220
        /* Try to get the interrupt */
221
        if (request_irq(OBMOUSE_IRQ,ob_interrupt,0,OBMOUSE_DEV_NAME,NULL)) {
222
                printk (OBMOUSE_DEV_NAME ": request_irq failed for %d\n",OBMOUSE_IRQ);
223
                return -EBUSY;
224
        }
225
 
226
#ifdef OBMOUSE_DEBUG
227
printk(OBMOUSE_DEV_NAME ": irq %d registered\n",OBMOUSE_IRQ);
228
#endif
229
 
230
        OBMOUSE_ENABLE_INTR() ;
231
        OBMOUSE_ENABLE_SENSE() ;
232
 
233
        MOD_INC_USE_COUNT;
234
        ob_opened = 1 ;
235
        return 0;
236
}
237
 
238
 
239
void ob_close(struct input_dev *dev)
240
{
241
        /* device has never been opened */
242
        if (!ob_opened)
243
                return;
244
 
245
        OBMOUSE_DISABLE_INTR() ;
246
        free_irq(OBMOUSE_IRQ, NULL);
247
 
248
        MOD_DEC_USE_COUNT;
249
        ob_opened = 0 ;
250
}
251
 
252
 
253
#ifndef MODULE
254
static int __init obmouse_setup(char *str)
255
{
256
        int ints[4];
257
 
258
        str = get_options(str, ARRAY_SIZE(ints), ints);
259
        if (ints[0] > 0)
260
                speed=ints[1];
261
 
262
        return 1;
263
}
264
 
265
__setup("speed=", obmouse_setup);
266
#endif /* !MODULE */
267
 
268
 
269
static int obmouse_init(void)
270
{
271
        /* Get the IO Port region first */
272
        if (request_region(OBMOUSE_BASE,OBMOUSE_EXTENT,OBMOUSE_DEV_NAME) < 0) {
273
                printk(KERN_ERR OBMOUSE_DEV_NAME ": IO Port 0x%d not available!\n", OBMOUSE_BASE);
274
                return -ENODEV;
275
 
276
        }
277
 
278
        OBMOUSE_DISABLE_INTR() ;
279
        OBMOUSE_DISABLE_SENSE() ;
280
 
281
        memset(&obdev, 0, sizeof(obdev));
282
 
283
        obdev.name = OBMOUSE_NAME " " OBMOUSE_VERSION;
284
        obdev.idbus = BUS_ISA;
285
        obdev.idvendor = 0x103c;        /* PCI_VENDOR_ID_HP */
286
        obdev.idproduct = 0x0001;
287
        obdev.idversion = 0x0100;
288
 
289
        obdev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
290
        obdev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
291
        obdev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
292
        obdev.open  = ob_open;
293
        obdev.close = ob_close;
294
 
295
        input_register_device(&obdev);
296
        printk( OBMOUSE_NAME " " OBMOUSE_VERSION
297
                " (0x%x, IRQ %d), Grant Grundler\n", OBMOUSE_BASE, OBMOUSE_IRQ);
298
 
299
        return 0;
300
}
301
 
302
static void obmouse_exit(void)
303
{
304
        OBMOUSE_DISABLE_INTR() ;
305
        OBMOUSE_DISABLE_SENSE() ;
306
 
307
        input_unregister_device(&obdev);
308
        release_region(OBMOUSE_BASE,OBMOUSE_EXTENT);
309
        printk(OBMOUSE_DEV_NAME ": closed\n");
310
}
311
 
312
module_init(obmouse_init);
313
module_exit(obmouse_exit);
314
 
315
EXPORT_NO_SYMBOLS;
316
 
317
MODULE_AUTHOR("Grant Grundler <grundler_at_parisc-linux.org>");
318
MODULE_DESCRIPTION(OBMOUSE_NAME);
319
MODULE_PARM(speed, "i");
320
MODULE_PARM_DESC(speed, "obmouse speed (not accel) control");
321
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.