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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/drivers/char/busmouse.c
3
 *
4
 * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk>
5
 *  Protocol taken from original busmouse.c
6
 *  read() waiting taken from psaux.c
7
 *
8
 * Medium-level interface for quadrature or bus mice.
9
 */
10
 
11
#include <linux/module.h>
12
#include <linux/kernel.h>
13
#include <linux/sched.h>
14
#include <linux/signal.h>
15
#include <linux/slab.h>
16
#include <linux/errno.h>
17
#include <linux/mm.h>
18
#include <linux/poll.h>
19
#include <linux/miscdevice.h>
20
#include <linux/random.h>
21
#include <linux/init.h>
22
#include <linux/smp_lock.h>
23
 
24
#include <asm/uaccess.h>
25
#include <asm/system.h>
26
#include <asm/io.h>
27
 
28
#include "busmouse.h"
29
 
30
/* Uncomment this if your mouse drivers expect the kernel to
31
 * return with EAGAIN if the mouse does not have any events
32
 * available, even if the mouse is opened in blocking mode.
33
 * Please report use of this "feature" to the author using the
34
 * above address.
35
 */
36
/*#define BROKEN_MOUSE*/
37
 
38
struct busmouse_data {
39
        struct miscdevice       miscdev;
40
        struct busmouse         *ops;
41
        spinlock_t              lock;
42
 
43
        wait_queue_head_t       wait;
44
        struct fasync_struct    *fasyncptr;
45
        char                    active;
46
        char                    buttons;
47
        char                    ready;
48
        int                     dxpos;
49
        int                     dypos;
50
};
51
 
52
#define NR_MICE                 15
53
#define FIRST_MOUSE             0
54
#define DEV_TO_MOUSE(dev)       MINOR_TO_MOUSE(MINOR(dev))
55
#define MINOR_TO_MOUSE(minor)   ((minor) - FIRST_MOUSE)
56
 
57
/*
58
 *      List of mice and guarding semaphore. You must take the semaphore
59
 *      before you take the misc device semaphore if you need both
60
 */
61
 
62
static struct busmouse_data *busmouse_data[NR_MICE];
63
static DECLARE_MUTEX(mouse_sem);
64
 
65
/**
66
 *      busmouse_add_movement - notification of a change of mouse position
67
 *      @mousedev: mouse number
68
 *      @dx: delta X movement
69
 *      @dy: delta Y movement
70
 *      @buttons: new button state
71
 *
72
 *      Updates the mouse position and button information. The mousedev
73
 *      parameter is the value returned from register_busmouse. The
74
 *      movement information is updated, and the new button state is
75
 *      saved.  A waiting user thread is woken.
76
 */
77
 
78
void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
79
{
80
        struct busmouse_data *mse = busmouse_data[mousedev];
81
        int changed;
82
 
83
        spin_lock(&mse->lock);
84
        changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
85
 
86
        if (changed) {
87
                add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
88
 
89
                mse->buttons = buttons;
90
                mse->dxpos += dx;
91
                mse->dypos += dy;
92
                mse->ready = 1;
93
 
94
                /*
95
                 * keep dx/dy reasonable, but still able to track when X (or
96
                 * whatever) must page or is busy (i.e. long waits between
97
                 * reads)
98
                 */
99
                if (mse->dxpos < -2048)
100
                        mse->dxpos = -2048;
101
                if (mse->dxpos > 2048)
102
                        mse->dxpos = 2048;
103
                if (mse->dypos < -2048)
104
                        mse->dypos = -2048;
105
                if (mse->dypos > 2048)
106
                        mse->dypos = 2048;
107
        }
108
 
109
        spin_unlock(&mse->lock);
110
 
111
        if (changed) {
112
                wake_up(&mse->wait);
113
 
114
                kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);
115
        }
116
}
117
 
118
/**
119
 *      busmouse_add_movement - notification of a change of mouse position
120
 *      @mousedev: mouse number
121
 *      @dx: delta X movement
122
 *      @dy: delta Y movement
123
 *
124
 *      Updates the mouse position. The mousedev parameter is the value
125
 *      returned from register_busmouse. The movement information is
126
 *      updated, and a waiting user thread is woken.
127
 */
128
 
129
void busmouse_add_movement(int mousedev, int dx, int dy)
130
{
131
        struct busmouse_data *mse = busmouse_data[mousedev];
132
 
133
        busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
134
}
135
 
136
/**
137
 *      busmouse_add_buttons - notification of a change of button state
138
 *      @mousedev: mouse number
139
 *      @clear: mask of buttons to clear
140
 *      @eor: mask of buttons to change
141
 *
142
 *      Updates the button state. The mousedev parameter is the value
143
 *      returned from register_busmouse. The buttons are updated by:
144
 *              new_state = (old_state & ~clear) ^ eor
145
 *      A waiting user thread is woken up.
146
 */
