]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
MdePkg/BaseSynchronizationLib: Added ARM Aarch64 architecture support
[mirror_edk2.git] / UnixPkg / Sec / UgaX11.c
CommitLineData
ccd55824 1/*++
2
1c3b1010 3Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
2ff79f2e 4Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
f9b8ab56 5This program and the accompanying materials
ccd55824 6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13--*/
d0c3acd4 14#include <Common/UnixInclude.h>
ccd55824 15
804405e7 16#include <sys/ipc.h>
17#include <sys/shm.h>
804405e7 18
2ff79f2e 19#include <PiPei.h>
20#include <Protocol/SimplePointer.h>
21#include <Protocol/SimpleTextIn.h>
22#include <Protocol/SimpleTextInEx.h>
23#include <Protocol/UgaDraw.h>
804405e7 24#include <X11/Xlib.h>
25#include <X11/Xutil.h>
26#include <X11/Xos.h>
27#include <X11/extensions/XShm.h>
28#include <X11/keysym.h>
2ff79f2e 29#include <X11/cursorfont.h>
30
31#include <Protocol/UnixThunk.h>
32#include <Protocol/UnixUgaIo.h>
804405e7 33
804405e7 34#include <Ppi/StatusCode.h>
35
36#include <Library/PeCoffLib.h>
37#include <Library/BaseLib.h>
38#include <Library/BaseMemoryLib.h>
39#include <Library/PrintLib.h>
40#include <Library/PcdLib.h>
41#include <Library/DebugLib.h>
42
2ff79f2e 43#include "Gasket.h"
44#include "SecMain.h"
45
46
804405e7 47extern void msSleep (unsigned long Milliseconds);
48
49/* XQueryPointer */
50
2ff79f2e 51struct uga_drv_shift_mask {
804405e7 52 unsigned char shift;
53 unsigned char size;
54 unsigned char csize;
55};
56
57#define NBR_KEYS 32
2ff79f2e 58typedef struct {
804405e7 59 EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
60
61 Display *display;
2ac288f9 62 int screen; /* values for window_size in main */
804405e7 63 Window win;
64 GC gc;
65 Visual *visual;
66
67 int depth;
68 unsigned int width;
69 unsigned int height;
70 unsigned int line_bytes;
71 unsigned int pixel_shift;
72 unsigned char *image_data;
73
74 struct uga_drv_shift_mask r, g, b;
75
76 int use_shm;
77 XShmSegmentInfo xshm_info;
78 XImage *image;
79
80 unsigned int key_rd;
81 unsigned int key_wr;
82 unsigned int key_count;
2ff79f2e 83 EFI_KEY_DATA keys[NBR_KEYS];
84
85 EFI_KEY_STATE KeyState;
86
87 UGA_REGISTER_KEY_NOTIFY_CALLBACK RegisterdKeyCallback;
88 VOID *RegisterdKeyCallbackContext;
89
90 int previous_x;
91 int previous_y;
92 EFI_SIMPLE_POINTER_STATE pointer_state;
93 int pointer_state_changed;
804405e7 94} UGA_IO_PRIVATE;
95
7492c63d 96void
804405e7 97HandleEvents(UGA_IO_PRIVATE *drv);
98
7492c63d 99void
804405e7 100fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
101{
102 sm->shift = 0;
103 sm->size = 0;
104 while ((mask & 1) == 0)
105 {
106 mask >>= 1;
107 sm->shift++;
108 }
109 while (mask & 1)
110 {
111 sm->size++;
112 mask >>= 1;
113 }
114 sm->csize = 8 - sm->size;
115}
116
7492c63d 117int
804405e7 118TryCreateShmImage(UGA_IO_PRIVATE *drv)
119{
120 drv->image = XShmCreateImage (drv->display, drv->visual,
288a3c98 121 drv->depth, ZPixmap, NULL, &drv->xshm_info,
122 drv->width, drv->height);
804405e7 123 if (drv->image == NULL)
124 return 0;
125
126 switch (drv->image->bitmap_unit) {
127 case 32:
128 drv->pixel_shift = 2;
129 break;
130 case 16:
131 drv->pixel_shift = 1;
132 break;
133 case 8:
134 drv->pixel_shift = 0;
135 break;
136 }
137
138 drv->xshm_info.shmid = shmget
288a3c98 139 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
140 IPC_CREAT | 0777);
7ee3b613
A
141 if (drv->xshm_info.shmid < 0) {
142 XDestroyImage(drv->image);
143 return 0;
144 }
804405e7 145
146 drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
7ee3b613
A
147 if(!drv->image_data) {
148 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
149 XDestroyImage(drv->image);
150 return 0;
151 }
ccd55824 152
153#ifndef __APPLE__
154 //
155 // This closes shared memory in real time on OS X. Only closes after folks quit using
156 // it on Linux.
157 //
804405e7 158 /* Can this fail ? */
159 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
ccd55824 160#endif
804405e7 161
162 drv->xshm_info.shmaddr = (char*)drv->image_data;
163 drv->image->data = (char*)drv->image_data;
288a3c98 164
7ee3b613
A
165 if (!XShmAttach (drv->display, &drv->xshm_info)) {
166 shmdt (drv->image_data);
167 XDestroyImage(drv->image);
168 return 0;
169 }
804405e7 170 return 1;
171}
172
804405e7 173EFI_STATUS
174UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
175{
176 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
177
178 if (drv == NULL)
179 return EFI_SUCCESS;
180 if (drv->image != NULL)
181 {
182 XDestroyImage(drv->image);
183
184 if (drv->use_shm)
288a3c98 185 shmdt (drv->image_data);
804405e7 186
187 drv->image_data = NULL;
188 drv->image = NULL;
189 }
190 XDestroyWindow(drv->display, drv->win);
191 XCloseDisplay(drv->display);
ccd55824 192
193#ifdef __APPLE__
194 // Free up the shared memory
195 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
196#endif
197
804405e7 198 free(drv);
199 return EFI_SUCCESS;
200}
201
804405e7 202EFI_STATUS
203UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
204{
205 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
206 XSizeHints size_hints;
207
208 /* Destroy current buffer if created. */
209 if (drv->image != NULL)
210 {
7d28e82d 211 /* Before destroy buffer, need to make sure the buffer available for access. */
804405e7 212 XDestroyImage(drv->image);
213
214 if (drv->use_shm)
288a3c98 215 shmdt (drv->image_data);
804405e7 216
217 drv->image_data = NULL;
218 drv->image = NULL;
219 }
220
221 drv->width = Width;
222 drv->height = Height;
223 XResizeWindow (drv->display, drv->win, Width, Height);
224
225 /* Allocate image. */
288a3c98 226 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
227 drv->use_shm = 1;
228 } else {
229 drv->use_shm = 0;
230 if (drv->depth > 16)
231 drv->pixel_shift = 2;
232 else if (drv->depth > 8)
233 drv->pixel_shift = 1;
234 else
235 drv->pixel_shift = 0;
804405e7 236
237 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
238 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 239 ZPixmap, 0, (char *)drv->image_data,
240 drv->width, drv->height,
241 8 << drv->pixel_shift, 0);
804405e7 242 }
243 drv->line_bytes = drv->image->bytes_per_line;
244 fill_shift_mask (&drv->r, drv->image->red_mask);
245 fill_shift_mask (&drv->g, drv->image->green_mask);
246 fill_shift_mask (&drv->b, drv->image->blue_mask);
247
248 /* Set WM hints. */
249 size_hints.flags = PSize | PMinSize | PMaxSize;
250 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
251 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
252 XSetWMNormalHints (drv->display, drv->win, &size_hints);
253
254 XMapWindow (drv->display, drv->win);
255 HandleEvents(drv);
256 return EFI_SUCCESS;
257}
258
7492c63d 259void
804405e7 260handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
261{
262 KeySym keysym;
263 char str[4];
2ff79f2e 264 EFI_KEY_DATA KeyData;
804405e7 265 int res;
266
267 if (drv->key_count == NBR_KEYS)
268 return;
269
270 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
2ff79f2e 271 KeyData.Key.ScanCode = 0;
272 KeyData.Key.UnicodeChar = 0;
273 KeyData.KeyState.KeyShiftState = 0;
274
275 //
276 // KeyRelease is not supported (on Mac) so we can not easily implement Ex functions.
277 // If a modifier key is hit by its self we get a keysym. If a modfifier and key is hit
278 // we get the state bit set and keysym is the modified key.
279 //
280 // We use lack of state bits being set to clear ToggleState and KeyShiftState. We can
281 // also use the stat bits to set ToggleState and KeyShiftState.
282 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs
283 //
284 if ((ev->xkey.state & LockMask) == 0) {
285 drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
286 } else {
287 drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
288 }
289
290 if ((ev->xkey.state & ControlMask) == 0) {
291 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED);
292 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_CONTROL_PRESSED) == 0) {
293 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
294 }
295
296 if ((ev->xkey.state & ShiftMask) == 0) {
297 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED);
298 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_SHIFT_PRESSED) == 0) {
299 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
300 }
301
302 if ((ev->xkey.state & Mod2Mask) == 0) {
303 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED);
304 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_LOGO_PRESSED) == 0) {
305 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
306 }
307
308 if ((ev->xkey.state & 0x2000) == 0) {
309 drv->KeyState.KeyShiftState &= ~(EFI_LEFT_ALT_PRESSED);
310 } else {
311 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
312 }
313
314
288a3c98 315 switch (keysym) {
2ff79f2e 316 case XK_Control_R:
317 drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
318 break;
319 case XK_Control_L:
320 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
321 break;
322
323 case XK_Shift_R:
324 drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
325 break;
326 case XK_Shift_L:
327 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
328 break;
329
330 case XK_Mode_switch:
331 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
332 break;
333
334 case XK_Meta_R:
335 drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
336 break;
337 case XK_Meta_L:
338 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
339 break;
340
341 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;
342 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;
343 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;
344 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;
345 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;
346 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;
347 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;
348 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;
349 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;
350 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;
351 case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break;
1c3b1010 352 case XK_Pause: KeyData.Key.ScanCode = SCAN_PAUSE; break;
2ff79f2e 353
354 case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break;
355 case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break;
356 case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break;
357 case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break;
358 case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break;
359 case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break;
360 case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break;
361 case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break;
362 case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break;
804405e7 363
364 default:
365 if (res == 1) {
2ff79f2e 366 KeyData.Key.UnicodeChar = str[0];
804405e7 367 } else {
368 return;
369 }
288a3c98 370 }
371
2ff79f2e 372 // The global state is our state
373 KeyData.KeyState.KeyShiftState = drv->KeyState.KeyShiftState;
374 KeyData.KeyState.KeyToggleState = drv->KeyState.KeyToggleState;
375
376 CopyMem (&drv->keys[drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA));
804405e7 377 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
378 drv->key_count++;
2ff79f2e 379
380
381#if defined(__APPLE__) || defined(MDE_CPU_X64)
382 ReverseGasketUint64Uint64 (drv->RegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData);
383#else
384 drv->RegisterdKeyCallback (drv->RegisterdKeyCallbackContext, &KeyData);
385#endif
386
387
388}
389
390
391void
392handleMouseMoved(UGA_IO_PRIVATE *drv, XEvent *ev)
393{
394 if ( ev->xmotion.x != drv->previous_x )
395 {
396 drv->pointer_state.RelativeMovementX += ( ev->xmotion.x - drv->previous_x );
2ac288f9 397 drv->previous_x = ev->xmotion.x;
398 drv->pointer_state_changed = 1;
2ff79f2e 399 }
400
401 if ( ev->xmotion.y != drv->previous_y )
402 {
403 drv->pointer_state.RelativeMovementY += ( ev->xmotion.y - drv->previous_y );
404 drv->previous_y = ev->xmotion.y;
2ac288f9 405 drv->pointer_state_changed = 1;
2ff79f2e 406 }
407
408 drv->pointer_state.RelativeMovementZ = 0;
409}
410
411void
412handleMouseDown(UGA_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Pressed)
413{
414 if ( ev->xbutton.button == Button1 )
415 {
416 drv->pointer_state_changed = ( drv->pointer_state.LeftButton != Pressed );
2ac288f9 417 drv->pointer_state.LeftButton = Pressed;
2ff79f2e 418 }
419 if ( ev->xbutton.button == Button2 )
420 {
421 drv->pointer_state_changed = ( drv->pointer_state.RightButton != Pressed );
2ac288f9 422 drv->pointer_state.RightButton = Pressed;
2ff79f2e 423 }
804405e7 424}
425
7492c63d 426void
804405e7 427Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
428{
429 if (drv->use_shm)
430 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 431 X, Y, X, Y, Width, Height, False);
804405e7 432 else
433 XPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 434 X, Y, X, Y, Width, Height);
435 XFlush(drv->display);
804405e7 436}
437
7492c63d 438void
804405e7 439HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
440{
441 switch (ev->type)
442 {
443 case Expose:
444 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
288a3c98 445 ev->xexpose.width, ev->xexpose.height);
804405e7 446 break;
447 case GraphicsExpose:
448 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
288a3c98 449 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
804405e7 450 break;
451 case KeyPress:
452 handleKeyEvent(drv, ev);
453 break;
2ff79f2e 454 case KeyRelease:
455 break;
804405e7 456 case MappingNotify:
457 XRefreshKeyboardMapping(&ev->xmapping);
458 break;
2ff79f2e 459 case MotionNotify:
460 handleMouseMoved(drv, ev);
461 break;
462 case ButtonPress:
463 handleMouseDown(drv, ev, TRUE);
2ac288f9 464 break;
2ff79f2e 465 case ButtonRelease:
466 handleMouseDown(drv, ev, FALSE);
2ac288f9 467 break;
804405e7 468#if 0
469 case DestroyNotify:
470 XCloseDisplay (drv->display);
471 exit (1);
472 break;
473#endif
474 case NoExpose:
475 default:
476 break;
477 }
478}
479
7492c63d 480void
804405e7 481HandleEvents(UGA_IO_PRIVATE *drv)
482{
483 while (XPending(drv->display) != 0)
484 {
485 XEvent ev;
288a3c98 486
804405e7 487 XNextEvent (drv->display, &ev);
488 HandleEvent(drv, &ev);
489 }
490}
491
804405e7 492unsigned long
493UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
494{
495 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
496 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
497 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
498}
499
804405e7 500EFI_UGA_PIXEL
501UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
502{
503 EFI_UGA_PIXEL res;
504
505 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
506 /* FIXME: should round instead of truncate. */
507 res.Red = (val >> drv->r.shift) << drv->r.csize;
508 res.Green = (val >> drv->g.shift) << drv->g.csize;
509 res.Blue = (val >> drv->b.shift) << drv->b.csize;
510
511 return res;
512}
513
2ff79f2e 514STATIC EFI_STATUS
515CheckKeyInternal( UGA_IO_PRIVATE *drv, BOOLEAN delay )
804405e7 516{
804405e7 517 HandleEvents(drv);
2ff79f2e 518 if (drv->key_count != 0)
804405e7 519 return EFI_SUCCESS;
2ff79f2e 520 if ( delay )
521 /* EFI is polling. Be CPU-friendly. */
804405e7 522 msSleep (20);
523 return EFI_NOT_READY;
524 }
2ff79f2e 525
526EFI_STATUS
527UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
528{
529 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
530 return( CheckKeyInternal( drv, TRUE ) );
804405e7 531}
532
804405e7 533EFI_STATUS
2ff79f2e 534EFIAPI
535UgaGetKey (
536 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
537 IN EFI_KEY_DATA *KeyData
538 )
804405e7 539{
540 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
541 EFI_STATUS status;
542
2ff79f2e 543 status = CheckKeyInternal(drv, FALSE);
804405e7 544 if (status != EFI_SUCCESS)
545 return status;
546
2ff79f2e 547 CopyMem (KeyData, &drv->keys[drv->key_rd], sizeof (EFI_KEY_DATA));
804405e7 548 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
549 drv->key_count--;
550 return EFI_SUCCESS;
551}
552
2ff79f2e 553
554EFI_STATUS
555EFIAPI
556UgaKeySetState (
557 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
558 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
559 )
560{
561 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
562// XKeyEvent event;
563
564 if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) {
565 if ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) {
566 //
567 // We could create an XKeyEvent and send a XK_Caps_Lock to
568 // the UGA/GOP Window
569 //
570 }
571 }
572
573 drv->KeyState.KeyToggleState = *KeyToggleState;
574 return EFI_SUCCESS;
575}
576
577
578EFI_STATUS
579EFIAPI
580UgaRegisterKeyNotify (
581 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
582 IN UGA_REGISTER_KEY_NOTIFY_CALLBACK CallBack,
583 IN VOID *Context
584 )
585{
586 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
587
588 drv->RegisterdKeyCallback = CallBack;
589 drv->RegisterdKeyCallbackContext = Context;
590
591 return EFI_SUCCESS;
592}
593
594
288a3c98 595EFI_STATUS
a4902ccc 596UgaBlt(
597 IN EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
598 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
599 IN EFI_UGA_BLT_OPERATION BltOperation,
600 IN UGA_BLT_ARGS *Args
288a3c98 601 )
804405e7 602{
603 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
288a3c98 604 UINTN DstY;
605 UINTN SrcY;
804405e7 606 UINTN DstX;
607 UINTN SrcX;
608 UINTN Index;
288a3c98 609 EFI_UGA_PIXEL *Blt;
804405e7 610 UINT8 *Dst;
611 UINT8 *Src;
612 UINTN Nbr;
613 unsigned long Color;
614
615 //
616 // Check bounds
617 //
618 if (BltOperation == EfiUgaVideoToBltBuffer
288a3c98 619 || BltOperation == EfiUgaVideoToVideo) {
620 //
804405e7 621 // Source is Video.
288a3c98 622 //
a4902ccc 623 if (Args->SourceY + Args->Height > Private->height) {
288a3c98 624 return EFI_INVALID_PARAMETER;
625 }
626
a4902ccc 627 if (Args->SourceX + Args->Width > Private->width) {
288a3c98 628 return EFI_INVALID_PARAMETER;
629 }
804405e7 630 }
631
632 if (BltOperation == EfiUgaBltBufferToVideo
633 || BltOperation == EfiUgaVideoToVideo
288a3c98 634 || BltOperation == EfiUgaVideoFill) {
635 //
636 // Destination is Video
637 //
a4902ccc 638 if (Args->DestinationY + Args->Height > Private->height) {
288a3c98 639 return EFI_INVALID_PARAMETER;
640 }
641
a4902ccc 642 if (Args->DestinationX + Args->Width > Private->width) {
288a3c98 643 return EFI_INVALID_PARAMETER;
644 }
804405e7 645 }
646
288a3c98 647 switch (BltOperation) {
804405e7 648 case EfiUgaVideoToBltBuffer:
a4902ccc 649 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL));
650 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
651 for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) {
652 for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) {
288a3c98 653 *Blt++ = UgaColorToPixel(Private,
654 XGetPixel(Private->image, SrcX, SrcY));
804405e7 655 }
a4902ccc 656 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
288a3c98 657 }
804405e7 658 break;
288a3c98 659 case EfiUgaBltBufferToVideo:
a4902ccc 660 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL));
661 Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL);
662 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
663 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
288a3c98 664 XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
665 Blt++;
804405e7 666 }
a4902ccc 667 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta);
804405e7 668 }
669 break;
288a3c98 670 case EfiUgaVideoToVideo:
a4902ccc 671 Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift)
672 + Args->DestinationY * Private->line_bytes;
673 Src = Private->image_data + (Args->SourceX << Private->pixel_shift)
674 + Args->SourceY * Private->line_bytes;
675 Nbr = Args->Width << Private->pixel_shift;
676 if (Args->DestinationY < Args->SourceY) {
677 for (Index = 0; Index < Args->Height; Index++) {
288a3c98 678 memcpy (Dst, Src, Nbr);
679 Dst += Private->line_bytes;
680 Src += Private->line_bytes;
804405e7 681 }
682 }
683 else {
a4902ccc 684 Dst += (Args->Height - 1) * Private->line_bytes;
685 Src += (Args->Height - 1) * Private->line_bytes;
686 for (Index = 0; Index < Args->Height; Index++) {
288a3c98 687 //
688 // Source and Destination Y may be equal, therefore Dst and Src may
689 // overlap.
690 //
691 memmove (Dst, Src, Nbr);
692 Dst -= Private->line_bytes;
693 Src -= Private->line_bytes;
804405e7 694 }
695 }
696 break;
697 case EfiUgaVideoFill:
698 Color = UgaPixelToColor(Private, *BltBuffer);
a4902ccc 699 for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) {
700 for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) {
288a3c98 701 XPutPixel(Private->image, DstX, DstY, Color);
804405e7 702 }
288a3c98 703 }
804405e7 704 break;
705 default:
288a3c98 706 return EFI_INVALID_PARAMETER;
804405e7 707 }
708
709 //
710 // Refresh screen.
711 //
288a3c98 712 switch (BltOperation) {
713 case EfiUgaVideoToVideo:
804405e7 714 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
a4902ccc 715 Args->SourceX, Args->SourceY, Args->Width, Args->Height, Args->DestinationX, Args->DestinationY);
804405e7 716 while (1) {
717 XEvent ev;
288a3c98 718
804405e7 719 XNextEvent (Private->display, &ev);
720 HandleEvent(Private, &ev);
721 if (ev.type == NoExpose || ev.type == GraphicsExpose)
288a3c98 722 break;
804405e7 723 }
724 break;
725 case EfiUgaVideoFill:
726 Color = UgaPixelToColor(Private, *BltBuffer);
727 XSetForeground(Private->display, Private->gc, Color);
728 XFillRectangle(Private->display, Private->win, Private->gc,
a4902ccc 729 Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
288a3c98 730 XFlush(Private->display);
804405e7 731 break;
288a3c98 732 case EfiUgaBltBufferToVideo:
a4902ccc 733 Redraw(Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height);
804405e7 734 break;
735 default:
736 break;
737 }
738 return EFI_SUCCESS;
739}
740
2ff79f2e 741STATIC EFI_STATUS
742CheckPointerInternal( UGA_IO_PRIVATE *drv, BOOLEAN delay )
743{
744 HandleEvents(drv);
745 if (drv->pointer_state_changed != 0)
746 return EFI_SUCCESS;
747 if ( delay )
748 /* EFI is polling. Be CPU-friendly. */
749 msSleep (20);
750 return EFI_NOT_READY;
751}
752
753EFI_STATUS
754UgaCheckPointer(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
755{
756 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
757 return( CheckPointerInternal( drv, TRUE ) );
758}
759
760EFI_STATUS
761UgaGetPointerState (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_SIMPLE_POINTER_STATE *state)
762{
763 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
764 EFI_STATUS status;
765
766 status = CheckPointerInternal( drv, FALSE );
767 if (status != EFI_SUCCESS)
768 return status;
769
770 memcpy( state, &drv->pointer_state, sizeof( EFI_SIMPLE_POINTER_STATE ) );
771
772 drv->pointer_state.RelativeMovementX = 0;
773 drv->pointer_state.RelativeMovementY = 0;
774 drv->pointer_state.RelativeMovementZ = 0;
775 drv->pointer_state_changed = 0;
776 return EFI_SUCCESS;
777}
778
804405e7 779EFI_STATUS
780UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
781{
782 UGA_IO_PRIVATE *drv;
783 unsigned int border_width = 0;
784 char *display_name = NULL;
785 int title_len;
786
ccd55824 787 drv = (UGA_IO_PRIVATE *)calloc (1, sizeof (UGA_IO_PRIVATE));
804405e7 788 if (drv == NULL)
789 return EFI_OUT_OF_RESOURCES;
790
2ff79f2e 791#if defined(__APPLE__) || defined(MDE_CPU_X64)
ccd55824 792//
793//
794//
ccd55824 795 drv->UgaIo.UgaClose = GasketUgaClose;
796 drv->UgaIo.UgaSize = GasketUgaSize;
797 drv->UgaIo.UgaCheckKey = GasketUgaCheckKey;
798 drv->UgaIo.UgaGetKey = GasketUgaGetKey;
2ff79f2e 799 drv->UgaIo.UgaKeySetState = GasketUgaKeySetState;
800 drv->UgaIo.UgaRegisterKeyNotify = GasketUgaRegisterKeyNotify;
ccd55824 801 drv->UgaIo.UgaBlt = GasketUgaBlt;
2ff79f2e 802 drv->UgaIo.UgaCheckPointer = GasketUgaCheckPointer;
803 drv->UgaIo.UgaGetPointerState = GasketUgaGetPointerState;
ccd55824 804#else
804405e7 805 drv->UgaIo.UgaClose = UgaClose;
806 drv->UgaIo.UgaSize = UgaSize;
807 drv->UgaIo.UgaCheckKey = UgaCheckKey;
808 drv->UgaIo.UgaGetKey = UgaGetKey;
2ff79f2e 809 drv->UgaIo.UgaKeySetState = UgaKeySetState;
810 drv->UgaIo.UgaRegisterKeyNotify = UgaRegisterKeyNotify;
804405e7 811 drv->UgaIo.UgaBlt = UgaBlt;
2ff79f2e 812 drv->UgaIo.UgaCheckPointer = UgaCheckPointer;
813 drv->UgaIo.UgaGetPointerState = UgaGetPointerState;
ccd55824 814#endif
815
816
804405e7 817
818 drv->key_count = 0;
819 drv->key_rd = 0;
820 drv->key_wr = 0;
2ff79f2e 821 drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
822 drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
823 drv->RegisterdKeyCallback = NULL;
824 drv->RegisterdKeyCallbackContext = NULL;
825
826
804405e7 827 drv->display = XOpenDisplay (display_name);
828 if (drv->display == NULL)
829 {
830 fprintf (stderr, "uga: cannot connect to X server %s\n",
288a3c98 831 XDisplayName (display_name));
804405e7 832 free (drv);
833 return EFI_DEVICE_ERROR;
834 }
835 drv->screen = DefaultScreen (drv->display);
836 drv->visual = DefaultVisual (drv->display, drv->screen);
837 drv->win = XCreateSimpleWindow
288a3c98 838 (drv->display, RootWindow (drv->display, drv->screen),
839 0, 0, 4, 4, border_width,
840 WhitePixel (drv->display, drv->screen),
841 BlackPixel (drv->display, drv->screen));
804405e7 842
843 drv->depth = DefaultDepth (drv->display, drv->screen);
2ff79f2e 844 XDefineCursor (drv->display, drv->win, XCreateFontCursor (drv->display, XC_pirate));
804405e7 845
846 /* Compute title len and convert to Ascii. */
847 for (title_len = 0; Title[title_len] != 0; title_len++)
848 ;
849 {
850 char title[title_len + 1];
851 int i;
852 for (i = 0; i < title_len; i++)
853 title[i] = Title[i];
854 title[i] = 0;
855
856 XStoreName (drv->display, drv->win, title);
857 }
858
2ff79f2e 859 XSelectInput (drv->display, drv->win,
860 ExposureMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask );
804405e7 861 drv->gc = DefaultGC (drv->display, drv->screen);
862
863 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
864 return EFI_SUCCESS;
865}