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