]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[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
69static void
70HandleEvents(UGA_IO_PRIVATE *drv);
71
72static void
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
90static int
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
142static
143EFI_STATUS
144UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
145{
146 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
147
148 if (drv == NULL)
149 return EFI_SUCCESS;
150 if (drv->image != NULL)
151 {
152 XDestroyImage(drv->image);
153
154 if (drv->use_shm)
288a3c98 155 shmdt (drv->image_data);
804405e7 156
157 drv->image_data = NULL;
158 drv->image = NULL;
159 }
160 XDestroyWindow(drv->display, drv->win);
161 XCloseDisplay(drv->display);
162 free(drv);
163 return EFI_SUCCESS;
164}
165
166static
167EFI_STATUS
168UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
169{
170 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
171 XSizeHints size_hints;
172
173 /* Destroy current buffer if created. */
174 if (drv->image != NULL)
175 {
176 XDestroyImage(drv->image);
177
178 if (drv->use_shm)
288a3c98 179 shmdt (drv->image_data);
804405e7 180
181 drv->image_data = NULL;
182 drv->image = NULL;
183 }
184
185 drv->width = Width;
186 drv->height = Height;
187 XResizeWindow (drv->display, drv->win, Width, Height);
188
189 /* Allocate image. */
288a3c98 190 if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv)) {
191 drv->use_shm = 1;
192 } else {
193 drv->use_shm = 0;
194 if (drv->depth > 16)
195 drv->pixel_shift = 2;
196 else if (drv->depth > 8)
197 drv->pixel_shift = 1;
198 else
199 drv->pixel_shift = 0;
804405e7 200
201 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
202 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 203 ZPixmap, 0, (char *)drv->image_data,
204 drv->width, drv->height,
205 8 << drv->pixel_shift, 0);
804405e7 206 }
207 drv->line_bytes = drv->image->bytes_per_line;
208 fill_shift_mask (&drv->r, drv->image->red_mask);
209 fill_shift_mask (&drv->g, drv->image->green_mask);
210 fill_shift_mask (&drv->b, drv->image->blue_mask);
211
212 /* Set WM hints. */
213 size_hints.flags = PSize | PMinSize | PMaxSize;
214 size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
215 size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
216 XSetWMNormalHints (drv->display, drv->win, &size_hints);
217
218 XMapWindow (drv->display, drv->win);
219 HandleEvents(drv);
220 return EFI_SUCCESS;
221}
222
223static void
224handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
225{
226 KeySym keysym;
227 char str[4];
228 EFI_INPUT_KEY Key;
229 int res;
230
231 if (drv->key_count == NBR_KEYS)
232 return;
233
234 res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
288a3c98 235 Key.ScanCode = 0;
804405e7 236 Key.UnicodeChar = 0;
288a3c98 237 switch (keysym) {
238 case XK_Home: Key.ScanCode = SCAN_HOME; break;
239 case XK_End: Key.ScanCode = SCAN_END; break;
240 case XK_Left: Key.ScanCode = SCAN_LEFT; break;
241 case XK_Right: Key.ScanCode = SCAN_RIGHT; break;
242 case XK_Up: Key.ScanCode = SCAN_UP; break;
243 case XK_Down: Key.ScanCode = SCAN_DOWN; break;
244 case XK_Delete: Key.ScanCode = SCAN_DELETE; break;
245 case XK_Insert: Key.ScanCode = SCAN_INSERT; break;
246 case XK_Page_Up: Key.ScanCode = SCAN_PAGE_UP; break;
247 case XK_Page_Down: Key.ScanCode = SCAN_PAGE_DOWN; break;
248 case XK_Escape: Key.ScanCode = SCAN_ESC; break;
249
250 case XK_F1: Key.ScanCode = SCAN_F1; break;
251 case XK_F2: Key.ScanCode = SCAN_F2; break;
252 case XK_F3: Key.ScanCode = SCAN_F3; break;
253 case XK_F4: Key.ScanCode = SCAN_F4; break;
254 case XK_F5: Key.ScanCode = SCAN_F5; break;
255 case XK_F6: Key.ScanCode = SCAN_F6; break;
256 case XK_F7: Key.ScanCode = SCAN_F7; break;
257 case XK_F8: Key.ScanCode = SCAN_F8; break;
258 case XK_F9: Key.ScanCode = SCAN_F9; break;
804405e7 259
260 default:
261 if (res == 1) {
262 Key.UnicodeChar = str[0];
263 } else {
264 return;
265 }
288a3c98 266 }
267
804405e7 268 drv->keys[drv->key_wr] = Key;
269 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
270 drv->key_count++;
271}
272
273static void
274Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
275{
276 if (drv->use_shm)
277 XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 278 X, Y, X, Y, Width, Height, False);
804405e7 279 else
280 XPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 281 X, Y, X, Y, Width, Height);
282 XFlush(drv->display);
804405e7 283}
284
285static void
286HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
287{
288 switch (ev->type)
289 {
290 case Expose:
291 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
288a3c98 292 ev->xexpose.width, ev->xexpose.height);
804405e7 293 break;
294 case GraphicsExpose:
295 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
288a3c98 296 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
804405e7 297 break;
298 case KeyPress:
299 handleKeyEvent(drv, ev);
300 break;
301 case MappingNotify:
302 XRefreshKeyboardMapping(&ev->xmapping);
303 break;
304#if 0
305 case DestroyNotify:
306 XCloseDisplay (drv->display);
307 exit (1);
308 break;
309#endif
310 case NoExpose:
311 default:
312 break;
313 }
314}
315
316static void
317HandleEvents(UGA_IO_PRIVATE *drv)
318{
319 while (XPending(drv->display) != 0)
320 {
321 XEvent ev;
288a3c98 322
804405e7 323 XNextEvent (drv->display, &ev);
324 HandleEvent(drv, &ev);
325 }
326}
327
328static
329unsigned long
330UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
331{
332 return ((pixel.Red >> drv->r.csize) << drv->r.shift)
333 | ((pixel.Green >> drv->g.csize) << drv->g.shift)
334 | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
335}
336
337static
338EFI_UGA_PIXEL
339UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
340{
341 EFI_UGA_PIXEL res;
342
343 memset (&res, 0, sizeof (EFI_UGA_PIXEL));
344 /* FIXME: should round instead of truncate. */
345 res.Red = (val >> drv->r.shift) << drv->r.csize;
346 res.Green = (val >> drv->g.shift) << drv->g.csize;
347 res.Blue = (val >> drv->b.shift) << drv->b.csize;
348
349 return res;
350}
351
352static
353EFI_STATUS
354UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
355{
356 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
357 HandleEvents(drv);
358 if (drv->key_count != 0)
359 return EFI_SUCCESS;
360 else {
361 /* EFI is certainly polling. Be CPU-friendly. */
362 msSleep (20);
363 return EFI_NOT_READY;
364 }
365}
366
367static
368EFI_STATUS
369UgaGetKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_INPUT_KEY *key)
370{
371 UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
372 EFI_STATUS status;
373
374 status = UgaCheckKey(UgaIo);
375 if (status != EFI_SUCCESS)
376 return status;
377
378 *key = drv->keys[drv->key_rd];
379 drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
380 drv->key_count--;
381 return EFI_SUCCESS;
382}
383
288a3c98 384EFI_STATUS
804405e7 385UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
288a3c98 386 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
387 IN EFI_UGA_BLT_OPERATION BltOperation,
388 IN UINTN SourceX,
389 IN UINTN SourceY,
390 IN UINTN DestinationX,
391 IN UINTN DestinationY,
392 IN UINTN Width,
393 IN UINTN Height,
394 IN UINTN Delta OPTIONAL
395 )
804405e7 396{
397 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
288a3c98 398 UINTN DstY;
399 UINTN SrcY;
804405e7 400 UINTN DstX;
401 UINTN SrcX;
402 UINTN Index;
288a3c98 403 EFI_UGA_PIXEL *Blt;
804405e7 404 UINT8 *Dst;
405 UINT8 *Src;
406 UINTN Nbr;
407 unsigned long Color;
408
409 //
410 // Check bounds
411 //
412 if (BltOperation == EfiUgaVideoToBltBuffer
288a3c98 413 || BltOperation == EfiUgaVideoToVideo) {
414 //
804405e7 415 // Source is Video.
288a3c98 416 //
417 if (SourceY + Height > Private->height) {
418 return EFI_INVALID_PARAMETER;
419 }
420
421 if (SourceX + Width > Private->width) {
422 return EFI_INVALID_PARAMETER;
423 }
804405e7 424 }
425
426 if (BltOperation == EfiUgaBltBufferToVideo
427 || BltOperation == EfiUgaVideoToVideo
288a3c98 428 || BltOperation == EfiUgaVideoFill) {
429 //
430 // Destination is Video
431 //
432 if (DestinationY + Height > Private->height) {
433 return EFI_INVALID_PARAMETER;
434 }
435
436 if (DestinationX + Width > Private->width) {
437 return EFI_INVALID_PARAMETER;
438 }
804405e7 439 }
440
288a3c98 441 switch (BltOperation) {
804405e7 442 case EfiUgaVideoToBltBuffer:
288a3c98 443 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (DestinationY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
804405e7 444 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 445 for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
804405e7 446 for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
288a3c98 447 *Blt++ = UgaColorToPixel(Private,
448 XGetPixel(Private->image, SrcX, SrcY));
804405e7 449 }
450 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
288a3c98 451 }
804405e7 452 break;
288a3c98 453 case EfiUgaBltBufferToVideo:
454 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (SourceY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
804405e7 455 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 456 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
457 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
458 XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
459 Blt++;
804405e7 460 }
461 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
462 }
463 break;
288a3c98 464 case EfiUgaVideoToVideo:
804405e7 465 Dst = Private->image_data + (DestinationX << Private->pixel_shift)
466 + DestinationY * Private->line_bytes;
467 Src = Private->image_data + (SourceX << Private->pixel_shift)
468 + SourceY * Private->line_bytes;
469 Nbr = Width << Private->pixel_shift;
288a3c98 470 if (DestinationY < SourceY) {
804405e7 471 for (Index = 0; Index < Height; Index++) {
288a3c98 472 memcpy (Dst, Src, Nbr);
473 Dst += Private->line_bytes;
474 Src += Private->line_bytes;
804405e7 475 }
476 }
477 else {
478 Dst += (Height - 1) * Private->line_bytes;
479 Src += (Height - 1) * Private->line_bytes;
480 for (Index = 0; Index < Height; Index++) {
288a3c98 481 //
482 // Source and Destination Y may be equal, therefore Dst and Src may
483 // overlap.
484 //
485 memmove (Dst, Src, Nbr);
486 Dst -= Private->line_bytes;
487 Src -= Private->line_bytes;
804405e7 488 }
489 }
490 break;
491 case EfiUgaVideoFill:
492 Color = UgaPixelToColor(Private, *BltBuffer);
288a3c98 493 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
804405e7 494 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
288a3c98 495 XPutPixel(Private->image, DstX, DstY, Color);
804405e7 496 }
288a3c98 497 }
804405e7 498 break;
499 default:
288a3c98 500 return EFI_INVALID_PARAMETER;
804405e7 501 }
502
503 //
504 // Refresh screen.
505 //
288a3c98 506 switch (BltOperation) {
507 case EfiUgaVideoToVideo:
804405e7 508 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
288a3c98 509 SourceX, SourceY, Width, Height, DestinationX, DestinationY);
804405e7 510 while (1) {
511 XEvent ev;
288a3c98 512
804405e7 513 XNextEvent (Private->display, &ev);
514 HandleEvent(Private, &ev);
515 if (ev.type == NoExpose || ev.type == GraphicsExpose)
288a3c98 516 break;
804405e7 517 }
518 break;
519 case EfiUgaVideoFill:
520 Color = UgaPixelToColor(Private, *BltBuffer);
521 XSetForeground(Private->display, Private->gc, Color);
522 XFillRectangle(Private->display, Private->win, Private->gc,
288a3c98 523 DestinationX, DestinationY, Width, Height);
524 XFlush(Private->display);
804405e7 525 break;
288a3c98 526 case EfiUgaBltBufferToVideo:
804405e7 527 Redraw(Private, DestinationX, DestinationY, Width, Height);
528 break;
529 default:
530 break;
531 }
532 return EFI_SUCCESS;
533}
534
535EFI_STATUS
536UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
537{
538 UGA_IO_PRIVATE *drv;
539 unsigned int border_width = 0;
540 char *display_name = NULL;
541 int title_len;
542
543 drv = (UGA_IO_PRIVATE *)
544 calloc (1, sizeof (UGA_IO_PRIVATE));
545 if (drv == NULL)
546 return EFI_OUT_OF_RESOURCES;
547
548 drv->UgaIo.UgaClose = UgaClose;
549 drv->UgaIo.UgaSize = UgaSize;
550 drv->UgaIo.UgaCheckKey = UgaCheckKey;
551 drv->UgaIo.UgaGetKey = UgaGetKey;
552 drv->UgaIo.UgaBlt = UgaBlt;
553
554 drv->key_count = 0;
555 drv->key_rd = 0;
556 drv->key_wr = 0;
557 drv->display = XOpenDisplay (display_name);
558 if (drv->display == NULL)
559 {
560 fprintf (stderr, "uga: cannot connect to X server %s\n",
288a3c98 561 XDisplayName (display_name));
804405e7 562 free (drv);
563 return EFI_DEVICE_ERROR;
564 }
565 drv->screen = DefaultScreen (drv->display);
566 drv->visual = DefaultVisual (drv->display, drv->screen);
567 drv->win = XCreateSimpleWindow
288a3c98 568 (drv->display, RootWindow (drv->display, drv->screen),
569 0, 0, 4, 4, border_width,
570 WhitePixel (drv->display, drv->screen),
571 BlackPixel (drv->display, drv->screen));
804405e7 572
573 drv->depth = DefaultDepth (drv->display, drv->screen);
574
575 /* Compute title len and convert to Ascii. */
576 for (title_len = 0; Title[title_len] != 0; title_len++)
577 ;
578 {
579 char title[title_len + 1];
580 int i;
581 for (i = 0; i < title_len; i++)
582 title[i] = Title[i];
583 title[i] = 0;
584
585 XStoreName (drv->display, drv->win, title);
586 }
587
588 XSelectInput (drv->display, drv->win,
288a3c98 589 ExposureMask | KeyPressMask);
804405e7 590 drv->gc = DefaultGC (drv->display, drv->screen);
591
592 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
593 return EFI_SUCCESS;
594}