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. bus_mouse_init
  10. init_module
  11. 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  * Replaced dumb busy loop with udelay()  16 Nov 95
  31  *   Nathan Laredo <laredo@gnu.ai.mit.edu>
  32  *
  33  * Track I/O ports with request_region().  12 Dec 95 Philip Blundell 
  34  */
  35 
  36 #include <linux/module.h>
  37 
  38 #include <linux/kernel.h>
  39 #include <linux/sched.h>
  40 #include <linux/busmouse.h>
  41 #include <linux/signal.h>
  42 #include <linux/errno.h>
  43 #include <linux/mm.h>
  44 #include <linux/mouse.h>
  45 #include <linux/random.h>
  46 #include <linux/delay.h>
  47 #include <linux/ioport.h>
  48 
  49 #include <asm/io.h>
  50 #include <asm/segment.h>
  51 #include <asm/system.h>
  52 #include <asm/irq.h>
  53 
  54 static struct mouse_status mouse;
  55 static int mouse_irq = MOUSE_IRQ;
  56 
  57 void bmouse_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59         if (ints[0] > 0)
  60                 mouse_irq=ints[1];
  61 }
  62 
  63 static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         char dx, dy;
  66         unsigned char buttons;
  67 
  68         outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
  69         dx = (inb(MSE_DATA_PORT) & 0xf);
  70         outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
  71         dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
  72         outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
  73         dy = (inb(MSE_DATA_PORT) & 0xf);
  74         outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
  75         buttons = inb(MSE_DATA_PORT);
  76         dy |= (buttons & 0xf) << 4;
  77         buttons = ((buttons >> 5) & 0x07);
  78         if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
  79           add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
  80           mouse.buttons = buttons;
  81           mouse.dx += dx;
  82           mouse.dy -= dy;
  83           mouse.ready = 1;
  84           wake_up_interruptible(&mouse.wait);
  85 
  86           /*
  87            * keep dx/dy reasonable, but still able to track when X (or
  88            * whatever) must page or is busy (i.e. long waits between
  89            * reads)
  90            */
  91           if (mouse.dx < -2048)
  92               mouse.dx = -2048;
  93           if (mouse.dx >  2048)
  94               mouse.dx =  2048;
  95 
  96           if (mouse.dy < -2048)
  97               mouse.dy = -2048;
  98           if (mouse.dy >  2048)
  99               mouse.dy =  2048;
 100 
 101           if (mouse.fasyncptr)
 102               kill_fasync(mouse.fasyncptr, SIGIO);
 103         }
 104         MSE_INT_ON();
 105 }
 106 
 107 static int fasync_mouse(struct inode *inode, struct file *filp, int on)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109         int retval;
 110 
 111         retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
 112         if (retval < 0)
 113                 return retval;
 114         return 0;
 115 }
 116 
 117 /*
 118  * close access to the mouse
 119  */
 120 
 121 static void close_mouse(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         fasync_mouse(inode, file, 0);
 124         if (--mouse.active)
 125                 return;
 126         MSE_INT_OFF();
 127         free_irq(mouse_irq, NULL);
 128         MOD_DEC_USE_COUNT;
 129 }
 130 
 131 /*
 132  * open access to the mouse
 133  */
 134 
 135 static int open_mouse(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137         if (!mouse.present)
 138                 return -EINVAL;
 139         if (mouse.active++)
 140                 return 0;
 141         if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) {
 142                 mouse.active--;
 143                 return -EBUSY;
 144         }
 145         mouse.ready = 0;
 146         mouse.dx = 0;
 147         mouse.dy = 0;
 148         mouse.buttons = 0x87;
 149         MOD_INC_USE_COUNT;
 150         MSE_INT_ON();
 151         return 0;
 152 }
 153 
 154 /*
 155  * writes are disallowed
 156  */
 157 
 158 static int write_mouse(struct inode * inode, struct file * file, const char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         return -EINVAL;
 161 }
 162 
 163 /*
 164  * read mouse data.  Currently never blocks.
 165  */
 166 
 167 static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         int r;
 170         int dx;
 171         int dy;
 172         unsigned char buttons; 
 173         /* long flags; */
 174 
 175         if (count < 3)
 176                 return -EINVAL;
 177         if ((r = verify_area(VERIFY_WRITE, buffer, count)))
 178                 return r;
 179         if (!mouse.ready)
 180                 return -EAGAIN;
 181 
 182         /*
 183          * Obtain the current mouse parameters and limit as appropriate for
 184          * the return data format.  Interrupts are only disabled while 
 185          * obtaining the parameters, NOT during the puts_fs_byte() calls,
 186          * so paging in put_user() does not effect mouse tracking.
 187          */
 188 
 189         /* save_flags(flags); cli(); */
 190         disable_irq(mouse_irq);
 191         dx = mouse.dx;
 192         dy = mouse.dy;
 193         if (dx < -127)
 194             dx = -127;
 195         if (dx > 127)
 196             dx = 127;
 197         if (dy < -127)
 198             dy = -127;
 199         if (dy > 127)
 200             dy = 127;
 201         buttons = mouse.buttons;
 202         mouse.dx -= dx;
 203         mouse.dy -= dy;
 204         mouse.ready = 0;
 205         enable_irq(mouse_irq);
 206         /* restore_flags(flags); */
 207 
 208         put_user(buttons | 0x80, buffer);
 209         put_user((char)dx, buffer + 1);
 210         put_user((char)dy, buffer + 2);
 211         for (r = 3; r < count; r++)
 212             put_user(0x00, buffer + r);
 213         return r;
 214 }
 215 
 216 /*
 217  * select for mouse input
 218  */
 219 static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221         if (sel_type == SEL_IN) {
 222                 if (mouse.ready)
 223                         return 1;
 224                 select_wait(&mouse.wait, wait);
 225         }
 226         return 0;
 227 }
 228 
 229 struct file_operations bus_mouse_fops = {
 230         NULL,           /* mouse_seek */
 231         read_mouse,
 232         write_mouse,
 233         NULL,           /* mouse_readdir */
 234         mouse_select,   /* mouse_select */
 235         NULL,           /* mouse_ioctl */
 236         NULL,           /* mouse_mmap */
 237         open_mouse,
 238         close_mouse,
 239         NULL,
 240         fasync_mouse,
 241 };
 242 
 243 static struct mouse bus_mouse = {
 244         LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
 245 };
 246 
 247 int bus_mouse_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249         if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) {
 250           mouse.present = 0;
 251           return -EIO;
 252         }
 253 
 254         outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
 255         outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
 256         udelay(100L);   /* wait for reply from mouse */
 257         if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
 258                 mouse.present = 0;
 259                 return -EIO;
 260         }
 261         outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
 262         MSE_INT_OFF();
 263         
 264         request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
 265 
 266         mouse.present = 1;
 267         mouse.active = 0;
 268         mouse.ready = 0;
 269         mouse.buttons = 0x87;
 270         mouse.dx = 0;
 271         mouse.dy = 0;
 272         mouse.wait = NULL;
 273         printk("Logitech bus mouse detected, using IRQ %d.\n",
 274                mouse_irq);
 275         mouse_register(&bus_mouse);
 276         return 0;
 277 }
 278 
 279 #ifdef MODULE
 280 
 281 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         return bus_mouse_init();
 284 }
 285 
 286 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288         mouse_deregister(&bus_mouse);
 289         release_region(LOGIBM_BASE, LOGIBM_EXTENT);
 290 }
 291 #endif

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