]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
Adding Simple Pointer, GOP, SimpleTextInEx, and Networking protocols to the emulator...
[mirror_edk2.git] / UnixPkg / Sec / UgaX11.c
CommitLineData
ccd55824 1/*++
2
f9b8ab56 3Copyright (c) 2004 - 2009, 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--*/
14
804405e7 15#include <sys/ipc.h>
16#include <sys/shm.h>
804405e7 17#include <stdio.h>
18#include <stdlib.h>
19
2ff79f2e 20#include <PiPei.h>
21#include <Protocol/SimplePointer.h>
22#include <Protocol/SimpleTextIn.h>
23#include <Protocol/SimpleTextInEx.h>
24#include <Protocol/UgaDraw.h>
804405e7 25#include <X11/Xlib.h>
26#include <X11/Xutil.h>
27#include <X11/Xos.h>
28#include <X11/extensions/XShm.h>
29#include <X11/keysym.h>
2ff79f2e 30#include <X11/cursorfont.h>
31
32#include <Protocol/UnixThunk.h>
33#include <Protocol/UnixUgaIo.h>
804405e7 34
804405e7 35#include <Ppi/StatusCode.h>
36
37#include <Library/PeCoffLib.h>
38#include <Library/BaseLib.h>
39#include <Library/BaseMemoryLib.h>
40#include <Library/PrintLib.h>
41#include <Library/PcdLib.h>
42#include <Library/DebugLib.h>
43
2ff79f2e 44#include "Gasket.h"
45#include "SecMain.h"
46
47
804405e7 48extern void msSleep (unsigned long Milliseconds);
49
50/* XQueryPointer */
51
2ff79f2e 52struct uga_drv_shift_mask {
804405e7 53 unsigned char shift;
54 unsigned char size;
55 unsigned char csize;
56};
57
58#define NBR_KEYS 32
2ff79f2e 59typedef struct {
804405e7 60 EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
61
62 Display *display;
63 int screen; /* values for window_size in main */
64 Window win;
65 GC gc;
66 Visual *visual;
67
68 int depth;
69 unsigned int width;
70 unsigned int height;
71 unsigned int line_bytes;
72 unsigned int pixel_shift;
73 unsigned char *image_data;
74
75 struct uga_drv_shift_mask r, g, b;
76
77 int use_shm;
78 XShmSegmentInfo xshm_info;
79 XImage *image;
80
81 unsigned int key_rd;
82 unsigned int key_wr;
83 unsigned int key_count;
2ff79f2e 84 EFI_KEY_DATA keys[NBR_KEYS];
85
86 EFI_KEY_STATE KeyState;
87
88 UGA_REGISTER_KEY_NOTIFY_CALLBACK RegisterdKeyCallback;
89 VOID *RegisterdKeyCallbackContext;
90
91 int previous_x;
92 int previous_y;
93 EFI_SIMPLE_POINTER_STATE pointer_state;
94 int pointer_state_changed;
804405e7 95} UGA_IO_PRIVATE;
96
7492c63d 97void
804405e7 98HandleEvents(UGA_IO_PRIVATE *drv);
99
7492c63d 100void
804405e7 101fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
102{
103 sm->shift = 0;
104 sm->size = 0;
105 while ((mask & 1) == 0)
106 {
107 mask >>= 1;
108 sm->shift++;
109 }
110 while (mask & 1)
111 {
112 sm->size++;
113 mask >>= 1;
114 }
115 sm->csize = 8 - sm->size;
116}
117
7492c63d 118int
804405e7 119TryCreateShmImage(UGA_IO_PRIVATE *drv)
120{
121 drv->image = XShmCreateImage (drv->display, drv->visual,
288a3c98 122 drv->depth, ZPixmap, NULL, &drv->xshm_info,
123 drv->width, drv->height);
804405e7 124 if (drv->image == NULL)
125 return 0;
126
127 switch (drv->image->bitmap_unit) {
128 case 32:
129 drv->pixel_shift = 2;
130 break;
131 case 16:
132 drv->pixel_shift = 1;
133 break;
134 case 8:
135 drv->pixel_shift = 0;
136 break;
137 }
138
139 drv->xshm_info.shmid = shmget
288a3c98 140 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
141 IPC_CREAT | 0777);
7ee3b613
A
142 if (drv->xshm_info.shmid < 0) {
143 XDestroyImage(drv->image);
144 return 0;
145 }
804405e7 146
147 drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
7ee3b613
A
148 if(!drv->image_data) {
149 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
150 XDestroyImage(drv->image);
151 return 0;
152 }
ccd55824 153
154#ifndef __APPLE__
155 //
156 // This closes shared memory in real time on OS X. Only closes after folks quit using
157 // it on Linux.
158 //
804405e7 159 /* Can this fail ? */
160 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
ccd55824 161#endif
804405e7 162
163 drv->xshm_info.shmaddr = (char*)drv->image_data;
164 drv->image->data = (char*)drv->image_data;
288a3c98 165
7ee3b613
A
166 if (!XShmAttach (drv->display, &drv->xshm_info)) {
167 shmdt (drv->image_data);
168 XDestroyImage(drv->image);
169 return 0;
170 }
804405e7 171 return 1;
172}
173
804405e7 174EFI_STATUS
175UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
176{
177 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
178
179 if (drv == NULL)
180 return EFI_SUCCESS;
181 if (drv->image != NULL)
182 {
183 XDestroyImage(drv->image);
184
185 if (drv->use_shm)
288a3c98 186 shmdt (drv->image_data);
804405e7 187
188 drv->image_data = NULL;
189 drv->image = NULL;
190 }
191 XDestroyWindow(drv->display, drv->win);
192 XCloseDisplay(drv->display);
ccd55824 193
194#ifdef __APPLE__
195 // Free up the shared memory
196 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
197#endif
198
804405e7 199 free(drv);
200 return EFI_SUCCESS;
201}
202
804405e7 203EFI_STATUS
204UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
205{
206 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
207 XSizeHints size_hints;
208
209 /* Destroy current buffer if created. */
210 if (drv->image != NULL)
211 {
7d28e82d 212 /* Before destroy buffer, need to make sure the buffer available for access. */
804405e7 213 XDestroyImage(drv->image);
214
215 if (drv->use_shm)
288a3c98 216 shmdt (drv->image_data);
804405e7 217
218 drv->image_data = NULL;
219 drv->image = NULL;
220 }
221
222 drv->width = Width;
223 drv->height = Height;
224 XResizeWindow (drv->display, drv->win, Width, Height);
225
226 /* Allocate image. */
288a3c98 227 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
228 drv->use_shm = 1;
229 } else {
230 drv->use_shm = 0;
231 if (drv->depth > 16)
232 drv->pixel_shift = 2;
233 else if (drv->depth > 8)
234 drv->pixel_shift = 1;
235 else
236 drv->pixel_shift = 0;
804405e7 237
238 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
239 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 240 ZPixmap, 0, (char *)drv->image_data,
241 drv->width, drv->height,
242 8 << drv->pixel_shift, 0);
804405e7 243 }
244 drv->line_bytes = drv->image->bytes_per_line;
245 fill_shift_mask (&drv->r, drv->image->red_mask);
246 fill_shift_mask (&drv->g, drv->image->green_mask);
247 fill_shift_mask (&drv->b, drv->image->blue_mask);
248
249 /* Set WM hints. */
250 size_hints.flags = PSize | PMinSize | PMaxSize;
251 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
252 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
253 XSetWMNormalHints (drv->display, drv->win, &size_hints);
254
255 XMapWindow (drv->display, drv->win);
256 HandleEvents(drv);
257 return EFI_SUCCESS;
258}
259
7492c63d 260void
804405e7 261handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
262{
263 KeySym keysym;
264 char str[4];
2ff79f2e 265 EFI_KEY_DATA KeyData;
804405e7 266 int res;
267
268 if (drv->key_count == NBR_KEYS)
269 return;
270
271 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
2ff79f2e 272 KeyData.Key.ScanCode = 0;
273 KeyData.Key.UnicodeChar = 0;
274 KeyData.KeyState.KeyShiftState = 0;
275
276 //
277 // KeyRelease is not supported (on Mac) so we can not easily implement Ex functions.
278 // If a modifier key is hit by its self we get a keysym. If a modfifier and key is hit
279 // we get the state bit set and keysym is the modified key.
280 //
281 // We use lack of state bits being set to clear ToggleState and KeyShiftState. We can
282 // also use the stat bits to set ToggleState and KeyShiftState.
283 // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs
284 //
285 if ((ev->xkey.state & LockMask) == 0) {
286 drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
287 } else {
288 drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
289 }
290
291 if ((ev->xkey.state & ControlMask) == 0) {
292 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED);
293 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_CONTROL_PRESSED) == 0) {
294 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
295 }
296
297 if ((ev->xkey.state & ShiftMask) == 0) {
298 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED);
299 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_SHIFT_PRESSED) == 0) {
300 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
301 }
302
303 if ((ev->xkey.state & Mod2Mask) == 0) {
304 drv->KeyState.KeyShiftState &= ~(EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED);
305 } else if ((drv->KeyState.KeyShiftState & EFI_RIGHT_LOGO_PRESSED) == 0) {
306 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
307 }
308
309 if ((ev->xkey.state & 0x2000) == 0) {
310 drv->KeyState.KeyShiftState &= ~(EFI_LEFT_ALT_PRESSED);
311 } else {
312 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
313 }
314
315
288a3c98 316 switch (keysym) {
2ff79f2e 317 case XK_Control_R:
318 drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
319 break;
320 case XK_Control_L:
321 drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
322 break;
323
324 case XK_Shift_R:
325 drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
326 break;
327 case XK_Shift_L:
328 drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
329 break;
330
331 case XK_Mode_switch:
332 drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
333 break;
334
335 case XK_Meta_R:
336 drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
337 break;
338 case XK_Meta_L:
339 drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
340 break;
341
342 case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break;
343 case XK_End: KeyData.Key.ScanCode = SCAN_END; break;
344 case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break;
345 case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break;
346 case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break;
347 case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break;
348 case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break;
349 case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break;
350 case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break;
351 case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break;
352 case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break;
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 );
397 drv->previous_x = ev->xmotion.x;
398 drv->pointer_state_changed = 1;
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;
405 drv->pointer_state_changed = 1;
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 );
417 drv->pointer_state.LeftButton = Pressed;
418 }
419 if ( ev->xbutton.button == Button2 )
420 {
421 drv->pointer_state_changed = ( drv->pointer_state.RightButton != Pressed );
422 drv->pointer_state.RightButton = Pressed;
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);
464 break;
465 case ButtonRelease:
466 handleMouseDown(drv, ev, FALSE);
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}