]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/UgaX11.c
sync comments, fix function header, rename variable name to follow coding style.
[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 <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
28 extern void msSleep (unsigned long Milliseconds);
29
30 /* XQueryPointer */
31
32 struct uga_drv_shift_mask
33 {
34 unsigned char shift;
35 unsigned char size;
36 unsigned char csize;
37 };
38
39 #define NBR_KEYS 32
40 typedef 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
69 void
70 HandleEvents(UGA_IO_PRIVATE *drv);
71
72 void
73 fill_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
90 int
91 TryCreateShmImage(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
142 EFI_STATUS
143 UgaClose (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)
154 shmdt (drv->image_data);
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
165 EFI_STATUS
166 UgaSize(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)
177 shmdt (drv->image_data);
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. */
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;
198
199 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
200 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
201 ZPixmap, 0, (char *)drv->image_data,
202 drv->width, drv->height,
203 8 << drv->pixel_shift, 0);
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
221 void
222 handleKeyEvent(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);
233 Key.ScanCode = 0;
234 Key.UnicodeChar = 0;
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;
257
258 default:
259 if (res == 1) {
260 Key.UnicodeChar = str[0];
261 } else {
262 return;
263 }
264 }
265
266 drv->keys[drv->key_wr] = Key;
267 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
268 drv->key_count++;
269 }
270
271 void
272 Redraw(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,
276 X, Y, X, Y, Width, Height, False);
277 else
278 XPutImage (drv->display, drv->win, drv->gc, drv->image,
279 X, Y, X, Y, Width, Height);
280 XFlush(drv->display);
281 }
282
283 void
284 HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
285 {
286 switch (ev->type)
287 {
288 case Expose:
289 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
290 ev->xexpose.width, ev->xexpose.height);
291 break;
292 case GraphicsExpose:
293 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
294 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
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
314 void
315 HandleEvents(UGA_IO_PRIVATE *drv)
316 {
317 while (XPending(drv->display) != 0)
318 {
319 XEvent ev;
320
321 XNextEvent (drv->display, &ev);
322 HandleEvent(drv, &ev);
323 }
324 }
325
326 unsigned long
327 UgaPixelToColor (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
334 EFI_UGA_PIXEL
335 UgaColorToPixel (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
348 EFI_STATUS
349 UgaCheckKey(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
362 EFI_STATUS
363 UgaGetKey(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
378 EFI_STATUS
379 UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
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 )
390 {
391 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
392 UINTN DstY;
393 UINTN SrcY;
394 UINTN DstX;
395 UINTN SrcX;
396 UINTN Index;
397 EFI_UGA_PIXEL *Blt;
398 UINT8 *Dst;
399 UINT8 *Src;
400 UINTN Nbr;
401 unsigned long Color;
402
403 //
404 // Check bounds
405 //
406 if (BltOperation == EfiUgaVideoToBltBuffer
407 || BltOperation == EfiUgaVideoToVideo) {
408 //
409 // Source is Video.
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 }
418 }
419
420 if (BltOperation == EfiUgaBltBufferToVideo
421 || BltOperation == EfiUgaVideoToVideo
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 }
433 }
434
435 switch (BltOperation) {
436 case EfiUgaVideoToBltBuffer:
437 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (DestinationY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
438 Delta -= Width * sizeof (EFI_UGA_PIXEL);
439 for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
440 for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
441 *Blt++ = UgaColorToPixel(Private,
442 XGetPixel(Private->image, SrcX, SrcY));
443 }
444 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
445 }
446 break;
447 case EfiUgaBltBufferToVideo:
448 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (SourceY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
449 Delta -= Width * sizeof (EFI_UGA_PIXEL);
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++;
454 }
455 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
456 }
457 break;
458 case EfiUgaVideoToVideo:
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;
464 if (DestinationY < SourceY) {
465 for (Index = 0; Index < Height; Index++) {
466 memcpy (Dst, Src, Nbr);
467 Dst += Private->line_bytes;
468 Src += Private->line_bytes;
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++) {
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;
482 }
483 }
484 break;
485 case EfiUgaVideoFill:
486 Color = UgaPixelToColor(Private, *BltBuffer);
487 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
488 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
489 XPutPixel(Private->image, DstX, DstY, Color);
490 }
491 }
492 break;
493 default:
494 return EFI_INVALID_PARAMETER;
495 }
496
497 //
498 // Refresh screen.
499 //
500 switch (BltOperation) {
501 case EfiUgaVideoToVideo:
502 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
503 SourceX, SourceY, Width, Height, DestinationX, DestinationY);
504 while (1) {
505 XEvent ev;
506
507 XNextEvent (Private->display, &ev);
508 HandleEvent(Private, &ev);
509 if (ev.type == NoExpose || ev.type == GraphicsExpose)
510 break;
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,
517 DestinationX, DestinationY, Width, Height);
518 XFlush(Private->display);
519 break;
520 case EfiUgaBltBufferToVideo:
521 Redraw(Private, DestinationX, DestinationY, Width, Height);
522 break;
523 default:
524 break;
525 }
526 return EFI_SUCCESS;
527 }
528
529 EFI_STATUS
530 UgaCreate (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",
555 XDisplayName (display_name));
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
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));
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,
583 ExposureMask | KeyPressMask);
584 drv->gc = DefaultGC (drv->display, drv->screen);
585
586 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
587 return EFI_SUCCESS;
588 }