]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
Fix file headers
[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
804405e7 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
27extern void msSleep (unsigned long Milliseconds);
28
29/* XQueryPointer */
30
31struct uga_drv_shift_mask
32{
33 unsigned char shift;
34 unsigned char size;
35 unsigned char csize;
36};
37
38#define NBR_KEYS 32
39typedef 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
7492c63d 68void
804405e7 69HandleEvents(UGA_IO_PRIVATE *drv);
70
7492c63d 71void
804405e7 72fill_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
7492c63d 89int
804405e7 90TryCreateShmImage(UGA_IO_PRIVATE *drv)
91{
92 drv->image = XShmCreateImage (drv->display, drv->visual,
288a3c98 93 drv->depth, ZPixmap, NULL, &drv->xshm_info,
94 drv->width, drv->height);
804405e7 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
288a3c98 111 (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
112 IPC_CREAT | 0777);
804405e7 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;
288a3c98 131
804405e7 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
804405e7 141EFI_STATUS
142UgaClose (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)
288a3c98 153 shmdt (drv->image_data);
804405e7 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
804405e7 164EFI_STATUS
165UgaSize(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 {
7d28e82d 173 /* Before destroy buffer, need to make sure the buffer available for access. */
804405e7 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}