1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991-1997 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <stdio.h> 35 #include <sys/types.h> 36 #include <sys/ioctl.h> 37 #include <sys/signal.h> 38 #include <sys/consio.h> 39 #include <sys/fbio.h> 40 #include "vgl.h" 41 42 #define X 0xff 43 static byte StdAndMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = { 44 X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 45 X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0, 46 X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0, 47 X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0, 48 X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0, 49 X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0, 50 X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,0, 51 X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,0, 52 X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0, 53 0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,0, 54 0,0,0,X,X,X,X,X,0,0,0,0,0,0,0,0, 55 0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,0, 56 0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,0, 57 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 58 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 59 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 60 }; 61 static byte StdOrMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = { 62 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 63 0,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 64 0,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0, 65 0,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0, 66 0,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0, 67 0,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0, 68 0,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0, 69 0,X,X,0,X,0,0,0,0,0,0,0,0,0,0,0, 70 0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0, 71 0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0, 72 0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,0, 73 0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,0, 74 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 75 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 76 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 77 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 78 }; 79 #undef X 80 static VGLBitmap VGLMouseStdAndMask = 81 VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask); 82 static VGLBitmap VGLMouseStdOrMask = 83 VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask); 84 static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask; 85 static byte map[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE*4]; 86 static VGLBitmap VGLMouseSave = 87 VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, map); 88 static int VGLMouseVisible = 0; 89 static int VGLMouseShown = 0; 90 static int VGLMouseXpos = 0; 91 static int VGLMouseYpos = 0; 92 static int VGLMouseButtons = 0; 93 static volatile sig_atomic_t VGLMintpending; 94 static volatile sig_atomic_t VGLMsuppressint; 95 96 #define INTOFF() (VGLMsuppressint++) 97 #define INTON() do { \ 98 if (--VGLMsuppressint == 0 && VGLMintpending) \ 99 VGLMouseAction(0); \ 100 } while (0) 101 102 void 103 VGLMousePointerShow() 104 { 105 byte buf[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE*4]; 106 VGLBitmap buffer = 107 VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf); 108 byte crtcidx, crtcval, gdcidx, gdcval; 109 int i, pos, pos1; 110 111 if (!VGLMouseVisible) { 112 INTOFF(); 113 VGLMouseVisible = 1; 114 crtcidx = inb(0x3c4); 115 crtcval = inb(0x3c5); 116 gdcidx = inb(0x3ce); 117 gdcval = inb(0x3cf); 118 __VGLBitmapCopy(VGLDisplay, VGLMouseXpos, VGLMouseYpos, 119 &VGLMouseSave, 0, 0, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 120 bcopy(VGLMouseSave.Bitmap, buffer.Bitmap, 121 MOUSE_IMG_SIZE*MOUSE_IMG_SIZE*VGLDisplay->PixelBytes); 122 for (pos = 0; pos < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; pos++) 123 for (i = 0; i < VGLDisplay->PixelBytes; i++) { 124 pos1 = pos * VGLDisplay->PixelBytes + i; 125 buffer.Bitmap[pos1] = (buffer.Bitmap[pos1] & 126 ~VGLMouseAndMask->Bitmap[pos]) | 127 VGLMouseOrMask->Bitmap[pos]; 128 } 129 __VGLBitmapCopy(&buffer, 0, 0, VGLDisplay, 130 VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 131 outb(0x3c4, crtcidx); 132 outb(0x3c5, crtcval); 133 outb(0x3ce, gdcidx); 134 outb(0x3cf, gdcval); 135 INTON(); 136 } 137 } 138 139 void 140 VGLMousePointerHide() 141 { 142 byte crtcidx, crtcval, gdcidx, gdcval; 143 144 if (VGLMouseVisible) { 145 INTOFF(); 146 VGLMouseVisible = 0; 147 crtcidx = inb(0x3c4); 148 crtcval = inb(0x3c5); 149 gdcidx = inb(0x3ce); 150 gdcval = inb(0x3cf); 151 __VGLBitmapCopy(&VGLMouseSave, 0, 0, VGLDisplay, 152 VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 153 outb(0x3c4, crtcidx); 154 outb(0x3c5, crtcval); 155 outb(0x3ce, gdcidx); 156 outb(0x3cf, gdcval); 157 INTON(); 158 } 159 } 160 161 void 162 VGLMouseMode(int mode) 163 { 164 if (mode == VGL_MOUSESHOW) { 165 if (VGLMouseShown == VGL_MOUSEHIDE) { 166 VGLMousePointerShow(); 167 VGLMouseShown = VGL_MOUSESHOW; 168 } 169 } 170 else { 171 if (VGLMouseShown == VGL_MOUSESHOW) { 172 VGLMousePointerHide(); 173 VGLMouseShown = VGL_MOUSEHIDE; 174 } 175 } 176 } 177 178 void 179 VGLMouseAction(int dummy) 180 { 181 struct mouse_info mouseinfo; 182 183 if (VGLMsuppressint) { 184 VGLMintpending = 1; 185 return; 186 } 187 again: 188 INTOFF(); 189 VGLMintpending = 0; 190 mouseinfo.operation = MOUSE_GETINFO; 191 ioctl(0, CONS_MOUSECTL, &mouseinfo); 192 if (VGLMouseShown == VGL_MOUSESHOW) 193 VGLMousePointerHide(); 194 VGLMouseXpos = mouseinfo.u.data.x; 195 VGLMouseYpos = mouseinfo.u.data.y; 196 VGLMouseButtons = mouseinfo.u.data.buttons; 197 if (VGLMouseShown == VGL_MOUSESHOW) 198 VGLMousePointerShow(); 199 200 /* 201 * Loop to handle any new (suppressed) signals. This is INTON() without 202 * recursion. !SA_RESTART prevents recursion in signal handling. So the 203 * maximum recursion is 2 levels. 204 */ 205 VGLMsuppressint = 0; 206 if (VGLMintpending) 207 goto again; 208 } 209 210 void 211 VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask) 212 { 213 if (VGLMouseShown == VGL_MOUSESHOW) 214 VGLMousePointerHide(); 215 VGLMouseAndMask = AndMask; 216 VGLMouseOrMask = OrMask; 217 if (VGLMouseShown == VGL_MOUSESHOW) 218 VGLMousePointerShow(); 219 } 220 221 void 222 VGLMouseSetStdImage() 223 { 224 if (VGLMouseShown == VGL_MOUSESHOW) 225 VGLMousePointerHide(); 226 VGLMouseAndMask = &VGLMouseStdAndMask; 227 VGLMouseOrMask = &VGLMouseStdOrMask; 228 if (VGLMouseShown == VGL_MOUSESHOW) 229 VGLMousePointerShow(); 230 } 231 232 int 233 VGLMouseInit(int mode) 234 { 235 struct mouse_info mouseinfo; 236 int error, i, mask; 237 238 switch (VGLModeInfo.vi_mem_model) { 239 case V_INFO_MM_PACKED: 240 case V_INFO_MM_PLANAR: 241 mask = 0x0f; 242 break; 243 case V_INFO_MM_VGAX: 244 mask = 0x3f; 245 break; 246 default: 247 mask = 0xff; 248 break; 249 } 250 for (i = 0; i < 256; i++) 251 VGLMouseStdOrMask.Bitmap[i] &= mask; 252 VGLMouseSetStdImage(); 253 mouseinfo.operation = MOUSE_MODE; 254 mouseinfo.u.mode.signal = SIGUSR2; 255 if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo))) 256 return error; 257 signal(SIGUSR2, VGLMouseAction); 258 mouseinfo.operation = MOUSE_GETINFO; 259 ioctl(0, CONS_MOUSECTL, &mouseinfo); 260 VGLMouseXpos = mouseinfo.u.data.x; 261 VGLMouseYpos = mouseinfo.u.data.y; 262 VGLMouseButtons = mouseinfo.u.data.buttons; 263 VGLMouseMode(mode); 264 return 0; 265 } 266 267 int 268 VGLMouseStatus(int *x, int *y, char *buttons) 269 { 270 INTOFF(); 271 *x = VGLMouseXpos; 272 *y = VGLMouseYpos; 273 *buttons = VGLMouseButtons; 274 INTON(); 275 return VGLMouseShown; 276 } 277 278 int 279 VGLMouseFreeze(int x, int y, int width, int hight, u_long color) 280 { 281 int i, xstride, ystride; 282 283 INTOFF(); 284 if (width > 1 || hight > 1 || (color & 0xc0000000) == 0) { /* bitmap */ 285 if (VGLMouseShown == 1) { 286 int overlap; 287 288 if (x > VGLMouseXpos) 289 overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x; 290 else 291 overlap = (x + width) - VGLMouseXpos; 292 if (overlap > 0) { 293 if (y > VGLMouseYpos) 294 overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y; 295 else 296 overlap = (y + hight) - VGLMouseYpos; 297 if (overlap > 0) 298 VGLMousePointerHide(); 299 } 300 } 301 } 302 else { /* bit */ 303 if (VGLMouseShown && 304 x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE && 305 y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE) { 306 xstride = VGLDisplay->PixelBytes; 307 ystride = MOUSE_IMG_SIZE * xstride; 308 if (color & 0x40000000) { /* Get */ 309 color = 0; 310 for (i = xstride - 1; i >= 0; i--) 311 color = (color << 8) | 312 VGLMouseSave.Bitmap[(y-VGLMouseYpos)*ystride+ 313 (x-VGLMouseXpos)*xstride+i]; 314 return 0x40000000 | (color & 0xffffff); 315 } else { /* Set */ 316 color &= 0xffffff; /* discard flag and other garbage */ 317 for (i = 0; i < xstride; i++, color >>= 8) 318 VGLMouseSave.Bitmap[(y-VGLMouseYpos)*ystride+ 319 (x-VGLMouseXpos)*xstride+i] = color; 320 if (VGLMouseAndMask->Bitmap 321 [(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)]) { 322 return 1; 323 } 324 } 325 } 326 } 327 return 0; 328 } 329 330 void 331 VGLMouseUnFreeze() 332 { 333 if (VGLMouseShown == VGL_MOUSESHOW && !VGLMouseVisible && !VGLMintpending) 334 VGLMousePointerShow(); 335 while (VGLMsuppressint) 336 INTON(); 337 } 338