home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2648 / lmouse.c next >
C/C++ Source or Header  |  1991-01-31  |  13KB  |  438 lines

  1. /* lmouse.c - Logitech Bus Mouse Device Driver for SysV/386 R3.2
  2. **
  3. ** Copyright (C) 1989,1991 by Mark W. Snitily
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. **
  12. ** 29-May-89  MWS  Initial code completed and debugged
  13. ** 31-Jan-91  MWS  Copyright notice added for general distribution
  14. **
  15. */
  16.  
  17. #define VPIX
  18.  
  19. #include "sys/param.h"
  20. #include "sys/types.h"
  21. #include "sys/sysmacros.h"
  22. #include "sys/dir.h"
  23. #include "sys/signal.h"
  24. #include "sys/user.h"
  25. #include "sys/errno.h"
  26.  
  27. /* Definitions for Logitech Mouse */
  28.  
  29. /* Base I/O addresses of mouse registers */
  30. #define DATA_REG      0x23c  /* Data          register (read  only) */
  31. #define SIGNATURE_REG 0x23d  /* Signature     register (read/write) */
  32. #define INTERRUPT_REG 0x23e  /* Interrupt     register (read  only) */
  33. #define CONTROL_REG   0x23e  /* Control       register (write only) */
  34. #define CONFIG_REG    0x23f  /* Configuration register (read/write) */
  35.  
  36. /* Definitions of bits in interrupt register. */
  37. #define IRQ5 0x01
  38. #define IRQ4 0x02
  39. #define IRQ3 0x04
  40. #define IRQ2 0x08
  41.  
  42. /* Definitions of bits in control register. */
  43. #define DINT 0x10  /* Disable Interrupts */
  44. #define SHL  0x20  /* Select Hi/Lo (0/1) nibble */
  45. #define SXY  0x40  /* Select X/Y (0/1) counter */
  46. #define HC   0x80  /* Hold Counters (latch counters on 0->1 edge) */
  47.  
  48. /* Magic number needed for configuration register. */
  49. #define CONFIG_BYTE 0x91
  50.  
  51. #define BUT3STAT        0x01
  52. #define BUT2STAT        0x02
  53. #define BUT1STAT        0x04
  54.  
  55. #define BUT3CHNG        0x08
  56. #define BUT2CHNG        0x10
  57. #define BUT1CHNG        0x20
  58. #define MOVEMENT        0x40
  59.  
  60. #define BUTSTATMASK     0x07
  61. #define BUTCHNGMASK     0x38
  62.  
  63. struct mouseinfo
  64. {       unsigned char status;
  65.     char xmotion, ymotion;
  66. };
  67.  
  68. /* Ioctl definitions */
  69. #define MOUSEIOC        ('M'<<8)
  70. #define MOUSEIOCREAD    (MOUSEIOC|60)
  71.  
  72. #ifdef VPIX
  73. #define VPC_MOUSE_READ  MOUSEIOCREAD
  74. #endif /* VPIX */
  75.  
  76. #ifdef VPIX
  77. #include "sys/immu.h"
  78. #include "sys/region.h"
  79. #include "sys/proc.h"
  80. #include "sys/tss.h"
  81. #include "sys/v86.h"
  82. #endif /* VPIX */
  83.  
  84. static char mousepresent;
  85. static char mouseinuse;
  86. static char mousemode;
  87. static char last_buttons;
  88. static char mousestatus;
  89. static int xmotion, ymotion;
  90. #ifdef VPIX
  91. static struct proc *ectproc;
  92. static char rupted;
  93. #endif /* VPIX */
  94.  
  95. #define UPPERLIM    127
  96. #define LOWERLIM   -128
  97. #define ONEBYTE(x) ((x)>UPPERLIM ? UPPERLIM : (x)<LOWERLIM ? LOWERLIM : (x))
  98.  
  99. /*---------------------------------------------------------------------------*/
  100. void logminit()
  101. {
  102.    unsigned char id1, id2, toggles, irq;
  103.    int i;
  104.  
  105.    /* Assume no mouse in system. */
  106.    mouseinuse = mousepresent = 0;
  107.  
  108.    /* Initialize configuration register with the required magic number. */
  109.    outb(CONFIG_REG, CONFIG_BYTE);
  110.  
  111.    /* See if we can store into the signature register.  If not return. */
  112.    outb(SIGNATURE_REG, 0xA5);
  113.    for (i=0; i<1000; i++); /* busy loop */
  114.    id1 = inb(SIGNATURE_REG);
  115.    if (id1 != 0xA5) {
  116.       printf("logminit: SIGNATURE_REG = 0x%x (should equal 0xA5)\n", id1);
  117.       printf("Logitech Bus Mouse not loaded.\n");
  118.       return;
  119.    }
  120.  
  121.    /* See which bits toggle in the interrupt register. */
  122.    outb(CONTROL_REG, 0); /* Make sure interrupts are enabled. */
  123.    id1 = inb(INTERRUPT_REG);
  124. #ifdef DEBUG
  125. printf("logminit:  Initial value of interrupt reg = 0x%x\n", id1);
  126. #endif /* DEBUG */
  127.    toggles = 0;
  128.    for (i=0; i<10000; i++) {
  129.       id2 = inb(INTERRUPT_REG);
  130.       toggles |= id1 ^ id2;
  131.       id1 = id2;
  132.    }
  133.    outb(CONTROL_REG, DINT); /* Disable interrupts just to be safe. */
  134.  
  135.    /* Based upon which bit(s) toggled, determine which IRQ is being used.
  136.       If nothing toggled, then something is wrong so don't set the
  137.       mousepresent flag. */
  138.    if      (toggles & IRQ5)  irq = 5;
  139.    else if (toggles & IRQ2)  irq = 2;
  140.    else if (toggles & IRQ3)  irq = 3;
  141.    else if (toggles & IRQ4)  irq = 4;
  142.    else {
  143.       printf("logminit: IRQ line did not respond (INTERRUPT_REG = 0x%x)\n",
  144.              toggles);
  145.       printf("Logitech Bus Mouse not loaded.\n");
  146.       return;
  147.    }
  148.    printf("Logitech Bus Mouse loaded with IRQ%d\n", irq);
  149.  
  150.    /* Set control register.  Set HC to 1:  A rising edge of HC transfers
  151.       the content of the counters into latches and resets the counters;
  152.       Disable interrupts; (also selects low nibble of the X counter.) */
  153.    outb(CONTROL_REG, HC | DINT);
  154.  
  155.    mousepresent = 1;
  156.  
  157. } /* logminit */
  158.  
  159. /*---------------------------------------------------------------------------*/
  160. void logmopen(dev, flag)
  161. int dev, flag;
  162. {
  163. #ifdef DEBUG
  164. printf("logmopen: dev = 0x%x, flag = 0x%x\n", dev, flag);
  165. #endif /* DEBUG */
  166.  
  167.    /* Insist on minor device 0 */
  168.    if (minor(dev))    { u.u_error = ENXIO;  return; }
  169.  
  170.    /* Make sure there is a mouse. */
  171.    if (!mousepresent) { u.u_error = ENXIO;  return; }
  172.  
  173.    /* Enforce exclusive use. */
  174.    if (mouseinuse)    { u.u_error = EBUSY;  return; }
  175.  
  176.    xmotion = ymotion = 0;
  177.    mousestatus = last_buttons = 0;
  178.  
  179. #ifdef VPIX
  180.    ectproc = u.u_procp;
  181.    rupted = 0;
  182. #endif /* VPIX */
  183.  
  184.    mouseinuse = 1;
  185.  
  186.    /* Set HC to 0 and enable interrupts. */
  187.    outb(CONTROL_REG, 0);
  188.  
  189. } /* logmopen */
  190.  
  191. /*---------------------------------------------------------------------------*/
  192. void logmclose(dev)
  193. int dev;
  194. {
  195. #ifdef DEBUG
  196. printf("logmclose\n");
  197. #endif /* DEBUG */
  198.  
  199.    /* Insist on minor device 0 */
  200.    if (minor(dev))    { u.u_error = ENXIO;  return; }
  201.  
  202.    /* Make sure there is a mouse. */
  203.    if (!mousepresent) { u.u_error = ENXIO;  return; }
  204.  
  205.    /* Make sure mouse has been opened. */
  206.    if (!mouseinuse)   { u.u_error = EACCES;  return; }
  207.  
  208.    /* Reset the mouse to make sure it does not interrupt. */
  209.    outb(CONTROL_REG, DINT);
  210.    mouseinuse = 0;
  211.  
  212. } /* logmclose */
  213.  
  214. /*---------------------------------------------------------------------------*/
  215. void logmioctl(dev, cmd, arg, flag)
  216. int dev, cmd, flag;
  217. caddr_t arg;
  218. {
  219.    struct mouseinfo info;
  220.    register int intmask;
  221.  
  222. #ifdef DEBUG
  223.    unsigned char ir;
  224.  
  225.    printf("logmioctl\n");
  226. #endif /* DEBUG */
  227.  
  228.    /* Insist on minor device 0 */
  229.    if (minor(dev))    { u.u_error = ENXIO;  return; }
  230.  
  231.    /* Make sure there is a mouse. */
  232.    if (!mousepresent) { u.u_error = ENXIO;  return; }
  233.  
  234.    /* Make sure mouse has been opened. */
  235.    if (!mouseinuse)   { u.u_error = EACCES;  return; }
  236.  
  237.    switch (cmd) {
  238. #ifdef DEBUG
  239.       case 0:
  240.          printf("logmioctl: outb(CONTROL_REG, 0                    )\n");
  241.          outb(CONTROL_REG, 0                    );
  242.          break;
  243.       case 1:
  244.          printf("logmioctl: outb(CONTROL_REG,                  DINT)\n");
  245.          outb(CONTROL_REG,                  DINT);
  246.          break;
  247.       case 2:
  248.          printf("logmioctl: outb(CONTROL_REG,            SHL       )\n");
  249.          outb(CONTROL_REG,            SHL       );
  250.          break;
  251.       case 3:
  252.          printf("logmioctl: outb(CONTROL_REG,            SHL | DINT)\n");
  253.          outb(CONTROL_REG,            SHL | DINT);
  254.          break;
  255.       case 4:
  256.          printf("logmioctl: outb(CONTROL_REG,      SXY             )\n");
  257.          outb(CONTROL_REG,      SXY             );
  258.          break;
  259.       case 5:
  260.          printf("logmioctl: outb(CONTROL_REG,      SXY |       DINT)\n");
  261.          outb(CONTROL_REG,      SXY |       DINT);
  262.          break;
  263.       case 6:
  264.          printf("logmioctl: outb(CONTROL_REG,      SXY | SHL       )\n");
  265.          outb(CONTROL_REG,      SXY | SHL       );
  266.          break;
  267.       case 7:
  268.          printf("logmioctl: outb(CONTROL_REG,      SXY | SHL | DINT)\n");
  269.          outb(CONTROL_REG,      SXY | SHL | DINT);
  270.          break;
  271.       case 8:
  272.          printf("logmioctl: outb(CONTROL_REG, HC                   )\n");
  273.          outb(CONTROL_REG, HC                   );
  274.          break;
  275.       case 9:
  276.          printf("logmioctl: outb(CONTROL_REG, HC |             DINT)\n");
  277.          outb(CONTROL_REG, HC |             DINT);
  278.          break;
  279.       case 10:
  280.          printf("logmioctl: outb(CONTROL_REG, HC |       SHL       )\n");
  281.          outb(CONTROL_REG, HC |       SHL       );
  282.          break;
  283.       case 11:
  284.          printf("logmioctl: outb(CONTROL_REG, HC |       SHL | DINT)\n");
  285.          outb(CONTROL_REG, HC |       SHL | DINT);
  286.          break;
  287.       case 12:
  288.          printf("logmioctl: outb(CONTROL_REG, HC | SXY             )\n");
  289.          outb(CONTROL_REG, HC | SXY             );
  290.          break;
  291.       case 13:
  292.          printf("logmioctl: outb(CONTROL_REG, HC | SXY |       DINT)\n");
  293.          outb(CONTROL_REG, HC | SXY |       DINT);
  294.          break;
  295.       case 14:
  296.          printf("logmioctl: outb(CONTROL_REG, HC | SXY | SHL       )\n");
  297.          outb(CONTROL_REG, HC | SXY | SHL       );
  298.          break;
  299.       case 15:
  300.          printf("logmioctl: outb(CONTROL_REG, HC | SXY | SHL | DINT)\n");
  301.          outb(CONTROL_REG, HC | SXY | SHL | DINT);
  302.          break;
  303.  
  304.       case 20:
  305.          ir = inb(DATA_REG);
  306.          printf("logmioctl: inb(DATA_REG) = 0x%x\n", ir);
  307.          break;
  308.       case 21:
  309.          ir = inb(SIGNATURE_REG);
  310.          printf("logmioctl: inb(SIGNATURE_REG) = 0x%x\n", ir);
  311.          break;
  312.       case 22:
  313.          ir = inb(INTERRUPT_REG);
  314.          printf("logmioctl: inb(INTERRUPT_REG) = 0x%x\n", ir);
  315.          break;
  316.       case 23:
  317.          ir = inb(CONFIG_REG);
  318.          printf("logmioctl: inb(CONFIG_REG) = 0x%x\n", ir);
  319.          break;
  320.       case 24:
  321.          outb(CONFIG_REG, CONFIG_BYTE);
  322.          printf("logmioctl: outb(CONFIG_REG, CONFIG_BYTE)\n");
  323.          break;
  324. #endif /* DEBUG */
  325.  
  326.       default:
  327.          /* Return error "Invalid argument". */
  328.          u.u_error = EINVAL;
  329. #ifdef DEBUG
  330.          printf("logmioctl: unknown cmd = 0x%x\n", cmd);
  331. #endif /* DEBUG */
  332.          break;
  333.  
  334.        case MOUSEIOCREAD:
  335.          /* Prevent mouse interrupts during update. */
  336.          intmask = splhi();
  337.  
  338.          /* Read and reset the accumulated interrupt info. */
  339.  
  340.          /* This emulates the microsoft bus mouse status return. */
  341.          info.status = mousestatus;
  342.          if (xmotion || ymotion) info.status |= MOVEMENT;
  343.  
  344.          info.xmotion = ONEBYTE(xmotion);
  345.          info.ymotion = ONEBYTE(ymotion);
  346.          xmotion = ymotion = 0;
  347.          mousestatus &= ~BUTCHNGMASK; /* clear "button changed" bits */
  348. #ifdef VPIX
  349.          rupted = 0;
  350. #endif /* VPIX */
  351.  
  352.          /* Resume mouse interrupts. */
  353.          splx(intmask);
  354.  
  355.          if (copyout(&info, arg, sizeof info)) u.u_error = EFAULT;
  356.          break;
  357.    } /* switch */
  358. } /* logmioctl */
  359.  
  360. /*---------------------------------------------------------------------------*/
  361. void logmintr(ivect)
  362. int ivect;
  363. {
  364.    unsigned char lo, hi, buttons, changed_buttons;
  365.    int dx, dy;
  366.  
  367.    /* Ignore if mouse is not present. */
  368.    if (!mousepresent) return;
  369.  
  370.    /* Print error on console if mouse has not been opened. */
  371.    if (!mouseinuse) {
  372. #ifdef DEBUG
  373.       printf("logmintr: Unsolicited INT %d\n", ivect);
  374. #endif /* DEBUG */
  375.       outb(CONTROL_REG, DINT); /* disable interrupts */
  376.       return;
  377.    }
  378.  
  379.    /* Read low X nibble. */
  380.    outb(CONTROL_REG, HC);
  381.    lo = inb(DATA_REG) & 0x0F;
  382.  
  383.    /* Read high X nibble. */
  384.    outb(CONTROL_REG, HC | SHL);
  385.    hi = inb(DATA_REG) & 0x0F;
  386.  
  387.    /* Combine high and low X nibbles. */
  388.    dx = (char) ((hi << 4) | lo);  /* force dx to be signed */
  389.  
  390.    /* Read low Y nibble. */
  391.    outb(CONTROL_REG, HC | SXY);
  392.    lo = inb(DATA_REG) & 0x0F;
  393.  
  394.    /* Read high Y nibble. */
  395.    outb(CONTROL_REG, HC | SXY | SHL);
  396.    hi = inb(DATA_REG);
  397.  
  398.    /* Extract and invert the button bits.
  399.       After inverting, a set bit means the button was pressed down. */
  400.    buttons = (~hi >> 5) & 0x07;
  401.    changed_buttons = buttons ^ last_buttons;
  402.    last_buttons = buttons;
  403.  
  404.    /* Combine high and low X nibbles. */
  405.    dy = (char) (((hi & 0x0F) << 4) | lo);  /* force dy to be signed */
  406.  
  407.    /* This code emulates the Microsoft bus mouse status (except for the MOTION
  408.       bit which is set in the ioctl routine).  State changes are or'ed over
  409.       any number of interrupts, but the buttons bits are always set to the
  410.       current state.  (The state changes are cleared when read in the ioctl
  411.       routine.) */
  412.    mousestatus = buttons | (mousestatus & ~BUTSTATMASK)
  413.                          | (changed_buttons << 3);
  414.  
  415.    /* Reset HC to 0. */
  416.    outb(CONTROL_REG, 0);
  417.  
  418.    /* If nothing has changed, nothing needs to be done, so return. */
  419.    if (!(dx || dy || changed_buttons)) return;
  420.  
  421.    /* Update global variables with info just read. */
  422.    xmotion += dx;
  423.    ymotion += dy;
  424. #ifdef DEBUG
  425.    printf("logmintr: dx = %d, dy = %d, buttons = %d\n", dx, dy, buttons);
  426. #endif /* DEBUG */
  427.  
  428. #ifdef VPIX
  429.    /* Send a pseudorupt if this is an ECT and the mouse has been read since
  430.       the last pseudorupt. */
  431.    if (ectproc && ectproc->p_v86 && !rupted) {
  432.       v86setint(ectproc->p_v86, V86VI_MOUSE);
  433.       rupted = 1;
  434.    }
  435. #endif /* VPIX */
  436.  
  437. } /* logmintr */
  438.