root/drivers/char/busmouse.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bmouse_setup
  2. mouse_interrupt
  3. fasync_mouse
  4. close_mouse
  5. open_mouse
  6. write_mouse
  7. read_mouse
  8. mouse_select
  9. init_module
  10. cleanup_module

   1 /*
   2  * Logitech Bus Mouse Driver for Linux
   3  * by James Banks
   4  *
   5  * Mods by Matthew Dillon
   6  *   calls verify_area()
   7  *   tracks better when X is busy or paging
   8  *
   9  * Heavily modified by David Giller
  10  *   changed from queue- to counter- driven
  11  *   hacked out a (probably incorrect) mouse_select
  12  *
  13  * Modified again by Nathan Laredo to interface with
  14  *   0.96c-pl1 IRQ handling changes (13JUL92)
  15  *   didn't bother touching select code.
  16  *
  17  * Modified the select() code blindly to conform to the VFS
  18  *   requirements. 92.07.14 - Linus. Somebody should test it out.
  19  *
  20  * Modified by Johan Myreen to make room for other mice (9AUG92)
  21  *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
  22  *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
  23  *   renamed this file mouse.c => busmouse.c
  24  *
  25  * Minor addition by Cliff Matthews
  26  *   added fasync support
  27  *
  28  * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk> 
  29  */
  30 
  31 #ifdef MODULE
  32 #include <linux/module.h>
  33 #include <linux/version.h>
  34 #else
  35 #define MOD_INC_USE_COUNT
  36 #define MOD_DEC_USE_COUNT
  37 #endif
  38 
  39 #include <linux/kernel.h>
  40 #include <linux/sched.h>
  41 #include <linux/busmouse.h>
  42 #include <linux/signal.h>
  43 #include <linux/errno.h>
  44 #include <linux/mm.h>
  45 
  46 #include <asm/io.h>
  47 #include <asm/segment.h>
  48 #include <asm/system.h>
  49 #include <asm/irq.h>
  50 
  51 static struct mouse_status mouse;
  52 static int mouse_irq = MOUSE_IRQ;
  53 
  54 void bmouse_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         if (ints[0] > 0)
  57                 mouse_irq=ints[1];
  58 }
  59 
  60 static void mouse_interrupt(int irq, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         char dx, dy;
  63         unsigned char buttons;
  64 
  65         MSE_INT_OFF();
  66         outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
  67         dx = (inb(MSE_DATA_PORT) & 0xf);
  68         outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
  69         dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
  70         outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
  71         dy = (inb(MSE_DATA_PORT) & 0xf);
  72         outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
  73         buttons = inb(MSE_DATA_PORT);
  74         dy |= (buttons & 0xf) << 4;
  75         buttons = ((buttons >> 5) & 0x07);
  76         if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
  77           mouse.buttons = buttons;
  78           mouse.dx += dx;
  79           mouse.dy -= dy;
  80           mouse.ready = 1;
  81           wake_up_interruptible(&mouse.wait);
  82 
  83           /*
  84            * keep dx/dy reasonable, but still able to track when X (or
  85            * whatever) must page or is busy (i.e. long waits between
  86            * reads)
  87            */
  88           if (mouse.dx < -2048)
  89               mouse.dx = -2048;
  90           if (mouse.dx >  2048)
  91               mouse.dx =  2048;
  92 
  93           if (mouse.dy < -2048)
  94               mouse.dy = -2048;
  95           if (mouse.dy >  2048)
  96               mouse.dy =  2048;
  97 
  98           if (mouse.fasyncptr)
  99               kill_fasync(mouse.fasyncptr, SIGIO);
 100         }
 101         MSE_INT_ON();
 102 }
 103 
 104 static int fasync_mouse(struct inode *inode, struct file *filp, int on)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106         int retval;
 107 
 108         retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
 109         if (retval < 0)
 110                 return retval;
 111         return 0;
 112 }
 113 
 114 /*
 115  * close access to the mouse (can deal with multiple
 116  * opens if allowed in the future)
 117  */
 118 
 119 static void close_mouse(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         if (--mouse.active == 0) {
 122             MSE_INT_OFF();
 123             free_irq(mouse_irq);
 124         }
 125         fasync_mouse(inode, file, 0);
 126 }
 127 
 128 /*
 129  * open access to the mouse, currently only one open is
 130  * allowed.
 131  */
 132 
 133 static int open_mouse(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         if (!mouse.present)
 136                 return -EINVAL;
 137         if (mouse.active)
 138                 return -EBUSY;
 139         mouse.ready = 0;
 140         mouse.dx = 0;
 141         mouse.dy = 0;
 142         mouse.buttons = 0x87;
 143         if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse"))
 144                 return -EBUSY;
 145         mouse.active = 1;
 146         MSE_INT_ON();
 147         return 0;
 148 }
 149 
 150 /*
 151  * writes are disallowed
 152  */
 153 
 154 static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         return -EINVAL;
 157 }
 158 
 159 /*
 160  * read mouse data.  Currently never blocks.
 161  */
 162 
 163 static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         int r;
 166         int dx;
 167         int dy;
 168         unsigned char buttons; 
 169 
 170         if (count < 3)
 171                 return -EINVAL;
 172         if ((r = verify_area(VERIFY_WRITE, buffer, count)))
 173                 return r;
 174         if (!mouse.ready)
 175                 return -EAGAIN;
 176 
 177         /*
 178          * Obtain the current mouse parameters and limit as appropriate for
 179          * the return data format.  Interrupts are only disabled while 
 180          * obtaining the parameters, NOT during the puts_fs_byte() calls,
 181          * so paging in put_user() does not effect mouse tracking.
 182          */
 183 
 184         MSE_INT_OFF();
 185         dx = mouse.dx;
 186         dy = mouse.dy;
 187         if (dx < -127)
 188             dx = -127;
 189         if (dx > 127)
 190             dx = 127;
 191         if (dy < -127)
 192             dy = -127;
 193         if (dy > 127)
 194             dy = 127;
 195         buttons = mouse.buttons;
 196         mouse.dx -= dx;
 197         mouse.dy -= dy;
 198         mouse.ready = 0;
 199         MSE_INT_ON();
 200 
 201         put_user(buttons | 0x80, buffer);
 202         put_user((char)dx, buffer + 1);
 203         put_user((char)dy, buffer + 2);
 204         for (r = 3; r < count; r++)
 205             put_user(0x00, buffer + r);
 206         return r;
 207 }
 208 
 209 /*
 210  * select for mouse input, must disable the mouse interrupt while checking
 211  * mouse.ready/select_wait() to avoid race condition (though in reality
 212  * such a condition is not fatal to the proper operation of the mouse since
 213  * multiple interrupts generally occur).
 214  */
 215 
 216 static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218     int r = 0;
 219 
 220     if (sel_type == SEL_IN) {
 221         MSE_INT_OFF();
 222         if (mouse.ready) {
 223             r = 1;
 224         } else {
 225             select_wait(&mouse.wait, wait);
 226         }
 227         MSE_INT_ON();
 228     }
 229     return(r);
 230 }
 231 
 232 struct file_operations bus_mouse_fops = {
 233         NULL,           /* mouse_seek */
 234         read_mouse,
 235         write_mouse,
 236         NULL,           /* mouse_readdir */
 237         mouse_select,   /* mouse_select */
 238         NULL,           /* mouse_ioctl */
 239         NULL,           /* mouse_mmap */
 240         open_mouse,
 241         close_mouse,
 242         NULL,
 243         fasync_mouse,
 244 };
 245 
 246 static struct mouse bus_mous = {
 247         LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
 248 };
 249 
 250 #ifdef MODULE
 251 char kernel_version[] = UTS_RELEASE;
 252 
 253 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 #else
 255 unsigned long bus_mouse_init(unsigned long kmem_start)
 256 #endif
 257 {
 258         int i;
 259 
 260         outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
 261         outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
 262         for (i = 0; i < 100000; i++)
 263                 /* busy loop */;
 264         if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
 265                 mouse.present = 0;
 266 #ifdef MODULE
 267                 return -EIO;
 268 #else
 269                 return kmem_start;
 270 #endif
 271         }
 272         outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
 273         MSE_INT_OFF();
 274         mouse.present = 1;
 275         mouse.active = 0;
 276         mouse.ready = 0;
 277         mouse.buttons = 0x87;
 278         mouse.dx = 0;
 279         mouse.dy = 0;
 280         mouse.wait = NULL;
 281         printk("Logitech Bus mouse detected and installed with IRQ %d.\n",
 282                mouse_irq);
 283         mouse_register(&bus_mouse);
 284 #ifdef MODULE
 285         return 0;
 286 #else
 287         return kmem_start;
 288 #endif
 289 }
 290 
 291 #ifdef MODULE
 292 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294         if (MOD_IN_USE)
 295                 printk("busmouse: in use - remove delayed\n");
 296         mouse_deregister(&bus_mouse);
 297 }
 298 #endif

/* [previous][next][first][last][top][bottom][index][help] */