]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
Updated per the latest changes
[mirror_edk2.git] / UnixPkg / Sec / UgaX11.c
CommitLineData
804405e7 1#include <sys/ipc.h>
2#include <sys/shm.h>
3#include <sys/dir.h>
4#include <stdio.h>
5#include <stdlib.h>
6
7#include "PiPei.h"
8#include "Protocol/UnixThunk.h"
9#include "Protocol/SimpleTextIn.h"
10#include "Protocol/UgaDraw.h"
11#include "Protocol/UnixUgaIo.h"
12#include <X11/Xlib.h>
13#include <X11/Xutil.h>
14#include <X11/Xos.h>
15#include <X11/extensions/XShm.h>
16#include <X11/keysym.h>
17
18#include <Guid/PeiPeCoffLoader.h>
19#include <Ppi/StatusCode.h>
20
21#include <Library/PeCoffLib.h>
22#include <Library/BaseLib.h>
23#include <Library/BaseMemoryLib.h>
24#include <Library/PrintLib.h>
25#include <Library/PcdLib.h>
26#include <Library/DebugLib.h>
27
28extern void msSleep (unsigned long Milliseconds);
29
30/* XQueryPointer */
31
32struct uga_drv_shift_mask
33{
34 unsigned char shift;
35 unsigned char size;
36 unsigned char csize;
37};
38
39#define NBR_KEYS 32
40typedef struct
41{
42 EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
43
44 Display *display;
45 int screen; /* values for window_size in main */
46 Window win;
47 GC gc;
48 Visual *visual;
49
50 int depth;
51 unsigned int width;
52 unsigned int height;
53 unsigned int line_bytes;
54 unsigned int pixel_shift;
55 unsigned char *image_data;
56
57 struct uga_drv_shift_mask r, g, b;
58
59 int use_shm;
60 XShmSegmentInfo xshm_info;
61 XImage *image;
62
63 unsigned int key_rd;
64 unsigned int key_wr;
65 unsigned int key_count;
66 EFI_INPUT_KEY keys[NBR_KEYS];
67} UGA_IO_PRIVATE;
68
7492c63d 69void
804405e7 70HandleEvents(UGA_IO_PRIVATE *drv);
71
7492c63d 72void
804405e7 73fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
74{
75 sm->shift = 0;
76 sm->size = 0;
77 while ((mask & 1) == 0)
78 {
79 mask >>= 1;
80 sm->shift++;
81 }
82 while (mask & 1)
83 {
84 sm->size++;
85 mask >>= 1;
86 }
87 sm->csize = 8 - sm->size;
88}
89
7492c63d 90int
804405e7 91TryCreateShmImage(UGA_IO_PRIVATE *drv)
92{
93 drv->image = XShmCreateImage (drv->display, drv->visual,
288a3c98 94 drv->depth, ZPixmap, NULL, &drv->xshm_info,
95 drv->width, drv->height);
804405e7 96 if (drv->image == NULL)
97 return 0;
98
99 switch (drv->image->bitmap_unit) {
100 case 32:
101 drv->pixel_shift = 2;
102 break;
103 case 16:
104 drv->pixel_shift = 1;
105 break;
106 case 8:
107 drv->pixel_shift = 0;
108 break;
109 }
110
111 drv->xshm_info.shmid = shmget
288a3c98 112 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
113 IPC_CREAT | 0777);
804405e7 114 if (drv->xshm_info.shmid < 0)
115 {
116 XDestroyImage(drv->image);
117 return 0;
118 }
119
120 drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
121 if(!drv->image_data)
122 {
123 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
124 XDestroyImage(drv->image);
125 return 0;
126 }
127 /* Can this fail ? */
128 shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
129
130 drv->xshm_info.shmaddr = (char*)drv->image_data;
131 drv->image->data = (char*)drv->image_data;
288a3c98 132
804405e7 133 if (!XShmAttach (drv->display, &drv->xshm_info))
134 {
135 shmdt (drv->image_data);
136 XDestroyImage(drv->image);
137 return 0;
138 }
139 return 1;
140}
141
804405e7 142EFI_STATUS
143UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
144{
145 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
146
147 if (drv == NULL)
148 return EFI_SUCCESS;
149 if (drv->image != NULL)
150 {
151 XDestroyImage(drv->image);
152
153 if (drv->use_shm)
288a3c98 154 shmdt (drv->image_data);
804405e7 155
156 drv->image_data = NULL;
157 drv->image = NULL;
158 }
159 XDestroyWindow(drv->display, drv->win);
160 XCloseDisplay(drv->display);
161 free(drv);
162 return EFI_SUCCESS;
163}
164
804405e7 165EFI_STATUS
166UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
167{
168 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
169 XSizeHints size_hints;
170
171 /* Destroy current buffer if created. */
172 if (drv->image != NULL)
173 {
174 XDestroyImage(drv->image);
175
176 if (drv->use_shm)
288a3c98 177 shmdt (drv->image_data);
804405e7 178
179 drv->image_data = NULL;
180 drv->image = NULL;
181 }
182
183 drv->width = Width;
184 drv->height = Height;
185 XResizeWindow (drv->display, drv->win, Width, Height);
186
187 /* Allocate image. */
288a3c98 188 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
189 drv->use_shm = 1;
190 } else {
191 drv->use_shm = 0;
192 if (drv->depth > 16)
193 drv->pixel_shift = 2;
194 else if (drv->depth > 8)
195 drv->pixel_shift = 1;
196 else
197 drv->pixel_shift = 0;
804405e7 198
199 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
200 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 201 ZPixmap, 0, (char *)drv->image_data,
202 drv->width, drv->height,
203 8 << drv->pixel_shift, 0);
804405e7 204 }
205 drv->line_bytes = drv->image->bytes_per_line;
206 fill_shift_mask (&drv->r, drv->image->red_mask);
207 fill_shift_mask (&drv->g, drv->image->green_mask);
208 fill_shift_mask (&drv->b, drv->image->blue_mask);
209
210 /* Set WM hints. */
211 size_hints.flags = PSize | PMinSize | PMaxSize;
212 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
213 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
214 XSetWMNormalHints (drv->display, drv->win, &size_hints);
215
216 XMapWindow (drv->display, drv->win);
217 HandleEvents(drv);
218 return EFI_SUCCESS;
219}
220
7492c63d 221void
804405e7 222handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
223{
224 KeySym keysym;
225 char str[4];
226 EFI_INPUT_KEY Key;
227 int res;
228
229 if (drv->key_count == NBR_KEYS)
230 return;
231
232 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
288a3c98 233 Key.ScanCode = 0;
804405e7 234 Key.UnicodeChar = 0;
288a3c98 235 switch (keysym) {
236 case XK_Home: Key.ScanCode = SCAN_HOME; break;
237 case XK_End: Key.ScanCode = SCAN_END; break;
238 case XK_Left: Key.ScanCode = SCAN_LEFT; break;
239 case XK_Right: Key.ScanCode = SCAN_RIGHT; break;
240 case XK_Up: Key.ScanCode = SCAN_UP; break;
241 case XK_Down: Key.ScanCode = SCAN_DOWN; break;
242 case XK_Delete: Key.ScanCode = SCAN_DELETE; break;
243 case XK_Insert: Key.ScanCode = SCAN_INSERT; break;
244 case XK_Page_Up: Key.ScanCode = SCAN_PAGE_UP; break;
245 case XK_Page_Down: Key.ScanCode = SCAN_PAGE_DOWN; break;
246 case XK_Escape: Key.ScanCode = SCAN_ESC; break;
247
248 case XK_F1: Key.ScanCode = SCAN_F1; break;
249 case XK_F2: Key.ScanCode = SCAN_F2; break;
250 case XK_F3: Key.ScanCode = SCAN_F3; break;
251 case XK_F4: Key.ScanCode = SCAN_F4; break;
252 case XK_F5: Key.ScanCode = SCAN_F5; break;
253 case XK_F6: Key.ScanCode = SCAN_F6; break;
254 case XK_F7: Key.ScanCode = SCAN_F7; break;
255 case XK_F8: Key.ScanCode = SCAN_F8; break;
256 case XK_F9: Key.ScanCode = SCAN_F9; break;
804405e7 257
258 default:
259 if (res == 1) {
260 Key.UnicodeChar = str[0];
261 } else {
262 return;
263 }
288a3c98 264 }
265
804405e7 266 drv->keys[drv->key_wr] = Key;
267 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
268 drv->key_count++;
269}
270
7492c63d 271void
804405e7 272Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
273{
274 if (drv->use_shm)
275 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 276 X, Y, X, Y, Width, Height, False);
804405e7 277 else
278 XPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 279 X, Y, X, Y, Width, Height);
280 XFlush(drv->display);
804405e7 281}
282
7492c63d 283void
804405e7 284HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
285{
286 switch (ev->type)
287 {
288 case Expose:
289 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
288a3c98 290 ev->xexpose.width, ev->xexpose.height);
804405e7 291 break;
292 case GraphicsExpose:
293 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
288a3c98 294 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
804405e7 295 break;
296 case KeyPress:
297 handleKeyEvent(drv, ev);
298 break;
299 case MappingNotify:
300 XRefreshKeyboardMapping(&ev->xmapping);
301 break;
302#if 0
303 case DestroyNotify:
304 XCloseDisplay (drv->display);
305 exit (1);
306 break;
307#endif
308 case NoExpose:
309 default:
310 break;
311 }
312}
313
7492c63d 314void
804405e7 315HandleEvents(UGA_IO_PRIVATE *drv)
316{
317 while (XPending(drv->display) != 0)
318 {
319 XEvent ev;
288a3c98 320
804405e7 321 XNextEvent (drv->display, &ev);
322 HandleEvent(drv, &ev);
323 }
324}
325
804405e7 326unsigned long
327UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
328{
329 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
330 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
331 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
332}
333
804405e7 334EFI_UGA_PIXEL
335UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
336{
337 EFI_UGA_PIXEL res;
338
339 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
340 /* FIXME: should round instead of truncate. */
341 res.Red = (val >> drv->r.shift) << drv->r.csize;
342 res.Green = (val >> drv->g.shift) << drv->g.csize;
343 res.Blue = (val >> drv->b.shift) << drv->b.csize;
344
345 return res;
346}
347
804405e7 348EFI_STATUS
349UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
350{
351 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
352 HandleEvents(drv);
353 if (drv->key_count != 0)
354 return EFI_SUCCESS;
355 else {
356 /* EFI is certainly polling. Be CPU-friendly. */
357 msSleep (20);
358 return EFI_NOT_READY;
359 }
360}
361
804405e7 362EFI_STATUS
363UgaGetKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_INPUT_KEY *key)
364{
365 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
366 EFI_STATUS status;
367
368 status = UgaCheckKey(UgaIo);
369 if (status != EFI_SUCCESS)
370 return status;
371
372 *key = drv->keys[drv->key_rd];
373 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
374 drv->key_count--;
375 return EFI_SUCCESS;
376}
377
288a3c98 378EFI_STATUS
804405e7 379UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
288a3c98 380 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
381 IN EFI_UGA_BLT_OPERATION BltOperation,
382 IN UINTN SourceX,
383 IN UINTN SourceY,
384 IN UINTN DestinationX,
385 IN UINTN DestinationY,
386 IN UINTN Width,
387 IN UINTN Height,
388 IN UINTN Delta OPTIONAL
389 )
804405e7 390{
391 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
288a3c98 392 UINTN DstY;
393 UINTN SrcY;
804405e7 394 UINTN DstX;
395 UINTN SrcX;
396 UINTN Index;
288a3c98 397 EFI_UGA_PIXEL *Blt;
804405e7 398 UINT8 *Dst;
399 UINT8 *Src;
400 UINTN Nbr;
401 unsigned long Color;
402
403 //
404 // Check bounds
405 //
406 if (BltOperation == EfiUgaVideoToBltBuffer
288a3c98 407 || BltOperation == EfiUgaVideoToVideo) {
408 //
804405e7 409 // Source is Video.
288a3c98 410 //
411 if (SourceY + Height > Private->height) {
412 return EFI_INVALID_PARAMETER;
413 }
414
415 if (SourceX + Width > Private->width) {
416 return EFI_INVALID_PARAMETER;
417 }
804405e7 418 }
419
420 if (BltOperation == EfiUgaBltBufferToVideo
421 || BltOperation == EfiUgaVideoToVideo
288a3c98 422 || BltOperation == EfiUgaVideoFill) {
423 //
424 // Destination is Video
425 //
426 if (DestinationY + Height > Private->height) {
427 return EFI_INVALID_PARAMETER;
428 }
429
430 if (DestinationX + Width > Private->width) {
431 return EFI_INVALID_PARAMETER;
432 }
804405e7 433 }
434
288a3c98 435 switch (BltOperation) {
804405e7 436 case EfiUgaVideoToBltBuffer:
288a3c98 437 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (DestinationY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
804405e7 438 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 439 for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
804405e7 440 for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
288a3c98 441 *Blt++ = UgaColorToPixel(Private,
442 XGetPixel(Private->image, SrcX, SrcY));
804405e7 443 }
444 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
288a3c98 445 }
804405e7 446 break;
288a3c98 447 case EfiUgaBltBufferToVideo:
448 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (SourceY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
804405e7 449 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 450 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
451 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
452 XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
453 Blt++;
804405e7 454 }
455 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
456 }
457 break;
288a3c98 458 case EfiUgaVideoToVideo:
804405e7 459 Dst = Private->image_data + (DestinationX << Private->pixel_shift)
460 + DestinationY * Private->line_bytes;
461 Src = Private->image_data + (SourceX << Private->pixel_shift)
462 + SourceY * Private->line_bytes;
463 Nbr = Width << Private->pixel_shift;
288a3c98 464 if (DestinationY < SourceY) {
804405e7 465 for (Index = 0; Index < Height; Index++) {
288a3c98 466 memcpy (Dst, Src, Nbr);
467 Dst += Private->line_bytes;
468 Src += Private->line_bytes;
804405e7 469 }
470 }
471 else {
472 Dst += (Height - 1) * Private->line_bytes;
473 Src += (Height - 1) * Private->line_bytes;
474 for (Index = 0; Index < Height; Index++) {
288a3c98 475 //
476 // Source and Destination Y may be equal, therefore Dst and Src may
477 // overlap.
478 //
479 memmove (Dst, Src, Nbr);
480 Dst -= Private->line_bytes;
481 Src -= Private->line_bytes;
804405e7 482 }
483 }
484 break;
485 case EfiUgaVideoFill:
486 Color = UgaPixelToColor(Private, *BltBuffer);
288a3c98 487 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
804405e7 488 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
288a3c98 489 XPutPixel(Private->image, DstX, DstY, Color);
804405e7 490 }
288a3c98 491 }
804405e7 492 break;
493 default:
288a3c98 494 return EFI_INVALID_PARAMETER;
804405e7 495 }
496
497 //
498 // Refresh screen.
499 //
288a3c98 500 switch (BltOperation) {
501 case EfiUgaVideoToVideo:
804405e7 502 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
288a3c98 503 SourceX, SourceY, Width, Height, DestinationX, DestinationY);
804405e7 504 while (1) {
505 XEvent ev;
288a3c98 506
804405e7 507 XNextEvent (Private->display, &ev);
508 HandleEvent(Private, &ev);
509 if (ev.type == NoExpose || ev.type == GraphicsExpose)
288a3c98 510 break;
804405e7 511 }
512 break;
513 case EfiUgaVideoFill:
514 Color = UgaPixelToColor(Private, *BltBuffer);
515 XSetForeground(Private->display, Private->gc, Color);
516 XFillRectangle(Private->display, Private->win, Private->gc,
288a3c98 517 DestinationX, DestinationY, Width, Height);
518 XFlush(Private->display);
804405e7 519 break;
288a3c98 520 case EfiUgaBltBufferToVideo:
804405e7 521 Redraw(Private, DestinationX, DestinationY, Width, Height);
522 break;
523 default:
524 break;
525 }
526 return EFI_SUCCESS;
527}
528
529EFI_STATUS
530UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
531{
532 UGA_IO_PRIVATE *drv;
533 unsigned int border_width = 0;
534 char *display_name = NULL;
535 int title_len;
536
537 drv = (UGA_IO_PRIVATE *)
538 calloc (1, sizeof (UGA_IO_PRIVATE));
539 if (drv == NULL)
540 return EFI_OUT_OF_RESOURCES;
541
542 drv->UgaIo.UgaClose = UgaClose;
543 drv->UgaIo.UgaSize = UgaSize;
544 drv->UgaIo.UgaCheckKey = UgaCheckKey;
545 drv->UgaIo.UgaGetKey = UgaGetKey;
546 drv->UgaIo.UgaBlt = UgaBlt;
547
548 drv->key_count = 0;
549 drv->key_rd = 0;
550 drv->key_wr = 0;
551 drv->display = XOpenDisplay (display_name);
552 if (drv->display == NULL)
553 {
554 fprintf (stderr, "uga: cannot connect to X server %s\n",
288a3c98 555 XDisplayName (display_name));
804405e7 556 free (drv);
557 return EFI_DEVICE_ERROR;
558 }
559 drv->screen = DefaultScreen (drv->display);
560 drv->visual = DefaultVisual (drv->display, drv->screen);
561 drv->win = XCreateSimpleWindow
288a3c98 562 (drv->display, RootWindow (drv->display, drv->screen),
563 0, 0, 4, 4, border_width,
564 WhitePixel (drv->display, drv->screen),
565 BlackPixel (drv->display, drv->screen));
804405e7 566
567 drv->depth = DefaultDepth (drv->display, drv->screen);
568
569 /* Compute title len and convert to Ascii. */
570 for (title_len = 0; Title[title_len] != 0; title_len++)
571 ;
572 {
573 char title[title_len + 1];
574 int i;
575 for (i = 0; i < title_len; i++)
576 title[i] = Title[i];
577 title[i] = 0;
578
579 XStoreName (drv->display, drv->win, title);
580 }
581
582 XSelectInput (drv->display, drv->win,
288a3c98 583 ExposureMask | KeyPressMask);
804405e7 584 drv->gc = DefaultGC (drv->display, drv->screen);
585
586 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
587 return EFI_SUCCESS;
588}