147
 
148
void busmouse_add_buttons(int mousedev, int clear, int eor)
149
{
150
        struct busmouse_data *mse = busmouse_data[mousedev];
151
 
152
        busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
153
}
154
 
155
static int busmouse_fasync(int fd, struct file *filp, int on)
156
{
157
        struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
158
        int retval;
159
 
160
        retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
161
        if (retval < 0)
162
                return retval;
163
        return 0;
164
}
165
 
166
static int busmouse_release(struct inode *inode, struct file *file)
167
{
168
        struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
169
        int ret = 0;
170
 
171
        lock_kernel();
172
        busmouse_fasync(-1, file, 0);
173
 
174
        if (--mse->active == 0) {
175
                if (mse->ops->release)
176
                        ret = mse->ops->release(inode, file);
177
                if (mse->ops->owner)
178
                        __MOD_DEC_USE_COUNT(mse->ops->owner);
179
                mse->ready = 0;
180
        }
181
        unlock_kernel();
182
 
183
        return ret;
184
}
185
 
186
static int busmouse_open(struct inode *inode, struct file *file)
187
{
188
        struct busmouse_data *mse;
189
        unsigned int mousedev;
190
        int ret;
191
 
192
        mousedev = DEV_TO_MOUSE(inode->i_rdev);
193
        if (mousedev >= NR_MICE)
194
                return -EINVAL;
195
 
196
        down(&mouse_sem);
197
        mse = busmouse_data[mousedev];
198
        ret = -ENODEV;
199
        if (!mse || !mse->ops)  /* shouldn't happen, but... */
200
                goto end;
201
 
202
        if (mse->ops->owner && !try_inc_mod_count(mse->ops->owner))
203
                goto end;
204
 
205
        ret = 0;
206
        if (mse->ops->open) {
207
                ret = mse->ops->open(inode, file);
208
                if (ret && mse->ops->owner)
209
                        __MOD_DEC_USE_COUNT(mse->ops->owner);
210
        }
211
 
212
        if (ret)
213
                goto end;
214
 
215
        file->private_data = mse;
216
 
217
        if (mse->active++)
218
                goto end;
219
 
220
        spin_lock_irq(&mse->lock);
221
 
222
        mse->ready   = 0;
223
        mse->dxpos   = 0;
224
        mse->dypos   = 0;
225
        mse->buttons = mse->ops->init_button_state;
226
 
227
        spin_unlock_irq(&mse->lock);
228
end:
229
        up(&mouse_sem);
230
        return ret;
231
}
232
 
233
static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
234
{
235
        return -EINVAL;
236
}
237
 
238
static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
239
{
240
        struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
241
        DECLARE_WAITQUEUE(wait, current);
242
        int dxpos, dypos, buttons;
243
 
244
        if (count < 3)
245
                return -EINVAL;
246
 
247
        spin_lock_irq(&mse->lock);
248
 
249
        if (!mse->ready) {
250
#ifdef BROKEN_MOUSE
251
                spin_unlock_irq(&mse->lock);
252
                return -EAGAIN;
253
#else
254
                if (file->f_flags & O_NONBLOCK) {
255
                        spin_unlock_irq(&mse->lock);
256
                        return -EAGAIN;
257
                }
258
 
259
                add_wait_queue(&mse->wait, &wait);
260
repeat:
261
                set_current_state(TASK_INTERRUPTIBLE);
262
                if (!mse->ready && !signal_pending(current)) {
263
                        spin_unlock_irq(&mse->lock);
264
                        schedule();
265
                        spin_lock_irq(&mse->lock);
266
                        goto repeat;
267
                }
268
 
269
                current->state = TASK_RUNNING;
270
                remove_wait_queue(&mse->wait, &wait);
271
 
272
                if (signal_pending(current)) {
273
                        spin_unlock_irq(&mse->lock);
274
                        return -ERESTARTSYS;
275
                }
276
#endif
277
        }
278
 
279
        dxpos = mse->dxpos;
280
        dypos = mse->dypos;
281
        buttons = mse->buttons;
282
 
283
        if (dxpos < -127)
284
                dxpos =- 127;
285
        if (dxpos > 127)
286
                dxpos = 127;
287
        if (dypos < -127)
288
                dypos =- 127;
289
        if (dypos > 127)
290
                dypos = 127;
291
 
292
        mse->dxpos -= dxpos;
293
        mse->dypos -= dypos;
294
 
295
        /* This is something that many drivers have apparantly
296
         * forgotten...  If the X and Y positions still contain
297
         * information, we still have some info ready for the
298
         * user program...
299
         */
300
        mse->ready = mse->dxpos || mse->dypos;
301
 
302
        spin_unlock_irq(&mse->lock);
303
 
304
        /* Write out data to the user.  Format is:
305
         *   byte 0 - identifer (0x80) and (inverted) mouse buttons
306
         *   byte 1 - X delta position +/- 127
307
         *   byte 2 - Y delta position +/- 127
308
         */
309
        if (put_user((char)buttons | 128, buffer) ||
310
            put_user((char)dxpos, buffer + 1) ||
311
            put_user((char)dypos, buffer + 2))
312
                return -EFAULT;
313
 
314
        if (count > 3 && clear_user(buffer + 3, count - 3))
315
                return -EFAULT;
316
 
317
        file->f_dentry->d_inode->i_atime = CURRENT_TIME;
318
 
319
        return count;
320
}
321
 
