home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / char / busmouse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-26  |  5.3 KB  |  240 lines

  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.  
  26. #include <linux/kernel.h>
  27. #include <linux/sched.h>
  28. #include <linux/busmouse.h>
  29. #include <linux/signal.h>
  30. #include <linux/errno.h>
  31.  
  32. #include <asm/io.h>
  33. #include <asm/segment.h>
  34. #include <asm/system.h>
  35. #include <asm/irq.h>
  36.  
  37. static struct mouse_status mouse;
  38. static int mouse_irq = MOUSE_IRQ;
  39.  
  40. void bmouse_setup(char *str, int *ints)
  41. {
  42.     if (ints[0] > 0)
  43.         mouse_irq=ints[1];
  44. }
  45.  
  46. static void mouse_interrupt(int unused)
  47. {
  48.     char dx, dy;
  49.     unsigned char buttons;
  50.  
  51.     MSE_INT_OFF();
  52.     outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
  53.     dx = (inb(MSE_DATA_PORT) & 0xf);
  54.     outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
  55.     dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
  56.     outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
  57.     dy = (inb(MSE_DATA_PORT) & 0xf);
  58.     outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
  59.     buttons = inb(MSE_DATA_PORT);
  60.     dy |= (buttons & 0xf) << 4;
  61.     buttons = ((buttons >> 5) & 0x07);
  62.     if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
  63.       mouse.buttons = buttons;
  64.       mouse.dx += dx;
  65.       mouse.dy -= dy;
  66.       mouse.ready = 1;
  67.       wake_up_interruptible(&mouse.wait);
  68.  
  69.       /*
  70.        * keep dx/dy reasonable, but still able to track when X (or
  71.        * whatever) must page or is busy (i.e. long waits between
  72.        * reads)
  73.        */
  74.       if (mouse.dx < -2048)
  75.           mouse.dx = -2048;
  76.       if (mouse.dx >  2048)
  77.           mouse.dx =  2048;
  78.  
  79.       if (mouse.dy < -2048)
  80.           mouse.dy = -2048;
  81.       if (mouse.dy >  2048)
  82.           mouse.dy =  2048;
  83.     }
  84.     MSE_INT_ON();
  85. }
  86.  
  87. /*
  88.  * close access to the mouse (can deal with multiple
  89.  * opens if allowed in the future)
  90.  */
  91.  
  92. static void close_mouse(struct inode * inode, struct file * file)
  93. {
  94.     if (--mouse.active == 0) {
  95.         MSE_INT_OFF();
  96.         free_irq(mouse_irq);
  97.     }
  98. }
  99.  
  100. /*
  101.  * open access to the mouse, currently only one open is
  102.  * allowed.
  103.  */
  104.  
  105. static int open_mouse(struct inode * inode, struct file * file)
  106. {
  107.     if (!mouse.present)
  108.         return -EINVAL;
  109.     if (mouse.active)
  110.         return -EBUSY;
  111.     mouse.ready = 0;
  112.     mouse.dx = 0;
  113.     mouse.dy = 0;
  114.     mouse.buttons = 0x87;
  115.     if (request_irq(mouse_irq, mouse_interrupt))
  116.         return -EBUSY;
  117.     mouse.active = 1;
  118.     MSE_INT_ON();
  119.     return 0;
  120. }
  121.  
  122. /*
  123.  * writes are disallowed
  124.  */
  125.  
  126. static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
  127. {
  128.     return -EINVAL;
  129. }
  130.  
  131. /*
  132.  * read mouse data.  Currently never blocks.
  133.  */
  134.  
  135. static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
  136. {
  137.     int r;
  138.     int dx;
  139.     int dy;
  140.     unsigned char buttons; 
  141.  
  142.     if (count < 3)
  143.         return -EINVAL;
  144.     if ((r = verify_area(VERIFY_WRITE, buffer, count)))
  145.         return r;
  146.     if (!mouse.ready)
  147.         return -EAGAIN;
  148.  
  149.     /*
  150.      * Obtain the current mouse parameters and limit as appropriate for
  151.      * the return data format.  Interrupts are only disabled while 
  152.      * obtaining the parameters, NOT during the puts_fs_byte() calls,
  153.      * so paging in put_fs_byte() does not effect mouse tracking.
  154.      */
  155.  
  156.     MSE_INT_OFF();
  157.     dx = mouse.dx;
  158.     dy = mouse.dy;
  159.     if (dx < -127)
  160.         dx = -127;
  161.     if (dx > 127)
  162.         dx = 127;
  163.     if (dy < -127)
  164.         dy = -127;
  165.     if (dy > 127)
  166.         dy = 127;
  167.     buttons = mouse.buttons;
  168.     mouse.dx -= dx;
  169.     mouse.dy -= dy;
  170.     mouse.ready = 0;
  171.     MSE_INT_ON();
  172.  
  173.     put_fs_byte(buttons | 0x80, buffer);
  174.     put_fs_byte((char)dx, buffer + 1);
  175.     put_fs_byte((char)dy, buffer + 2);
  176.     for (r = 3; r < count; r++)
  177.         put_fs_byte(0x00, buffer + r);
  178.     return r;
  179. }
  180.  
  181. /*
  182.  * select for mouse input, must disable the mouse interrupt while checking
  183.  * mouse.ready/select_wait() to avoid race condition (though in reality
  184.  * such a condition is not fatal to the proper operation of the mouse since
  185.  * multiple interrupts generally occur).
  186.  */
  187.  
  188. static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
  189. {
  190.     int r = 0;
  191.  
  192.     if (sel_type == SEL_IN) {
  193.         MSE_INT_OFF();
  194.         if (mouse.ready) {
  195.             r = 1;
  196.         } else {
  197.         select_wait(&mouse.wait, wait);
  198.         }
  199.         MSE_INT_ON();
  200.     }
  201.     return(r);
  202. }
  203.  
  204. struct file_operations bus_mouse_fops = {
  205.     NULL,        /* mouse_seek */
  206.     read_mouse,
  207.     write_mouse,
  208.     NULL,         /* mouse_readdir */
  209.     mouse_select,     /* mouse_select */
  210.     NULL,         /* mouse_ioctl */
  211.     NULL,        /* mouse_mmap */
  212.     open_mouse,
  213.     close_mouse,
  214. };
  215.  
  216. unsigned long bus_mouse_init(unsigned long kmem_start)
  217. {
  218.     int i;
  219.  
  220.     outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
  221.     outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
  222.     for (i = 0; i < 100000; i++)
  223.         /* busy loop */;
  224.     if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
  225.         mouse.present = 0;
  226.         return kmem_start;
  227.     }
  228.     outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
  229.     MSE_INT_OFF();
  230.     mouse.present = 1;
  231.     mouse.active = 0;
  232.     mouse.ready = 0;
  233.     mouse.buttons = 0x87;
  234.     mouse.dx = 0;
  235.     mouse.dy = 0;
  236.     mouse.wait = NULL;
  237.     printk("Logitech Bus mouse detected and installed.\n");
  238.     return kmem_start;
  239. }
  240.