mms.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* $OpenBSD: mms.c,v 1.19 2007/04/10 22:37:17 miod Exp $ */
  2. /* $NetBSD: mms.c,v 1.35 2000/01/08 02:57:25 takemura Exp $ */
  3. /*-
  4. * Copyright (c) 1993, 1994 Charles M. Hannum.
  5. * Copyright (c) 1992, 1993 Erik Forsberg.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
  15. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  16. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  17. * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  21. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  22. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include <sys/param.h>
  26. #include <sys/systm.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/device.h>
  29. #include <machine/intr.h>
  30. #include <machine/bus.h>
  31. #include <dev/isa/isavar.h>
  32. #include <dev/wscons/wsconsio.h>
  33. #include <dev/wscons/wsmousevar.h>
  34. #define MMS_ADDR 0 /* offset for register select */
  35. #define MMS_DATA 1 /* offset for InPort data */
  36. #define MMS_IDENT 2 /* offset for identification register */
  37. #define MMS_NPORTS 4
  38. struct mms_softc { /* driver status information */
  39. struct device sc_dev;
  40. void *sc_ih;
  41. bus_space_tag_t sc_iot;
  42. bus_space_handle_t sc_ioh;
  43. int sc_enabled; /* device is open */
  44. struct device *sc_wsmousedev;
  45. };
  46. int mmsprobe(struct device *, void *, void *);
  47. void mmsattach(struct device *, struct device *, void *);
  48. int mmsintr(void *);
  49. struct cfattach mms_ca = {
  50. sizeof(struct mms_softc), mmsprobe, mmsattach
  51. };
  52. int mms_enable(void *);
  53. int mms_ioctl(void *, u_long, caddr_t, int, struct proc *);
  54. void mms_disable(void *);
  55. const struct wsmouse_accessops mms_accessops = {
  56. mms_enable,
  57. mms_ioctl,
  58. mms_disable,
  59. };
  60. int
  61. mmsprobe(struct device *parent, void *match, void *aux)
  62. {
  63. struct isa_attach_args *ia = aux;
  64. bus_space_tag_t iot = ia->ia_iot;
  65. bus_space_handle_t ioh;
  66. int rv;
  67. /* Disallow wildcarded i/o address. */
  68. if (ia->ia_iobase == IOBASEUNK)
  69. return 0;
  70. /* Map the i/o space. */
  71. if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh))
  72. return 0;
  73. rv = 0;
  74. /* Read identification register to see if present */
  75. if (bus_space_read_1(iot, ioh, MMS_IDENT) != 0xde)
  76. goto out;
  77. /* Seems it was there; reset. */
  78. bus_space_write_1(iot, ioh, MMS_ADDR, 0x87);
  79. rv = 1;
  80. ia->ia_iosize = MMS_NPORTS;
  81. ia->ia_msize = 0;
  82. out:
  83. bus_space_unmap(iot, ioh, MMS_NPORTS);
  84. return rv;
  85. }
  86. void
  87. mmsattach(struct device *parent, struct device *self, void *aux)
  88. {
  89. struct mms_softc *sc = (void *)self;
  90. struct isa_attach_args *ia = aux;
  91. bus_space_tag_t iot = ia->ia_iot;
  92. bus_space_handle_t ioh;
  93. struct wsmousedev_attach_args a;
  94. printf("\n");
  95. if (bus_space_map(iot, ia->ia_iobase, MMS_NPORTS, 0, &ioh)) {
  96. printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
  97. return;
  98. }
  99. /* Other initialization was done by mmsprobe. */
  100. sc->sc_iot = iot;
  101. sc->sc_ioh = ioh;
  102. sc->sc_enabled = 0;
  103. sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_PULSE,
  104. IPL_TTY, mmsintr, sc, sc->sc_dev.dv_xname);
  105. a.accessops = &mms_accessops;
  106. a.accesscookie = sc;
  107. /*
  108. * Attach the wsmouse, saving a handle to it.
  109. * Note that we don't need to check this pointer against NULL
  110. * here or in psmintr, because if this fails lms_enable() will
  111. * never be called, so lmsintr() will never be called.
  112. */
  113. sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
  114. }
  115. int
  116. mms_enable(void *v)
  117. {
  118. struct mms_softc *sc = v;
  119. if (sc->sc_enabled)
  120. return EBUSY;
  121. sc->sc_enabled = 1;
  122. /* Enable interrupts. */
  123. bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x07);
  124. bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_DATA, 0x09);
  125. return 0;
  126. }
  127. void
  128. mms_disable(void *v)
  129. {
  130. struct mms_softc *sc = v;
  131. /* Disable interrupts. */
  132. bus_space_write_1(sc->sc_iot, sc->sc_ioh, MMS_ADDR, 0x87);
  133. sc->sc_enabled = 0;
  134. }
  135. int
  136. mms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
  137. {
  138. #if 0
  139. struct mms_softc *sc = v;
  140. #endif
  141. switch (cmd) {
  142. case WSMOUSEIO_GTYPE:
  143. *(u_int *)data = WSMOUSE_TYPE_MMS;
  144. return (0);
  145. }
  146. return (-1);
  147. }
  148. int
  149. mmsintr(void *arg)
  150. {
  151. struct mms_softc *sc = arg;
  152. bus_space_tag_t iot = sc->sc_iot;
  153. bus_space_handle_t ioh = sc->sc_ioh;
  154. u_char status;
  155. signed char dx, dy;
  156. u_int buttons;
  157. int changed;
  158. if (!sc->sc_enabled)
  159. /* Interrupts are not expected. */
  160. return 0;
  161. /* Freeze InPort registers (disabling interrupts). */
  162. bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
  163. bus_space_write_1(iot, ioh, MMS_DATA, 0x29);
  164. bus_space_write_1(iot, ioh, MMS_ADDR, 0x00);
  165. status = bus_space_read_1(iot, ioh, MMS_DATA);
  166. if (status & 0x40) {
  167. bus_space_write_1(iot, ioh, MMS_ADDR, 1);
  168. dx = bus_space_read_1(iot, ioh, MMS_DATA);
  169. /* Bounding at -127 avoids a bug in XFree86. */
  170. dx = (dx == -128) ? -127 : dx;
  171. bus_space_write_1(iot, ioh, MMS_ADDR, 2);
  172. dy = bus_space_read_1(iot, ioh, MMS_DATA);
  173. dy = (dy == -128) ? 127 : -dy;
  174. } else
  175. dx = dy = 0;
  176. /* Unfreeze InPort registers (reenabling interrupts). */
  177. bus_space_write_1(iot, ioh, MMS_ADDR, 0x07);
  178. bus_space_write_1(iot, ioh, MMS_DATA, 0x09);
  179. buttons = ((status & 0x04) ? 0x1 : 0) |
  180. ((status & 0x02) ? 0x2 : 0) |
  181. ((status & 0x01) ? 0x4 : 0);
  182. changed = status & 0x38;
  183. if (dx || dy || changed)
  184. wsmouse_input(sc->sc_wsmousedev,
  185. buttons, dx, dy, 0, 0, WSMOUSE_INPUT_DELTA);
  186. return -1;
  187. }
  188. struct cfdriver mms_cd = {
  189. NULL, "mms", DV_DULL
  190. };