]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/UgaX11.c
Correct DriverSample to produce the ConfigAccess protocol
[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 {
173 XDestroyImage(drv->image);
174
175 if (drv->use_shm)
288a3c98 176 shmdt (drv->image_data);
804405e7 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. */
288a3c98 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;
804405e7 197
198 drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
199 drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
288a3c98 200 ZPixmap, 0, (char *)drv->image_data,
201 drv->width, drv->height,
202 8 << drv->pixel_shift, 0);
804405e7 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
7492c63d 220void
804405e7 221handleKeyEvent(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);
288a3c98 232 Key.ScanCode = 0;
804405e7 233 Key.UnicodeChar = 0;
288a3c98 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;
804405e7 256
257 default:
258 if (res == 1) {
259 Key.UnicodeChar = str[0];
260 } else {
261 return;
262 }
288a3c98 263 }
264
804405e7 265 drv->keys[drv->key_wr] = Key;
266 drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
267 drv->key_count++;
268}
269
7492c63d 270void
804405e7 271Redraw(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,
288a3c98 275 X, Y, X, Y, Width, Height, False);
804405e7 276 else
277 XPutImage (drv->display, drv->win, drv->gc, drv->image,
288a3c98 278 X, Y, X, Y, Width, Height);
279 XFlush(drv->display);
804405e7 280}
281
7492c63d 282void
804405e7 283HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
284{
285 switch (ev->type)
286 {
287 case Expose:
288 Redraw(drv, ev->xexpose.x, ev->xexpose.y,
288a3c98 289 ev->xexpose.width, ev->xexpose.height);
804405e7 290 break;
291 case GraphicsExpose:
292 Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
288a3c98 293 ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
804405e7 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
7492c63d 313void
804405e7 314HandleEvents(UGA_IO_PRIVATE *drv)
315{
316 while (XPending(drv->display) != 0)
317 {
318 XEvent ev;
288a3c98 319
804405e7 320 XNextEvent (drv->display, &ev);
321 HandleEvent(drv, &ev);
322 }
323}
324
804405e7 325unsigned long
326UgaPixelToColor (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
804405e7 333EFI_UGA_PIXEL
334UgaColorToPixel (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
804405e7 347EFI_STATUS
348UgaCheckKey(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
804405e7 361EFI_STATUS
362UgaGetKey(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
288a3c98 377EFI_STATUS
804405e7 378UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
288a3c98 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 )
804405e7 389{
390 UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
288a3c98 391 UINTN DstY;
392 UINTN SrcY;
804405e7 393 UINTN DstX;
394 UINTN SrcX;
395 UINTN Index;
288a3c98 396 EFI_UGA_PIXEL *Blt;
804405e7 397 UINT8 *Dst;
398 UINT8 *Src;
399 UINTN Nbr;
400 unsigned long Color;
401
402 //
403 // Check bounds
404 //
405 if (BltOperation == EfiUgaVideoToBltBuffer
288a3c98 406 || BltOperation == EfiUgaVideoToVideo) {
407 //
804405e7 408 // Source is Video.
288a3c98 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 }
804405e7 417 }
418
419 if (BltOperation == EfiUgaBltBufferToVideo
420 || BltOperation == EfiUgaVideoToVideo
288a3c98 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 }
804405e7 432 }
433
288a3c98 434 switch (BltOperation) {
804405e7 435 case EfiUgaVideoToBltBuffer:
288a3c98 436 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (DestinationY * Delta) + DestinationX * sizeof (EFI_UGA_PIXEL));
804405e7 437 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 438 for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
804405e7 439 for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
288a3c98 440 *Blt++ = UgaColorToPixel(Private,
441 XGetPixel(Private->image, SrcX, SrcY));
804405e7 442 }
443 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
288a3c98 444 }
804405e7 445 break;
288a3c98 446 case EfiUgaBltBufferToVideo:
447 Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (SourceY * Delta) + SourceX * sizeof (EFI_UGA_PIXEL));
804405e7 448 Delta -= Width * sizeof (EFI_UGA_PIXEL);
288a3c98 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++;
804405e7 453 }
454 Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
455 }
456 break;
288a3c98 457 case EfiUgaVideoToVideo:
804405e7 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;
288a3c98 463 if (DestinationY < SourceY) {
804405e7 464 for (Index = 0; Index < Height; Index++) {
288a3c98 465 memcpy (Dst, Src, Nbr);
466 Dst += Private->line_bytes;
467 Src += Private->line_bytes;
804405e7 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++) {
288a3c98 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;
804405e7 481 }
482 }
483 break;
484 case EfiUgaVideoFill:
485 Color = UgaPixelToColor(Private, *BltBuffer);
288a3c98 486 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
804405e7 487 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
288a3c98 488 XPutPixel(Private->image, DstX, DstY, Color);
804405e7 489 }
288a3c98 490 }
804405e7 491 break;
492 default:
288a3c98 493 return EFI_INVALID_PARAMETER;
804405e7 494 }
495
496 //
497 // Refresh screen.
498 //
288a3c98 499 switch (BltOperation) {
500 case EfiUgaVideoToVideo:
804405e7 501 XCopyArea(Private->display, Private->win, Private->win, Private->gc,
288a3c98 502 SourceX, SourceY, Width, Height, DestinationX, DestinationY);
804405e7 503 while (1) {
504 XEvent ev;
288a3c98 505
804405e7 506 XNextEvent (Private->display, &ev);
507 HandleEvent(Private, &ev);
508 if (ev.type == NoExpose || ev.type == GraphicsExpose)
288a3c98 509 break;
804405e7 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,
288a3c98 516 DestinationX, DestinationY, Width, Height);
517 XFlush(Private->display);
804405e7 518 break;
288a3c98 519 case EfiUgaBltBufferToVideo:
804405e7 520 Redraw(Private, DestinationX, DestinationY, Width, Height);
521 break;
522 default:
523 break;
524 }
525 return EFI_SUCCESS;
526}
527
528EFI_STATUS
529UgaCreate (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",
288a3c98 554 XDisplayName (display_name));
804405e7 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
288a3c98 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));
804405e7 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,
288a3c98 582 ExposureMask | KeyPressMask);
804405e7 583 drv->gc = DefaultGC (drv->display, drv->screen);
584
585 *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
586 return EFI_SUCCESS;
587}