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