322
/* No kernel lock held - fine */
323
static unsigned int busmouse_poll(struct file *file, poll_table *wait)
324
{
325
        struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
326
 
327
        poll_wait(file, &mse->wait, wait);
328
 
329
        if (mse->ready)
330
                return POLLIN | POLLRDNORM;
331
 
332
        return 0;
333
}
334
 
335
struct file_operations busmouse_fops=
336
{
337
        owner:          THIS_MODULE,
338
        read:           busmouse_read,
339
        write:          busmouse_write,
340
        poll:           busmouse_poll,
341
        open:           busmouse_open,
342
        release:        busmouse_release,
343
        fasync:         busmouse_fasync,
344
};
345
 
346
/**
347
 *      register_busmouse - register a bus mouse interface
348
 *      @ops: busmouse structure for the mouse
349
 *
350
 *      Registers a mouse with the driver. The return is mouse number on
351
 *      success and a negative errno code on an error. The passed ops
352
 *      structure most not be freed until the mouser is unregistered
353
 */
354
 
355
int register_busmouse(struct busmouse *ops)
356
{
357
        unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
358
        struct busmouse_data *mse;
359
        int ret;
360
 
361
        if (msedev >= NR_MICE) {
362
                printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
363
                       ops->minor);
364
                return -EINVAL;
365
        }
366
 
367
        mse = kmalloc(sizeof(*mse), GFP_KERNEL);
368
        if (!mse)
369
                return -ENOMEM;
370
 
371
        down(&mouse_sem);
372
        if (busmouse_data[msedev])
373
        {
374
                up(&mouse_sem);
375
                kfree(mse);
376
                return -EBUSY;
377
        }
378
 
379
        memset(mse, 0, sizeof(*mse));
380
 
381
        mse->miscdev.minor = ops->minor;
382
        mse->miscdev.name = ops->name;
383
        mse->miscdev.fops = &busmouse_fops;
384
        mse->ops = ops;
385
        mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
386
        init_waitqueue_head(&mse->wait);
387
 
388
        busmouse_data[msedev] = mse;
389
 
390
        ret = misc_register(&mse->miscdev);
391
        if (!ret)
392
                ret = msedev;
393
        up(&mouse_sem);
394
 
395
        return ret;
396
}
397
 
398
/**
399
 *      unregister_busmouse - unregister a bus mouse interface
400
 *      @mousedev: Mouse number to release
401
 *
402
 *      Unregister a previously installed mouse handler. The mousedev
403
 *      passed is the return code from a previous call to register_busmouse
404
 */
405
 
406
 
407
int unregister_busmouse(int mousedev)
408
{
409
        int err = -EINVAL;
410
 
411
        if (mousedev < 0)
412
                return 0;
413
        if (mousedev >= NR_MICE) {
414
                printk(KERN_ERR "busmouse: trying to free mouse on"
415
                       " mousedev %d\n", mousedev);
416
                return -EINVAL;
417
        }
418
 
419
        down(&mouse_sem);
420
 
421
        if (!busmouse_data[mousedev]) {
422
                printk(KERN_WARNING "busmouse: trying to free free mouse"
423
                       " on mousedev %d\n", mousedev);
424
                goto fail;
425
        }
426
 
427
        if (busmouse_data[mousedev]->active) {
428
                printk(KERN_ERR "busmouse: trying to free active mouse"
429
                       " on mousedev %d\n", mousedev);
430
                goto fail;
431
        }
432
 
433
        err = misc_deregister(&busmouse_data[mousedev]->miscdev);
434
 
435
        kfree(busmouse_data[mousedev]);
436
        busmouse_data[mousedev] = NULL;
437
fail:
438
        up(&mouse_sem);
439
        return err;
440
}
441
 
442
EXPORT_SYMBOL(busmouse_add_movementbuttons);
443
EXPORT_SYMBOL(busmouse_add_movement);
444
EXPORT_SYMBOL(busmouse_add_buttons);
445
EXPORT_SYMBOL(register_busmouse);
446
EXPORT_SYMBOL(unregister_busmouse);
447
 
448
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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