1 /*
2 * Xephyr - A kdrive X server thats runs in a host X window.
3 * Authored by Matthew Allum <mallum@openedhand.com>
4 *
5 * Copyright © 2004 Nokia
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Nokia not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. Nokia makes no
14 * representations about the suitability of this software for any purpose. It
15 * is provided "as is" without express or implied warranty.
16 *
17 * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 */
25
26 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
28 #endif
29
30 #include <xcb/xcb_keysyms.h>
31 #include <X11/keysym.h>
32
33 #include "ephyr.h"
34
35 #include "inputstr.h"
36 #include "scrnintstr.h"
37 #include "ephyrlog.h"
38
39 #ifdef GLAMOR
40 #include "glamor.h"
41 #endif
42 #include "ephyr_glamor_glx.h"
43 #include "glx_extinit.h"
44 #include "xkbsrv.h"
45
46 extern Bool ephyr_glamor;
47
48 KdKeyboardInfo *ephyrKbd;
49 KdPointerInfo *ephyrMouse;
50 Bool ephyrNoDRI = FALSE;
51 Bool ephyrNoXV = FALSE;
52
53 static int mouseState = 0;
54 static Rotation ephyrRandr = RR_Rotate_0;
55
56 typedef struct _EphyrInputPrivate {
57 Bool enabled;
58 } EphyrKbdPrivate, EphyrPointerPrivate;
59
60 Bool EphyrWantGrayScale = 0;
61 Bool EphyrWantResize = 0;
62 Bool EphyrWantNoHostGrab = 0;
63
64 Bool
ephyrInitialize(KdCardInfo * card,EphyrPriv * priv)65 ephyrInitialize(KdCardInfo * card, EphyrPriv * priv)
66 {
67 OsSignal(SIGUSR1, hostx_handle_signal);
68
69 priv->base = 0;
70 priv->bytes_per_line = 0;
71 return TRUE;
72 }
73
74 Bool
ephyrCardInit(KdCardInfo * card)75 ephyrCardInit(KdCardInfo * card)
76 {
77 EphyrPriv *priv;
78
79 priv = (EphyrPriv *) malloc(sizeof(EphyrPriv));
80 if (!priv)
81 return FALSE;
82
83 if (!ephyrInitialize(card, priv)) {
84 free(priv);
85 return FALSE;
86 }
87 card->driver = priv;
88
89 return TRUE;
90 }
91
92 Bool
ephyrScreenInitialize(KdScreenInfo * screen)93 ephyrScreenInitialize(KdScreenInfo *screen)
94 {
95 EphyrScrPriv *scrpriv = screen->driver;
96 int x = 0, y = 0;
97 int width = 640, height = 480;
98 CARD32 redMask, greenMask, blueMask;
99
100 if (hostx_want_screen_geometry(screen, &width, &height, &x, &y)
101 || !screen->width || !screen->height) {
102 screen->width = width;
103 screen->height = height;
104 screen->x = x;
105 screen->y = y;
106 }
107
108 if (EphyrWantGrayScale)
109 screen->fb.depth = 8;
110
111 if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) {
112 if (screen->fb.depth < hostx_get_depth()
113 && (screen->fb.depth == 24 || screen->fb.depth == 16
114 || screen->fb.depth == 8)) {
115 scrpriv->server_depth = screen->fb.depth;
116 }
117 else
118 ErrorF
119 ("\nXephyr: requested screen depth not supported, setting to match hosts.\n");
120 }
121
122 screen->fb.depth = hostx_get_server_depth(screen);
123 screen->rate = 72;
124
125 if (screen->fb.depth <= 8) {
126 if (EphyrWantGrayScale)
127 screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale));
128 else
129 screen->fb.visuals = ((1 << StaticGray) |
130 (1 << GrayScale) |
131 (1 << StaticColor) |
132 (1 << PseudoColor) |
133 (1 << TrueColor) | (1 << DirectColor));
134
135 screen->fb.redMask = 0x00;
136 screen->fb.greenMask = 0x00;
137 screen->fb.blueMask = 0x00;
138 screen->fb.depth = 8;
139 screen->fb.bitsPerPixel = 8;
140 }
141 else {
142 screen->fb.visuals = (1 << TrueColor);
143
144 if (screen->fb.depth <= 15) {
145 screen->fb.depth = 15;
146 screen->fb.bitsPerPixel = 16;
147 }
148 else if (screen->fb.depth <= 16) {
149 screen->fb.depth = 16;
150 screen->fb.bitsPerPixel = 16;
151 }
152 else if (screen->fb.depth <= 24) {
153 screen->fb.depth = 24;
154 screen->fb.bitsPerPixel = 32;
155 }
156 else if (screen->fb.depth <= 30) {
157 screen->fb.depth = 30;
158 screen->fb.bitsPerPixel = 32;
159 }
160 else {
161 ErrorF("\nXephyr: Unsupported screen depth %d\n", screen->fb.depth);
162 return FALSE;
163 }
164
165 hostx_get_visual_masks(screen, &redMask, &greenMask, &blueMask);
166
167 screen->fb.redMask = (Pixel) redMask;
168 screen->fb.greenMask = (Pixel) greenMask;
169 screen->fb.blueMask = (Pixel) blueMask;
170
171 }
172
173 scrpriv->randr = screen->randr;
174
175 return ephyrMapFramebuffer(screen);
176 }
177
178 void *
ephyrWindowLinear(ScreenPtr pScreen,CARD32 row,CARD32 offset,int mode,CARD32 * size,void * closure)179 ephyrWindowLinear(ScreenPtr pScreen,
180 CARD32 row,
181 CARD32 offset, int mode, CARD32 *size, void *closure)
182 {
183 KdScreenPriv(pScreen);
184 EphyrPriv *priv = pScreenPriv->card->driver;
185
186 if (!pScreenPriv->enabled)
187 return 0;
188
189 *size = priv->bytes_per_line;
190 return priv->base + row * priv->bytes_per_line + offset;
191 }
192
193 /**
194 * Figure out display buffer size. If fakexa is enabled, allocate a larger
195 * buffer so that fakexa has space to put offscreen pixmaps.
196 */
197 int
ephyrBufferHeight(KdScreenInfo * screen)198 ephyrBufferHeight(KdScreenInfo * screen)
199 {
200 int buffer_height;
201
202 if (ephyrFuncs.initAccel == NULL)
203 buffer_height = screen->height;
204 else
205 buffer_height = 3 * screen->height;
206 return buffer_height;
207 }
208
209 Bool
ephyrMapFramebuffer(KdScreenInfo * screen)210 ephyrMapFramebuffer(KdScreenInfo * screen)
211 {
212 EphyrScrPriv *scrpriv = screen->driver;
213 EphyrPriv *priv = screen->card->driver;
214 KdPointerMatrix m;
215 int buffer_height;
216
217 EPHYR_LOG("screen->width: %d, screen->height: %d index=%d",
218 screen->width, screen->height, screen->mynum);
219
220 /*
221 * Use the rotation last applied to ourselves (in the Xephyr case the fb
222 * coordinate system moves independently of the pointer coordiante system).
223 */
224 KdComputePointerMatrix(&m, ephyrRandr, screen->width, screen->height);
225 KdSetPointerMatrix(&m);
226
227 buffer_height = ephyrBufferHeight(screen);
228
229 priv->base =
230 hostx_screen_init(screen, screen->x, screen->y,
231 screen->width, screen->height, buffer_height,
232 &priv->bytes_per_line, &screen->fb.bitsPerPixel);
233
234 if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) {
235 scrpriv->shadow = FALSE;
236
237 screen->fb.byteStride = priv->bytes_per_line;
238 screen->fb.pixelStride = screen->width;
239 screen->fb.frameBuffer = (CARD8 *) (priv->base);
240 }
241 else {
242 /* Rotated/Reflected so we need to use shadow fb */
243 scrpriv->shadow = TRUE;
244
245 EPHYR_LOG("allocing shadow");
246
247 KdShadowFbAlloc(screen,
248 scrpriv->randr & (RR_Rotate_90 | RR_Rotate_270));
249 }
250
251 return TRUE;
252 }
253
254 void
ephyrSetScreenSizes(ScreenPtr pScreen)255 ephyrSetScreenSizes(ScreenPtr pScreen)
256 {
257 KdScreenPriv(pScreen);
258 KdScreenInfo *screen = pScreenPriv->screen;
259 EphyrScrPriv *scrpriv = screen->driver;
260
261 if (scrpriv->randr & (RR_Rotate_0 | RR_Rotate_180)) {
262 pScreen->width = screen->width;
263 pScreen->height = screen->height;
264 pScreen->mmWidth = screen->width_mm;
265 pScreen->mmHeight = screen->height_mm;
266 }
267 else {
268 pScreen->width = screen->height;
269 pScreen->height = screen->width;
270 pScreen->mmWidth = screen->height_mm;
271 pScreen->mmHeight = screen->width_mm;
272 }
273 }
274
275 Bool
ephyrUnmapFramebuffer(KdScreenInfo * screen)276 ephyrUnmapFramebuffer(KdScreenInfo * screen)
277 {
278 EphyrScrPriv *scrpriv = screen->driver;
279
280 if (scrpriv->shadow)
281 KdShadowFbFree(screen);
282
283 /* Note, priv->base will get freed when XImage recreated */
284
285 return TRUE;
286 }
287
288 void
ephyrShadowUpdate(ScreenPtr pScreen,shadowBufPtr pBuf)289 ephyrShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf)
290 {
291 KdScreenPriv(pScreen);
292 KdScreenInfo *screen = pScreenPriv->screen;
293
294 EPHYR_LOG("slow paint");
295
296 /* FIXME: Slow Rotated/Reflected updates could be much
297 * much faster efficiently updating via tranforming
298 * pBuf->pDamage regions
299 */
300 shadowUpdateRotatePacked(pScreen, pBuf);
301 hostx_paint_rect(screen, 0, 0, 0, 0, screen->width, screen->height);
302 }
303
304 static void
ephyrInternalDamageRedisplay(ScreenPtr pScreen)305 ephyrInternalDamageRedisplay(ScreenPtr pScreen)
306 {
307 KdScreenPriv(pScreen);
308 KdScreenInfo *screen = pScreenPriv->screen;
309 EphyrScrPriv *scrpriv = screen->driver;
310 RegionPtr pRegion;
311
312 if (!scrpriv || !scrpriv->pDamage)
313 return;
314
315 pRegion = DamageRegion(scrpriv->pDamage);
316
317 if (RegionNotEmpty(pRegion)) {
318 int nbox;
319 BoxPtr pbox;
320
321 if (ephyr_glamor) {
322 ephyr_glamor_damage_redisplay(scrpriv->glamor, pRegion);
323 } else {
324 nbox = RegionNumRects(pRegion);
325 pbox = RegionRects(pRegion);
326
327 while (nbox--) {
328 hostx_paint_rect(screen,
329 pbox->x1, pbox->y1,
330 pbox->x1, pbox->y1,
331 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
332 pbox++;
333 }
334 }
335 DamageEmpty(scrpriv->pDamage);
336 }
337 }
338
339 static void
340 ephyrXcbProcessEvents(Bool queued_only);
341
342 static Bool
ephyrEventWorkProc(ClientPtr client,void * closure)343 ephyrEventWorkProc(ClientPtr client, void *closure)
344 {
345 ephyrXcbProcessEvents(TRUE);
346 return TRUE;
347 }
348
349 static void
ephyrScreenBlockHandler(ScreenPtr pScreen,void * timeout)350 ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout)
351 {
352 KdScreenPriv(pScreen);
353 KdScreenInfo *screen = pScreenPriv->screen;
354 EphyrScrPriv *scrpriv = screen->driver;
355
356 pScreen->BlockHandler = scrpriv->BlockHandler;
357 (*pScreen->BlockHandler)(pScreen, timeout);
358 scrpriv->BlockHandler = pScreen->BlockHandler;
359 pScreen->BlockHandler = ephyrScreenBlockHandler;
360
361 if (scrpriv->pDamage)
362 ephyrInternalDamageRedisplay(pScreen);
363
364 if (hostx_has_queued_event()) {
365 if (!QueueWorkProc(ephyrEventWorkProc, NULL, NULL))
366 FatalError("cannot queue event processing in ephyr block handler");
367 AdjustWaitForDelay(timeout, 0);
368 }
369 }
370
371 Bool
ephyrSetInternalDamage(ScreenPtr pScreen)372 ephyrSetInternalDamage(ScreenPtr pScreen)
373 {
374 KdScreenPriv(pScreen);
375 KdScreenInfo *screen = pScreenPriv->screen;
376 EphyrScrPriv *scrpriv = screen->driver;
377 PixmapPtr pPixmap = NULL;
378
379 scrpriv->pDamage = DamageCreate((DamageReportFunc) 0,
380 (DamageDestroyFunc) 0,
381 DamageReportNone, TRUE, pScreen, pScreen);
382
383 pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
384
385 DamageRegister(&pPixmap->drawable, scrpriv->pDamage);
386
387 return TRUE;
388 }
389
390 void
ephyrUnsetInternalDamage(ScreenPtr pScreen)391 ephyrUnsetInternalDamage(ScreenPtr pScreen)
392 {
393 KdScreenPriv(pScreen);
394 KdScreenInfo *screen = pScreenPriv->screen;
395 EphyrScrPriv *scrpriv = screen->driver;
396
397 DamageDestroy(scrpriv->pDamage);
398 scrpriv->pDamage = NULL;
399 }
400
401 #ifdef RANDR
402 Bool
ephyrRandRGetInfo(ScreenPtr pScreen,Rotation * rotations)403 ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations)
404 {
405 KdScreenPriv(pScreen);
406 KdScreenInfo *screen = pScreenPriv->screen;
407 EphyrScrPriv *scrpriv = screen->driver;
408 RRScreenSizePtr pSize;
409 Rotation randr;
410 int n = 0;
411
412 struct {
413 int width, height;
414 } sizes[] = {
415 {1600, 1200},
416 {1400, 1050},
417 {1280, 960},
418 {1280, 1024},
419 {1152, 864},
420 {1024, 768},
421 {832, 624},
422 {800, 600},
423 {720, 400},
424 {480, 640},
425 {640, 480},
426 {640, 400},
427 {320, 240},
428 {240, 320},
429 {160, 160},
430 {0, 0}
431 };
432
433 EPHYR_LOG("mark");
434
435 *rotations = RR_Rotate_All | RR_Reflect_All;
436
437 if (!hostx_want_preexisting_window(screen)
438 && !hostx_want_fullscreen()) { /* only if no -parent switch */
439 while (sizes[n].width != 0 && sizes[n].height != 0) {
440 RRRegisterSize(pScreen,
441 sizes[n].width,
442 sizes[n].height,
443 (sizes[n].width * screen->width_mm) / screen->width,
444 (sizes[n].height * screen->height_mm) /
445 screen->height);
446 n++;
447 }
448 }
449
450 pSize = RRRegisterSize(pScreen,
451 screen->width,
452 screen->height, screen->width_mm, screen->height_mm);
453
454 randr = KdSubRotation(scrpriv->randr, screen->randr);
455
456 RRSetCurrentConfig(pScreen, randr, 0, pSize);
457
458 return TRUE;
459 }
460
461 Bool
ephyrRandRSetConfig(ScreenPtr pScreen,Rotation randr,int rate,RRScreenSizePtr pSize)462 ephyrRandRSetConfig(ScreenPtr pScreen,
463 Rotation randr, int rate, RRScreenSizePtr pSize)
464 {
465 KdScreenPriv(pScreen);
466 KdScreenInfo *screen = pScreenPriv->screen;
467 EphyrScrPriv *scrpriv = screen->driver;
468 Bool wasEnabled = pScreenPriv->enabled;
469 EphyrScrPriv oldscr;
470 int oldwidth, oldheight, oldmmwidth, oldmmheight;
471 Bool oldshadow;
472 int newwidth, newheight;
473
474 if (screen->randr & (RR_Rotate_0 | RR_Rotate_180)) {
475 newwidth = pSize->width;
476 newheight = pSize->height;
477 }
478 else {
479 newwidth = pSize->height;
480 newheight = pSize->width;
481 }
482
483 if (wasEnabled)
484 KdDisableScreen(pScreen);
485
486 oldscr = *scrpriv;
487
488 oldwidth = screen->width;
489 oldheight = screen->height;
490 oldmmwidth = pScreen->mmWidth;
491 oldmmheight = pScreen->mmHeight;
492 oldshadow = scrpriv->shadow;
493
494 /*
495 * Set new configuration
496 */
497
498 /*
499 * We need to store the rotation value for pointer coords transformation;
500 * though initially the pointer and fb rotation are identical, when we map
501 * the fb, the screen will be reinitialized and return into an unrotated
502 * state (presumably the HW is taking care of the rotation of the fb), but the
503 * pointer still needs to be transformed.
504 */
505 ephyrRandr = KdAddRotation(screen->randr, randr);
506 scrpriv->randr = ephyrRandr;
507
508 ephyrUnmapFramebuffer(screen);
509
510 screen->width = newwidth;
511 screen->height = newheight;
512
513 scrpriv->win_width = screen->width;
514 scrpriv->win_height = screen->height;
515 #ifdef GLAMOR
516 ephyr_glamor_set_window_size(scrpriv->glamor,
517 scrpriv->win_width,
518 scrpriv->win_height);
519 #endif
520
521 if (!ephyrMapFramebuffer(screen))
522 goto bail4;
523
524 /* FIXME below should go in own call */
525
526 if (oldshadow)
527 KdShadowUnset(screen->pScreen);
528 else
529 ephyrUnsetInternalDamage(screen->pScreen);
530
531 ephyrSetScreenSizes(screen->pScreen);
532
533 if (scrpriv->shadow) {
534 if (!KdShadowSet(screen->pScreen,
535 scrpriv->randr, ephyrShadowUpdate, ephyrWindowLinear))
536 goto bail4;
537 }
538 else {
539 #ifdef GLAMOR
540 if (ephyr_glamor)
541 ephyr_glamor_create_screen_resources(pScreen);
542 #endif
543 /* Without shadow fb ( non rotated ) we need
544 * to use damage to efficiently update display
545 * via signal regions what to copy from 'fb'.
546 */
547 if (!ephyrSetInternalDamage(screen->pScreen))
548 goto bail4;
549 }
550
551 /*
552 * Set frame buffer mapping
553 */
554 (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap(pScreen),
555 pScreen->width,
556 pScreen->height,
557 screen->fb.depth,
558 screen->fb.bitsPerPixel,
559 screen->fb.byteStride,
560 screen->fb.frameBuffer);
561
562 /* set the subpixel order */
563
564 KdSetSubpixelOrder(pScreen, scrpriv->randr);
565
566 if (wasEnabled)
567 KdEnableScreen(pScreen);
568
569 RRScreenSizeNotify(pScreen);
570
571 return TRUE;
572
573 bail4:
574 EPHYR_LOG("bailed");
575
576 ephyrUnmapFramebuffer(screen);
577 *scrpriv = oldscr;
578 (void) ephyrMapFramebuffer(screen);
579
580 pScreen->width = oldwidth;
581 pScreen->height = oldheight;
582 pScreen->mmWidth = oldmmwidth;
583 pScreen->mmHeight = oldmmheight;
584
585 if (wasEnabled)
586 KdEnableScreen(pScreen);
587 return FALSE;
588 }
589
590 Bool
ephyrRandRInit(ScreenPtr pScreen)591 ephyrRandRInit(ScreenPtr pScreen)
592 {
593 rrScrPrivPtr pScrPriv;
594
595 if (!RRScreenInit(pScreen))
596 return FALSE;
597
598 pScrPriv = rrGetScrPriv(pScreen);
599 pScrPriv->rrGetInfo = ephyrRandRGetInfo;
600 pScrPriv->rrSetConfig = ephyrRandRSetConfig;
601 return TRUE;
602 }
603
604 static Bool
ephyrResizeScreen(ScreenPtr pScreen,int newwidth,int newheight)605 ephyrResizeScreen (ScreenPtr pScreen,
606 int newwidth,
607 int newheight)
608 {
609 KdScreenPriv(pScreen);
610 KdScreenInfo *screen = pScreenPriv->screen;
611 RRScreenSize size = {0};
612 Bool ret;
613 int t;
614
615 if (screen->randr & (RR_Rotate_90|RR_Rotate_270)) {
616 t = newwidth;
617 newwidth = newheight;
618 newheight = t;
619 }
620
621 if (newwidth == screen->width && newheight == screen->height) {
622 return FALSE;
623 }
624
625 size.width = newwidth;
626 size.height = newheight;
627
628 hostx_size_set_from_configure(TRUE);
629 ret = ephyrRandRSetConfig (pScreen, screen->randr, 0, &size);
630 hostx_size_set_from_configure(FALSE);
631 if (ret) {
632 RROutputPtr output;
633
634 output = RRFirstOutput(pScreen);
635 if (!output)
636 return FALSE;
637 RROutputSetModes(output, NULL, 0, 0);
638 }
639
640 return ret;
641 }
642 #endif
643
644 Bool
ephyrCreateColormap(ColormapPtr pmap)645 ephyrCreateColormap(ColormapPtr pmap)
646 {
647 return fbInitializeColormap(pmap);
648 }
649
650 Bool
ephyrInitScreen(ScreenPtr pScreen)651 ephyrInitScreen(ScreenPtr pScreen)
652 {
653 KdScreenPriv(pScreen);
654 KdScreenInfo *screen = pScreenPriv->screen;
655
656 EPHYR_LOG("pScreen->myNum:%d\n", pScreen->myNum);
657 hostx_set_screen_number(screen, pScreen->myNum);
658 if (EphyrWantNoHostGrab) {
659 hostx_set_win_title(screen, "xephyr");
660 } else {
661 hostx_set_win_title(screen, "(ctrl+shift grabs mouse and keyboard)");
662 }
663 pScreen->CreateColormap = ephyrCreateColormap;
664
665 #ifdef XV
666 if (!ephyrNoXV) {
667 if (ephyr_glamor)
668 ephyr_glamor_xv_init(pScreen);
669 else if (!ephyrInitVideo(pScreen)) {
670 EPHYR_LOG_ERROR("failed to initialize xvideo\n");
671 }
672 else {
673 EPHYR_LOG("initialized xvideo okay\n");
674 }
675 }
676 #endif /*XV*/
677
678 return TRUE;
679 }
680
681
682 Bool
ephyrFinishInitScreen(ScreenPtr pScreen)683 ephyrFinishInitScreen(ScreenPtr pScreen)
684 {
685 KdScreenPriv(pScreen);
686 KdScreenInfo *screen = pScreenPriv->screen;
687 EphyrScrPriv *scrpriv = screen->driver;
688
689 /* FIXME: Calling this even if not using shadow.
690 * Seems harmless enough. But may be safer elsewhere.
691 */
692 if (!shadowSetup(pScreen))
693 return FALSE;
694
695 #ifdef RANDR
696 if (!ephyrRandRInit(pScreen))
697 return FALSE;
698 #endif
699
700 scrpriv->BlockHandler = pScreen->BlockHandler;
701 pScreen->BlockHandler = ephyrScreenBlockHandler;
702
703 return TRUE;
704 }
705
706 /**
707 * Called by kdrive after calling down the
708 * pScreen->CreateScreenResources() chain, this gives us a chance to
709 * make any pixmaps after the screen and all extensions have been
710 * initialized.
711 */
712 Bool
ephyrCreateResources(ScreenPtr pScreen)713 ephyrCreateResources(ScreenPtr pScreen)
714 {
715 KdScreenPriv(pScreen);
716 KdScreenInfo *screen = pScreenPriv->screen;
717 EphyrScrPriv *scrpriv = screen->driver;
718
719 EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d",
720 pScreen, pScreen->myNum, scrpriv->shadow);
721
722 if (scrpriv->shadow)
723 return KdShadowSet(pScreen,
724 scrpriv->randr,
725 ephyrShadowUpdate, ephyrWindowLinear);
726 else {
727 #ifdef GLAMOR
728 if (ephyr_glamor) {
729 if (!ephyr_glamor_create_screen_resources(pScreen))
730 return FALSE;
731 }
732 #endif
733 return ephyrSetInternalDamage(pScreen);
734 }
735 }
736
737 void
ephyrScreenFini(KdScreenInfo * screen)738 ephyrScreenFini(KdScreenInfo * screen)
739 {
740 EphyrScrPriv *scrpriv = screen->driver;
741
742 if (scrpriv->shadow) {
743 KdShadowFbFree(screen);
744 }
745 scrpriv->BlockHandler = NULL;
746 }
747
748 void
ephyrCloseScreen(ScreenPtr pScreen)749 ephyrCloseScreen(ScreenPtr pScreen)
750 {
751 ephyrUnsetInternalDamage(pScreen);
752 }
753
754 /*
755 * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug.
756 * See https://bugs.freedesktop.org/show_bug.cgi?id=3030
757 */
758 void
ephyrUpdateModifierState(unsigned int state)759 ephyrUpdateModifierState(unsigned int state)
760 {
761
762 DeviceIntPtr pDev = inputInfo.keyboard;
763 KeyClassPtr keyc = pDev->key;
764 int i;
765 CARD8 mask;
766 int xkb_state;
767
768 if (!pDev)
769 return;
770
771 xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
772 state = state & 0xff;
773
774 if (xkb_state == state)
775 return;
776
777 for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
778 int key;
779
780 /* Modifier is down, but shouldn't be
781 */
782 if ((xkb_state & mask) && !(state & mask)) {
783 int count = keyc->modifierKeyCount[i];
784
785 for (key = 0; key < MAP_LENGTH; key++)
786 if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
787 if (mask == XCB_MOD_MASK_LOCK) {
788 KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE);
789 KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
790 }
791 else if (key_is_down(pDev, key, KEY_PROCESSED))
792 KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
793
794 if (--count == 0)
795 break;
796 }
797 }
798
799 /* Modifier shoud be down, but isn't
800 */
801 if (!(xkb_state & mask) && (state & mask))
802 for (key = 0; key < MAP_LENGTH; key++)
803 if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
804 KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE);
805 if (mask == XCB_MOD_MASK_LOCK)
806 KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
807 break;
808 }
809 }
810 }
811
812 static Bool
ephyrCursorOffScreen(ScreenPtr * ppScreen,int * x,int * y)813 ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
814 {
815 return FALSE;
816 }
817
818 static void
ephyrCrossScreen(ScreenPtr pScreen,Bool entering)819 ephyrCrossScreen(ScreenPtr pScreen, Bool entering)
820 {
821 }
822
823 ScreenPtr ephyrCursorScreen; /* screen containing the cursor */
824
825 static void
ephyrWarpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)826 ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
827 {
828 input_lock();
829 ephyrCursorScreen = pScreen;
830 miPointerWarpCursor(inputInfo.pointer, pScreen, x, y);
831
832 input_unlock();
833 }
834
835 miPointerScreenFuncRec ephyrPointerScreenFuncs = {
836 ephyrCursorOffScreen,
837 ephyrCrossScreen,
838 ephyrWarpCursor,
839 };
840
841 static KdScreenInfo *
screen_from_window(Window w)842 screen_from_window(Window w)
843 {
844 int i = 0;
845
846 for (i = 0; i < screenInfo.numScreens; i++) {
847 ScreenPtr pScreen = screenInfo.screens[i];
848 KdPrivScreenPtr kdscrpriv = KdGetScreenPriv(pScreen);
849 KdScreenInfo *screen = kdscrpriv->screen;
850 EphyrScrPriv *scrpriv = screen->driver;
851
852 if (scrpriv->win == w
853 || scrpriv->peer_win == w
854 || scrpriv->win_pre_existing == w) {
855 return screen;
856 }
857 }
858
859 return NULL;
860 }
861
862 static void
ephyrProcessErrorEvent(xcb_generic_event_t * xev)863 ephyrProcessErrorEvent(xcb_generic_event_t *xev)
864 {
865 xcb_generic_error_t *e = (xcb_generic_error_t *)xev;
866
867 FatalError("X11 error\n"
868 "Error code: %hhu\n"
869 "Sequence number: %hu\n"
870 "Major code: %hhu\tMinor code: %hu\n"
871 "Error value: %u\n",
872 e->error_code,
873 e->sequence,
874 e->major_code, e->minor_code,
875 e->resource_id);
876 }
877
878 static void
ephyrProcessExpose(xcb_generic_event_t * xev)879 ephyrProcessExpose(xcb_generic_event_t *xev)
880 {
881 xcb_expose_event_t *expose = (xcb_expose_event_t *)xev;
882 KdScreenInfo *screen = screen_from_window(expose->window);
883 EphyrScrPriv *scrpriv = screen->driver;
884
885 /* Wait for the last expose event in a series of cliprects
886 * to actually paint our screen.
887 */
888 if (expose->count != 0)
889 return;
890
891 if (scrpriv) {
892 hostx_paint_rect(scrpriv->screen, 0, 0, 0, 0,
893 scrpriv->win_width,
894 scrpriv->win_height);
895 } else {
896 EPHYR_LOG_ERROR("failed to get host screen\n");
897 }
898 }
899
900 static void
ephyrProcessMouseMotion(xcb_generic_event_t * xev)901 ephyrProcessMouseMotion(xcb_generic_event_t *xev)
902 {
903 xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
904 KdScreenInfo *screen = screen_from_window(motion->event);
905
906 if (!ephyrMouse ||
907 !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
908 EPHYR_LOG("skipping mouse motion:%d\n", screen->pScreen->myNum);
909 return;
910 }
911
912 if (ephyrCursorScreen != screen->pScreen) {
913 EPHYR_LOG("warping mouse cursor. "
914 "cur_screen:%d, motion_screen:%d\n",
915 ephyrCursorScreen->myNum, screen->pScreen->myNum);
916 ephyrWarpCursor(inputInfo.pointer, screen->pScreen,
917 motion->event_x, motion->event_y);
918 }
919 else {
920 int x = 0, y = 0;
921
922 EPHYR_LOG("enqueuing mouse motion:%d\n", screen->pScreen->myNum);
923 x = motion->event_x;
924 y = motion->event_y;
925 EPHYR_LOG("initial (x,y):(%d,%d)\n", x, y);
926
927 /* convert coords into desktop-wide coordinates.
928 * fill_pointer_events will convert that back to
929 * per-screen coordinates where needed */
930 x += screen->pScreen->x;
931 y += screen->pScreen->y;
932
933 KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_POINTER_DESKTOP, x, y, 0);
934 }
935 }
936
937 static void
ephyrProcessButtonPress(xcb_generic_event_t * xev)938 ephyrProcessButtonPress(xcb_generic_event_t *xev)
939 {
940 xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
941
942 if (!ephyrMouse ||
943 !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
944 EPHYR_LOG("skipping mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum);
945 return;
946 }
947
948 ephyrUpdateModifierState(button->state);
949 /* This is a bit hacky. will break for button 5 ( defined as 0x10 )
950 * Check KD_BUTTON defines in kdrive.h
951 */
952 mouseState |= 1 << (button->detail - 1);
953
954 EPHYR_LOG("enqueuing mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum);
955 KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
956 }
957
958 static void
ephyrProcessButtonRelease(xcb_generic_event_t * xev)959 ephyrProcessButtonRelease(xcb_generic_event_t *xev)
960 {
961 xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
962
963 if (!ephyrMouse ||
964 !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
965 return;
966 }
967
968 ephyrUpdateModifierState(button->state);
969 mouseState &= ~(1 << (button->detail - 1));
970
971 EPHYR_LOG("enqueuing mouse release:%d\n", screen_from_window(button->event)->pScreen->myNum);
972 KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
973 }
974
975 /* Xephyr wants ctrl+shift to grab the window, but that conflicts with
976 ctrl+alt+shift key combos. Remember the modifier state on key presses and
977 releases, if mod1 is pressed, we need ctrl, shift and mod1 released
978 before we allow a shift-ctrl grab activation.
979
980 note: a key event contains the mask _before_ the current key takes
981 effect, so mod1_was_down will be reset on the first key press after all
982 three were released, not on the last release. That'd require some more
983 effort.
984 */
985 static int
ephyrUpdateGrabModifierState(int state)986 ephyrUpdateGrabModifierState(int state)
987 {
988 static int mod1_was_down = 0;
989
990 if ((state & (XCB_MOD_MASK_CONTROL|XCB_MOD_MASK_SHIFT|XCB_MOD_MASK_1)) == 0)
991 mod1_was_down = 0;
992 else if (state & XCB_MOD_MASK_1)
993 mod1_was_down = 1;
994
995 return mod1_was_down;
996 }
997
998 static void
ephyrProcessKeyPress(xcb_generic_event_t * xev)999 ephyrProcessKeyPress(xcb_generic_event_t *xev)
1000 {
1001 xcb_key_press_event_t *key = (xcb_key_press_event_t *)xev;
1002
1003 if (!ephyrKbd ||
1004 !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
1005 return;
1006 }
1007
1008 ephyrUpdateGrabModifierState(key->state);
1009 ephyrUpdateModifierState(key->state);
1010 KdEnqueueKeyboardEvent(ephyrKbd, key->detail, FALSE);
1011 }
1012
1013 static void
ephyrProcessKeyRelease(xcb_generic_event_t * xev)1014 ephyrProcessKeyRelease(xcb_generic_event_t *xev)
1015 {
1016 xcb_connection_t *conn = hostx_get_xcbconn();
1017 xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev;
1018 static xcb_key_symbols_t *keysyms;
1019 static int grabbed_screen = -1;
1020 int mod1_down = ephyrUpdateGrabModifierState(key->state);
1021
1022 if (!keysyms)
1023 keysyms = xcb_key_symbols_alloc(conn);
1024
1025 if (!EphyrWantNoHostGrab &&
1026 (((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_L
1027 || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_R)
1028 && (key->state & XCB_MOD_MASK_CONTROL)) ||
1029 ((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_L
1030 || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_R)
1031 && (key->state & XCB_MOD_MASK_SHIFT)))) {
1032 KdScreenInfo *screen = screen_from_window(key->event);
1033 EphyrScrPriv *scrpriv = screen->driver;
1034
1035 if (grabbed_screen != -1) {
1036 xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME);
1037 xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
1038 grabbed_screen = -1;
1039 hostx_set_win_title(screen,
1040 "(ctrl+shift grabs mouse and keyboard)");
1041 }
1042 else if (!mod1_down) {
1043 /* Attempt grab */
1044 xcb_grab_keyboard_cookie_t kbgrabc =
1045 xcb_grab_keyboard(conn,
1046 TRUE,
1047 scrpriv->win,
1048 XCB_TIME_CURRENT_TIME,
1049 XCB_GRAB_MODE_ASYNC,
1050 XCB_GRAB_MODE_ASYNC);
1051 xcb_grab_keyboard_reply_t *kbgrabr;
1052 xcb_grab_pointer_cookie_t pgrabc =
1053 xcb_grab_pointer(conn,
1054 TRUE,
1055 scrpriv->win,
1056 0,
1057 XCB_GRAB_MODE_ASYNC,
1058 XCB_GRAB_MODE_ASYNC,
1059 scrpriv->win,
1060 XCB_NONE,
1061 XCB_TIME_CURRENT_TIME);
1062 xcb_grab_pointer_reply_t *pgrabr;
1063 kbgrabr = xcb_grab_keyboard_reply(conn, kbgrabc, NULL);
1064 if (!kbgrabr || kbgrabr->status != XCB_GRAB_STATUS_SUCCESS) {
1065 xcb_discard_reply(conn, pgrabc.sequence);
1066 xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
1067 } else {
1068 pgrabr = xcb_grab_pointer_reply(conn, pgrabc, NULL);
1069 if (!pgrabr || pgrabr->status != XCB_GRAB_STATUS_SUCCESS)
1070 {
1071 xcb_ungrab_keyboard(conn,
1072 XCB_TIME_CURRENT_TIME);
1073 } else {
1074 grabbed_screen = scrpriv->mynum;
1075 hostx_set_win_title
1076 (screen,
1077 "(ctrl+shift releases mouse and keyboard)");
1078 }
1079 }
1080 }
1081 }
1082
1083 if (!ephyrKbd ||
1084 !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
1085 return;
1086 }
1087
1088 /* Still send the release event even if above has happened server
1089 * will get confused with just an up event. Maybe it would be
1090 * better to just block shift+ctrls getting to kdrive all
1091 * together.
1092 */
1093 ephyrUpdateModifierState(key->state);
1094 KdEnqueueKeyboardEvent(ephyrKbd, key->detail, TRUE);
1095 }
1096
1097 static void
ephyrProcessConfigureNotify(xcb_generic_event_t * xev)1098 ephyrProcessConfigureNotify(xcb_generic_event_t *xev)
1099 {
1100 xcb_configure_notify_event_t *configure =
1101 (xcb_configure_notify_event_t *)xev;
1102 KdScreenInfo *screen = screen_from_window(configure->window);
1103 EphyrScrPriv *scrpriv = screen->driver;
1104
1105 if (!scrpriv ||
1106 (scrpriv->win_pre_existing == None && !EphyrWantResize)) {
1107 return;
1108 }
1109
1110 #ifdef RANDR
1111 ephyrResizeScreen(screen->pScreen, configure->width, configure->height);
1112 #endif /* RANDR */
1113 }
1114
1115 static void
ephyrXcbProcessEvents(Bool queued_only)1116 ephyrXcbProcessEvents(Bool queued_only)
1117 {
1118 xcb_connection_t *conn = hostx_get_xcbconn();
1119 xcb_generic_event_t *expose = NULL, *configure = NULL;
1120
1121 while (TRUE) {
1122 xcb_generic_event_t *xev = hostx_get_event(queued_only);
1123
1124 if (!xev) {
1125 /* If our XCB connection has died (for example, our window was
1126 * closed), exit now.
1127 */
1128 if (xcb_connection_has_error(conn)) {
1129 CloseWellKnownConnections();
1130 OsCleanup(1);
1131 exit(1);
1132 }
1133
1134 break;
1135 }
1136
1137 switch (xev->response_type & 0x7f) {
1138 case 0:
1139 ephyrProcessErrorEvent(xev);
1140 break;
1141
1142 case XCB_EXPOSE:
1143 free(expose);
1144 expose = xev;
1145 xev = NULL;
1146 break;
1147
1148 case XCB_MOTION_NOTIFY:
1149 ephyrProcessMouseMotion(xev);
1150 break;
1151
1152 case XCB_KEY_PRESS:
1153 ephyrProcessKeyPress(xev);
1154 break;
1155
1156 case XCB_KEY_RELEASE:
1157 ephyrProcessKeyRelease(xev);
1158 break;
1159
1160 case XCB_BUTTON_PRESS:
1161 ephyrProcessButtonPress(xev);
1162 break;
1163
1164 case XCB_BUTTON_RELEASE:
1165 ephyrProcessButtonRelease(xev);
1166 break;
1167
1168 case XCB_CONFIGURE_NOTIFY:
1169 free(configure);
1170 configure = xev;
1171 xev = NULL;
1172 break;
1173 }
1174
1175 if (xev) {
1176 if (ephyr_glamor)
1177 ephyr_glamor_process_event(xev);
1178
1179 free(xev);
1180 }
1181 }
1182
1183 if (configure) {
1184 ephyrProcessConfigureNotify(configure);
1185 free(configure);
1186 }
1187
1188 if (expose) {
1189 ephyrProcessExpose(expose);
1190 free(expose);
1191 }
1192 }
1193
1194 static void
ephyrXcbNotify(int fd,int ready,void * data)1195 ephyrXcbNotify(int fd, int ready, void *data)
1196 {
1197 ephyrXcbProcessEvents(FALSE);
1198 }
1199
1200 void
ephyrCardFini(KdCardInfo * card)1201 ephyrCardFini(KdCardInfo * card)
1202 {
1203 EphyrPriv *priv = card->driver;
1204
1205 free(priv);
1206 }
1207
1208 void
ephyrGetColors(ScreenPtr pScreen,int n,xColorItem * pdefs)1209 ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
1210 {
1211 /* XXX Not sure if this is right */
1212
1213 EPHYR_LOG("mark");
1214
1215 while (n--) {
1216 pdefs->red = 0;
1217 pdefs->green = 0;
1218 pdefs->blue = 0;
1219 pdefs++;
1220 }
1221
1222 }
1223
1224 void
ephyrPutColors(ScreenPtr pScreen,int n,xColorItem * pdefs)1225 ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
1226 {
1227 KdScreenPriv(pScreen);
1228 KdScreenInfo *screen = pScreenPriv->screen;
1229 EphyrScrPriv *scrpriv = screen->driver;
1230 int min, max, p;
1231
1232 /* XXX Not sure if this is right */
1233
1234 min = 256;
1235 max = 0;
1236
1237 while (n--) {
1238 p = pdefs->pixel;
1239 if (p < min)
1240 min = p;
1241 if (p > max)
1242 max = p;
1243
1244 hostx_set_cmap_entry(pScreen, p,
1245 pdefs->red >> 8,
1246 pdefs->green >> 8, pdefs->blue >> 8);
1247 pdefs++;
1248 }
1249 if (scrpriv->pDamage) {
1250 BoxRec box;
1251 RegionRec region;
1252
1253 box.x1 = 0;
1254 box.y1 = 0;
1255 box.x2 = pScreen->width;
1256 box.y2 = pScreen->height;
1257 RegionInit(®ion, &box, 1);
1258 DamageReportDamage(scrpriv->pDamage, ®ion);
1259 RegionUninit(®ion);
1260 }
1261 }
1262
1263 /* Mouse calls */
1264
1265 static Status
MouseInit(KdPointerInfo * pi)1266 MouseInit(KdPointerInfo * pi)
1267 {
1268 pi->driverPrivate = (EphyrPointerPrivate *)
1269 calloc(sizeof(EphyrPointerPrivate), 1);
1270 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE;
1271 pi->nAxes = 3;
1272 pi->nButtons = 32;
1273 free(pi->name);
1274 pi->name = strdup("Xephyr virtual mouse");
1275
1276 /*
1277 * Must transform pointer coords since the pointer position
1278 * relative to the Xephyr window is controlled by the host server and
1279 * remains constant regardless of any rotation applied to the Xephyr screen.
1280 */
1281 pi->transformCoordinates = TRUE;
1282
1283 ephyrMouse = pi;
1284 return Success;
1285 }
1286
1287 static Status
MouseEnable(KdPointerInfo * pi)1288 MouseEnable(KdPointerInfo * pi)
1289 {
1290 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = TRUE;
1291 SetNotifyFd(hostx_get_fd(), ephyrXcbNotify, X_NOTIFY_READ, NULL);
1292 return Success;
1293 }
1294
1295 static void
MouseDisable(KdPointerInfo * pi)1296 MouseDisable(KdPointerInfo * pi)
1297 {
1298 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE;
1299 RemoveNotifyFd(hostx_get_fd());
1300 return;
1301 }
1302
1303 static void
MouseFini(KdPointerInfo * pi)1304 MouseFini(KdPointerInfo * pi)
1305 {
1306 free(pi->driverPrivate);
1307 ephyrMouse = NULL;
1308 return;
1309 }
1310
1311 KdPointerDriver EphyrMouseDriver = {
1312 "ephyr",
1313 MouseInit,
1314 MouseEnable,
1315 MouseDisable,
1316 MouseFini,
1317 NULL,
1318 };
1319
1320 /* Keyboard */
1321
1322 static Status
EphyrKeyboardInit(KdKeyboardInfo * ki)1323 EphyrKeyboardInit(KdKeyboardInfo * ki)
1324 {
1325 KeySymsRec keySyms;
1326 CARD8 modmap[MAP_LENGTH];
1327 XkbControlsRec controls;
1328
1329 ki->driverPrivate = (EphyrKbdPrivate *)
1330 calloc(sizeof(EphyrKbdPrivate), 1);
1331
1332 if (hostx_load_keymap(&keySyms, modmap, &controls)) {
1333 XkbApplyMappingChange(ki->dixdev, &keySyms,
1334 keySyms.minKeyCode,
1335 keySyms.maxKeyCode - keySyms.minKeyCode + 1,
1336 modmap, serverClient);
1337 XkbDDXChangeControls(ki->dixdev, &controls, &controls);
1338 free(keySyms.map);
1339 }
1340
1341 ki->minScanCode = keySyms.minKeyCode;
1342 ki->maxScanCode = keySyms.maxKeyCode;
1343
1344 if (ki->name != NULL) {
1345 free(ki->name);
1346 }
1347
1348 ki->name = strdup("Xephyr virtual keyboard");
1349 ephyrKbd = ki;
1350 return Success;
1351 }
1352
1353 static Status
EphyrKeyboardEnable(KdKeyboardInfo * ki)1354 EphyrKeyboardEnable(KdKeyboardInfo * ki)
1355 {
1356 ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = TRUE;
1357
1358 return Success;
1359 }
1360
1361 static void
EphyrKeyboardDisable(KdKeyboardInfo * ki)1362 EphyrKeyboardDisable(KdKeyboardInfo * ki)
1363 {
1364 ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = FALSE;
1365 }
1366
1367 static void
EphyrKeyboardFini(KdKeyboardInfo * ki)1368 EphyrKeyboardFini(KdKeyboardInfo * ki)
1369 {
1370 free(ki->driverPrivate);
1371 ephyrKbd = NULL;
1372 return;
1373 }
1374
1375 static void
EphyrKeyboardLeds(KdKeyboardInfo * ki,int leds)1376 EphyrKeyboardLeds(KdKeyboardInfo * ki, int leds)
1377 {
1378 }
1379
1380 static void
EphyrKeyboardBell(KdKeyboardInfo * ki,int volume,int frequency,int duration)1381 EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration)
1382 {
1383 }
1384
1385 KdKeyboardDriver EphyrKeyboardDriver = {
1386 "ephyr",
1387 EphyrKeyboardInit,
1388 EphyrKeyboardEnable,
1389 EphyrKeyboardLeds,
1390 EphyrKeyboardBell,
1391 EphyrKeyboardDisable,
1392 EphyrKeyboardFini,
1393 NULL,
1394 };
1395