1 #include "Uefi/UefiSpec.h"
2 #include "Protocol/UnixThunk.h"
3 #include "Protocol/SimpleTextIn.h"
4 #include "Protocol/UgaDraw.h"
5 #include "Protocol/UnixUgaIo.h"
9 #include <X11/extensions/XShm.h>
10 #include <X11/keysym.h>
16 extern void msSleep (unsigned long Milliseconds
);
20 struct uga_drv_shift_mask
30 EFI_UNIX_UGA_IO_PROTOCOL UgaIo
;
33 int screen
; /* values for window_size in main */
41 unsigned int line_bytes
;
42 unsigned int pixel_shift
;
43 unsigned char *image_data
;
45 struct uga_drv_shift_mask r
, g
, b
;
48 XShmSegmentInfo xshm_info
;
53 unsigned int key_count
;
54 EFI_INPUT_KEY keys
[NBR_KEYS
];
58 HandleEvents(UGA_IO_PRIVATE
*drv
);
61 fill_shift_mask (struct uga_drv_shift_mask
*sm
, unsigned long mask
)
65 while ((mask
& 1) == 0)
75 sm
->csize
= 8 - sm
->size
;
79 TryCreateShmImage(UGA_IO_PRIVATE
*drv
)
81 drv
->image
= XShmCreateImage (drv
->display
, drv
->visual
,
82 drv
->depth
, ZPixmap
, NULL
, &drv
->xshm_info
,
83 drv
->width
, drv
->height
);
84 if (drv
->image
== NULL
)
87 switch (drv
->image
->bitmap_unit
) {
99 drv
->xshm_info
.shmid
= shmget
100 (IPC_PRIVATE
, drv
->image
->bytes_per_line
* drv
->image
->height
,
102 if (drv
->xshm_info
.shmid
< 0)
104 XDestroyImage(drv
->image
);
108 drv
->image_data
= shmat (drv
->xshm_info
.shmid
, NULL
, 0);
111 shmctl (drv
->xshm_info
.shmid
, IPC_RMID
, NULL
);
112 XDestroyImage(drv
->image
);
115 /* Can this fail ? */
116 shmctl (drv
->xshm_info
.shmid
, IPC_RMID
, NULL
);
118 drv
->xshm_info
.shmaddr
= (char*)drv
->image_data
;
119 drv
->image
->data
= (char*)drv
->image_data
;
121 if (!XShmAttach (drv
->display
, &drv
->xshm_info
))
123 shmdt (drv
->image_data
);
124 XDestroyImage(drv
->image
);
132 UgaClose (EFI_UNIX_UGA_IO_PROTOCOL
*UgaIo
)
134 UGA_IO_PRIVATE
*drv
= (UGA_IO_PRIVATE
*)UgaIo
;
138 if (drv
->image
!= NULL
)
140 XDestroyImage(drv
->image
);
143 shmdt (drv
->image_data
);
145 drv
->image_data
= NULL
;
148 XDestroyWindow(drv
->display
, drv
->win
);
149 XCloseDisplay(drv
->display
);
156 UgaSize(EFI_UNIX_UGA_IO_PROTOCOL
*UgaIo
, UINT32 Width
, UINT32 Height
)
158 UGA_IO_PRIVATE
*drv
= (UGA_IO_PRIVATE
*)UgaIo
;
159 XSizeHints size_hints
;
161 /* Destroy current buffer if created. */
162 if (drv
->image
!= NULL
)
164 XDestroyImage(drv
->image
);
167 shmdt (drv
->image_data
);
169 drv
->image_data
= NULL
;
174 drv
->height
= Height
;
175 XResizeWindow (drv
->display
, drv
->win
, Width
, Height
);
177 /* Allocate image. */
178 if (XShmQueryExtension(drv
->display
) && TryCreateShmImage(drv
))
186 drv
->pixel_shift
= 2;
187 else if (drv
->depth
> 8)
188 drv
->pixel_shift
= 1;
190 drv
->pixel_shift
= 0;
192 drv
->image_data
= malloc((drv
->width
* drv
->height
) << drv
->pixel_shift
);
193 drv
->image
= XCreateImage (drv
->display
, drv
->visual
, drv
->depth
,
194 ZPixmap
, 0, (char *)drv
->image_data
,
195 drv
->width
, drv
->height
,
196 8 << drv
->pixel_shift
, 0);
198 drv
->line_bytes
= drv
->image
->bytes_per_line
;
199 fill_shift_mask (&drv
->r
, drv
->image
->red_mask
);
200 fill_shift_mask (&drv
->g
, drv
->image
->green_mask
);
201 fill_shift_mask (&drv
->b
, drv
->image
->blue_mask
);
204 size_hints
.flags
= PSize
| PMinSize
| PMaxSize
;
205 size_hints
.min_width
= size_hints
.max_width
= size_hints
.base_width
= Width
;
206 size_hints
.min_height
= size_hints
.max_height
= size_hints
.base_height
= Height
;
207 XSetWMNormalHints (drv
->display
, drv
->win
, &size_hints
);
209 XMapWindow (drv
->display
, drv
->win
);
215 handleKeyEvent(UGA_IO_PRIVATE
*drv
, XEvent
*ev
)
222 if (drv
->key_count
== NBR_KEYS
)
225 res
= XLookupString(&ev
->xkey
, str
, sizeof(str
), &keysym
, NULL
);
229 case XK_Home
: Key
.ScanCode
= SCAN_HOME
; break;
230 case XK_End
: Key
.ScanCode
= SCAN_END
; break;
231 case XK_Left
: Key
.ScanCode
= SCAN_LEFT
; break;
232 case XK_Right
: Key
.ScanCode
= SCAN_RIGHT
; break;
233 case XK_Up
: Key
.ScanCode
= SCAN_UP
; break;
234 case XK_Down
: Key
.ScanCode
= SCAN_DOWN
; break;
235 case XK_Delete
: Key
.ScanCode
= SCAN_DELETE
; break;
236 case XK_Insert
: Key
.ScanCode
= SCAN_INSERT
; break;
237 case XK_Page_Up
: Key
.ScanCode
= SCAN_PAGE_UP
; break;
238 case XK_Page_Down
: Key
.ScanCode
= SCAN_PAGE_DOWN
; break;
239 case XK_Escape
: Key
.ScanCode
= SCAN_ESC
; break;
241 case XK_F1
: Key
.ScanCode
= SCAN_F1
; break;
242 case XK_F2
: Key
.ScanCode
= SCAN_F2
; break;
243 case XK_F3
: Key
.ScanCode
= SCAN_F3
; break;
244 case XK_F4
: Key
.ScanCode
= SCAN_F4
; break;
245 case XK_F5
: Key
.ScanCode
= SCAN_F5
; break;
246 case XK_F6
: Key
.ScanCode
= SCAN_F6
; break;
247 case XK_F7
: Key
.ScanCode
= SCAN_F7
; break;
248 case XK_F8
: Key
.ScanCode
= SCAN_F8
; break;
249 case XK_F9
: Key
.ScanCode
= SCAN_F9
; break;
253 Key
.UnicodeChar
= str
[0];
259 drv
->keys
[drv
->key_wr
] = Key
;
260 drv
->key_wr
= (drv
->key_wr
+ 1) % NBR_KEYS
;
265 Redraw(UGA_IO_PRIVATE
*drv
, UINTN X
, UINTN Y
, UINTN Width
, UINTN Height
)
268 XShmPutImage (drv
->display
, drv
->win
, drv
->gc
, drv
->image
,
269 X
, Y
, X
, Y
, Width
, Height
, False
);
271 XPutImage (drv
->display
, drv
->win
, drv
->gc
, drv
->image
,
272 X
, Y
, X
, Y
, Width
, Height
);
276 HandleEvent(UGA_IO_PRIVATE
*drv
, XEvent
*ev
)
281 Redraw(drv
, ev
->xexpose
.x
, ev
->xexpose
.y
,
282 ev
->xexpose
.width
, ev
->xexpose
.height
);
285 Redraw(drv
, ev
->xgraphicsexpose
.x
, ev
->xgraphicsexpose
.y
,
286 ev
->xgraphicsexpose
.width
, ev
->xgraphicsexpose
.height
);
289 handleKeyEvent(drv
, ev
);
292 XRefreshKeyboardMapping(&ev
->xmapping
);
296 XCloseDisplay (drv
->display
);
307 HandleEvents(UGA_IO_PRIVATE
*drv
)
309 while (XPending(drv
->display
) != 0)
313 XNextEvent (drv
->display
, &ev
);
314 HandleEvent(drv
, &ev
);
320 UgaPixelToColor (UGA_IO_PRIVATE
*drv
, EFI_UGA_PIXEL pixel
)
322 return ((pixel
.Red
>> drv
->r
.csize
) << drv
->r
.shift
)
323 | ((pixel
.Green
>> drv
->g
.csize
) << drv
->g
.shift
)
324 | ((pixel
.Blue
>> drv
->b
.csize
) << drv
->b
.shift
);
329 UgaColorToPixel (UGA_IO_PRIVATE
*drv
, unsigned long val
)
333 memset (&res
, 0, sizeof (EFI_UGA_PIXEL
));
334 /* FIXME: should round instead of truncate. */
335 res
.Red
= (val
>> drv
->r
.shift
) << drv
->r
.csize
;
336 res
.Green
= (val
>> drv
->g
.shift
) << drv
->g
.csize
;
337 res
.Blue
= (val
>> drv
->b
.shift
) << drv
->b
.csize
;
344 UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL
*UgaIo
)
346 UGA_IO_PRIVATE
*drv
= (UGA_IO_PRIVATE
*)UgaIo
;
348 if (drv
->key_count
!= 0)
351 /* EFI is certainly polling. Be CPU-friendly. */
353 return EFI_NOT_READY
;
359 UgaGetKey(EFI_UNIX_UGA_IO_PROTOCOL
*UgaIo
, EFI_INPUT_KEY
*key
)
361 UGA_IO_PRIVATE
*drv
= (UGA_IO_PRIVATE
*)UgaIo
;
364 status
= UgaCheckKey(UgaIo
);
365 if (status
!= EFI_SUCCESS
)
368 *key
= drv
->keys
[drv
->key_rd
];
369 drv
->key_rd
= (drv
->key_rd
+ 1) % NBR_KEYS
;
375 UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL
*UgaIo
,
376 IN EFI_UGA_PIXEL
*BltBuffer OPTIONAL
,
377 IN EFI_UGA_BLT_OPERATION BltOperation
,
380 IN UINTN DestinationX
,
381 IN UINTN DestinationY
,
384 IN UINTN Delta OPTIONAL
387 UGA_IO_PRIVATE
*Private
= (UGA_IO_PRIVATE
*)UgaIo
;
402 if (BltOperation
== EfiUgaVideoToBltBuffer
403 || BltOperation
== EfiUgaVideoToVideo
) {
407 if (SourceY
+ Height
> Private
->height
) {
408 return EFI_INVALID_PARAMETER
;
411 if (SourceX
+ Width
> Private
->width
) {
412 return EFI_INVALID_PARAMETER
;
416 if (BltOperation
== EfiUgaBltBufferToVideo
417 || BltOperation
== EfiUgaVideoToVideo
418 || BltOperation
== EfiUgaVideoFill
) {
420 // Destination is Video
422 if (DestinationY
+ Height
> Private
->height
) {
423 return EFI_INVALID_PARAMETER
;
426 if (DestinationX
+ Width
> Private
->width
) {
427 return EFI_INVALID_PARAMETER
;
431 switch (BltOperation
) {
432 case EfiUgaVideoToBltBuffer
:
434 Delta
-= Width
* sizeof (EFI_UGA_PIXEL
);
435 for (SrcY
= SourceY
; SrcY
< (Height
+ SourceY
); SrcY
++) {
436 for (SrcX
= SourceX
; SrcX
< (Width
+ SourceX
); SrcX
++) {
437 *Blt
++ = UgaColorToPixel(Private
,
438 XGetPixel(Private
->image
, SrcX
, SrcY
));
440 Blt
= (EFI_UGA_PIXEL
*) ((UINT8
*) Blt
+ Delta
);
443 case EfiUgaBltBufferToVideo
:
445 Delta
-= Width
* sizeof (EFI_UGA_PIXEL
);
446 for (DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); DstY
++) {
447 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
448 XPutPixel(Private
->image
, DstX
, DstY
, UgaPixelToColor(Private
, *Blt
));
451 Blt
= (EFI_UGA_PIXEL
*) ((UINT8
*) Blt
+ Delta
);
454 case EfiUgaVideoToVideo
:
455 Dst
= Private
->image_data
+ (DestinationX
<< Private
->pixel_shift
)
456 + DestinationY
* Private
->line_bytes
;
457 Src
= Private
->image_data
+ (SourceX
<< Private
->pixel_shift
)
458 + SourceY
* Private
->line_bytes
;
459 Nbr
= Width
<< Private
->pixel_shift
;
460 if (DestinationY
< SourceY
) {
461 for (Index
= 0; Index
< Height
; Index
++) {
462 memcpy (Dst
, Src
, Nbr
);
463 Dst
+= Private
->line_bytes
;
464 Src
+= Private
->line_bytes
;
468 Dst
+= (Height
- 1) * Private
->line_bytes
;
469 Src
+= (Height
- 1) * Private
->line_bytes
;
470 for (Index
= 0; Index
< Height
; Index
++) {
472 // Source and Destination Y may be equal, therefore Dst and Src may
475 memmove (Dst
, Src
, Nbr
);
476 Dst
-= Private
->line_bytes
;
477 Src
-= Private
->line_bytes
;
481 case EfiUgaVideoFill
:
482 Color
= UgaPixelToColor(Private
, *BltBuffer
);
483 for (DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); DstY
++) {
484 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
485 XPutPixel(Private
->image
, DstX
, DstY
, Color
);
490 return EFI_INVALID_PARAMETER
;
496 switch (BltOperation
) {
497 case EfiUgaVideoToVideo
:
498 XCopyArea(Private
->display
, Private
->win
, Private
->win
, Private
->gc
,
499 SourceX
, SourceY
, Width
, Height
, DestinationX
, DestinationY
);
503 XNextEvent (Private
->display
, &ev
);
504 HandleEvent(Private
, &ev
);
505 if (ev
.type
== NoExpose
|| ev
.type
== GraphicsExpose
)
509 case EfiUgaVideoFill
:
510 Color
= UgaPixelToColor(Private
, *BltBuffer
);
511 XSetForeground(Private
->display
, Private
->gc
, Color
);
512 XFillRectangle(Private
->display
, Private
->win
, Private
->gc
,
513 DestinationX
, DestinationY
, Width
, Height
);
515 case EfiUgaBltBufferToVideo
:
516 Redraw(Private
, DestinationX
, DestinationY
, Width
, Height
);
525 UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL
**Uga
, CONST CHAR16
*Title
)
528 unsigned int border_width
= 0;
529 char *display_name
= NULL
;
532 drv
= (UGA_IO_PRIVATE
*)
533 calloc (1, sizeof (UGA_IO_PRIVATE
));
535 return EFI_OUT_OF_RESOURCES
;
537 drv
->UgaIo
.UgaClose
= UgaClose
;
538 drv
->UgaIo
.UgaSize
= UgaSize
;
539 drv
->UgaIo
.UgaCheckKey
= UgaCheckKey
;
540 drv
->UgaIo
.UgaGetKey
= UgaGetKey
;
541 drv
->UgaIo
.UgaBlt
= UgaBlt
;
546 drv
->display
= XOpenDisplay (display_name
);
547 if (drv
->display
== NULL
)
549 fprintf (stderr
, "uga: cannot connect to X server %s\n",
550 XDisplayName (display_name
));
552 return EFI_DEVICE_ERROR
;
554 drv
->screen
= DefaultScreen (drv
->display
);
555 drv
->visual
= DefaultVisual (drv
->display
, drv
->screen
);
556 drv
->win
= XCreateSimpleWindow
557 (drv
->display
, RootWindow (drv
->display
, drv
->screen
),
558 0, 0, 4, 4, border_width
,
559 BlackPixel (drv
->display
, drv
->screen
),
560 WhitePixel (drv
->display
, drv
->screen
));
562 drv
->depth
= DefaultDepth (drv
->display
, drv
->screen
);
564 /* Compute title len and convert to Ascii. */
565 for (title_len
= 0; Title
[title_len
] != 0; title_len
++)
568 char title
[title_len
+ 1];
570 for (i
= 0; i
< title_len
; i
++)
574 XStoreName (drv
->display
, drv
->win
, title
);
577 XSelectInput (drv
->display
, drv
->win
,
578 ExposureMask
| KeyPressMask
);
579 drv
->gc
= DefaultGC (drv
->display
, drv
->screen
);
581 *Uga
= (EFI_UNIX_UGA_IO_PROTOCOL
*)drv
;