Two swsusp patches:
[linux-flexiantxendom0-3.2.10.git] / arch / um / drivers / x11_user.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include <sys/ipc.h>
5 #include <sys/shm.h>
6
7 #include <linux/fb.h>
8 #include <linux/input.h>
9
10 #include <X11/X.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <X11/keysym.h>
14 #include <X11/extensions/XShm.h>
15
16 #include "x11_kern.h"
17 #include "x11_user.h"
18
19 /* --------------------------------------------------------------------------- */
20
21 struct x11_window {
22         /* misc x11 stuff */
23         Display                   *dpy;
24         Window                    root, win;
25         GC                        gc;
26         XVisualInfo               vi;
27         Atom                      delete_window;
28
29         /* framebuffer -- x11 */
30         XImage                    *ximage;
31         unsigned char             *xidata;
32         XShmSegmentInfo           shminfo;
33         
34         /* framebuffer -- kernel */
35         struct fb_fix_screeninfo  fix;
36         struct fb_var_screeninfo  var;
37 };
38
39 /* --------------------------------------------------------------------------- */
40
41 /*
42  * map X11 keycodes to linux keycodes
43  *
44  * WARNING: X11 keycodes are not portable, this likely breaks as soon
45  * as one uses a X-Server not running on a linux machine as display.
46  *
47  * Using portable keysyms instead creates some strange and hard to
48  * handle keymapping effects through.  That happens because both host
49  * and uml machine are mapping keys then ...
50  */
51 static int x11_keymap[] = {
52         [   9 ] = KEY_ESC,
53         [  10 ] = KEY_1,
54         [  11 ] = KEY_2,
55         [  12 ] = KEY_3,
56         [  13 ] = KEY_4,
57         [  14 ] = KEY_5,
58         [  15 ] = KEY_6,
59         [  16 ] = KEY_7,
60         [  17 ] = KEY_8,
61         [  18 ] = KEY_9,
62         [  19 ] = KEY_0,
63         [  20 ] = KEY_MINUS,
64         [  21 ] = KEY_EQUAL,
65         [  22 ] = KEY_BACKSPACE,
66
67         [  23 ] = KEY_TAB,
68         [  24 ] = KEY_Q,
69         [  25 ] = KEY_W,
70         [  26 ] = KEY_E,
71         [  27 ] = KEY_R,
72         [  28 ] = KEY_T,
73         [  29 ] = KEY_Y,
74         [  30 ] = KEY_U,
75         [  31 ] = KEY_I,
76         [  32 ] = KEY_O,
77         [  33 ] = KEY_P,
78         [  34 ] = KEY_LEFTBRACE,
79         [  35 ] = KEY_RIGHTBRACE,
80         [  36 ] = KEY_ENTER,
81
82         [  37 ] = KEY_LEFTCTRL,
83         [  38 ] = KEY_A,
84         [  39 ] = KEY_S,
85         [  40 ] = KEY_D,
86         [  41 ] = KEY_F,
87         [  42 ] = KEY_G,
88         [  43 ] = KEY_H,
89         [  44 ] = KEY_J,
90         [  45 ] = KEY_K,
91         [  46 ] = KEY_L,
92         [  47 ] = KEY_SEMICOLON,
93         [  48 ] = KEY_APOSTROPHE,
94         [  49 ] = KEY_GRAVE,
95
96         [  50 ] = KEY_LEFTSHIFT,
97         [  51 ] = KEY_BACKSLASH,
98         [  52 ] = KEY_Z,
99         [  53 ] = KEY_X,
100         [  54 ] = KEY_C,
101         [  55 ] = KEY_V,
102         [  56 ] = KEY_B,
103         [  57 ] = KEY_N,
104         [  58 ] = KEY_M,
105         [  59 ] = KEY_COMMA,
106         [  60 ] = KEY_DOT,
107         [  61 ] = KEY_SLASH,
108         [  62 ] = KEY_RIGHTSHIFT,
109
110         [  63 ] = KEY_KPASTERISK,
111         [  64 ] = KEY_LEFTALT,
112         [  65 ] = KEY_SPACE,
113         [  66 ] = KEY_CAPSLOCK,
114
115         [  67 ] = KEY_F1,
116         [  68 ] = KEY_F2,
117         [  69 ] = KEY_F3,
118         [  70 ] = KEY_F4,
119         [  71 ] = KEY_F5,
120         [  72 ] = KEY_F6,
121         [  73 ] = KEY_F7,
122         [  74 ] = KEY_F8,
123         [  75 ] = KEY_F9,
124         [  76 ] = KEY_F10,
125         [  77 ] = KEY_NUMLOCK,
126         [  78 ] = KEY_SCROLLLOCK,
127
128         [  79 ] = KEY_KP7,
129         [  80 ] = KEY_KP8,
130         [  81 ] = KEY_KP9,
131         [  82 ] = KEY_KPMINUS,
132         [  83 ] = KEY_KP4,
133         [  84 ] = KEY_KP5,
134         [  85 ] = KEY_KP6,
135         [  86 ] = KEY_KPPLUS,
136         [  87 ] = KEY_KP1,
137         [  88 ] = KEY_KP2,
138         [  89 ] = KEY_KP3,
139         [  90 ] = KEY_KP0,
140         [  91 ] = KEY_KPDOT,
141
142         // [  92 ] = KEY_Print,
143         // [  93 ] = KEY_Mode_switch,
144         [  94 ] = KEY_102ND,
145
146         [  95 ] = KEY_F11,
147         [  96 ] = KEY_F12,
148         [  97 ] = KEY_HOME,
149         [  98 ] = KEY_UP,
150         [  99 ] = KEY_PAGEUP,
151         [ 100 ] = KEY_LEFT,
152         [ 102 ] = KEY_RIGHT,
153         [ 103 ] = KEY_END,
154         [ 104 ] = KEY_DOWN,
155         [ 105 ] = KEY_PAGEDOWN,
156         [ 106 ] = KEY_INSERT,
157         [ 107 ] = KEY_DELETE,
158
159         // [ 108 ] = KEY_KP_Enter,
160         [ 109 ] = KEY_RIGHTCTRL,
161         // [ 110 ] = KEY_Pause,
162         // [ 111 ] = KEY_Print,
163         // [ 112 ] = KEY_KP_Divide,
164         [ 113 ] = KEY_RIGHTALT,
165         // [ 114 ] = KEY_Pause,
166         // [ 115 ] = KEY_Super_L,
167         // [ 116 ] = KEY_Super_R,
168         [ 117 ] = KEY_MENU,
169         // [ 124 ] = KEY_ISO_Level3_Shift,
170         // [ 126 ] = KEY_KP_Equal,
171 };
172
173 static void x11_kbd(struct x11_window *win, struct x11_kerndata *kd, XEvent *e)
174 {
175         int key = KEY_RESERVED;
176         
177         if (e->xkey.keycode < sizeof(x11_keymap)/sizeof(x11_keymap[0]))
178                 key = x11_keymap[e->xkey.keycode];
179         if (KEY_RESERVED != key) {
180                 x11_kbd_input(kd, key, e->type == KeyPress);
181         } else {
182                 x11_kbd_input(kd, KEY_MAX + e->xkey.keycode, e->type == KeyPress);
183         }
184 }
185
186 /* --------------------------------------------------------------------------- */
187
188 static int mitshm_err;
189
190 static int
191 catch_no_mitshm(Display * dpy, XErrorEvent * event)
192 {
193         mitshm_err++;
194         return 0;
195 }
196
197 static void init_color(int32_t mask, struct fb_bitfield *bf)
198 {
199     int i;
200
201     memset(bf, 0, sizeof(*bf));
202     for (i = 0; i < 32; i++) {
203             if (mask & ((int32_t)1 << i))
204                     bf->length++;
205             else if (!bf->length)
206                     bf->offset++;
207     }
208 }
209     
210 struct x11_window *x11_open(int width, int height)
211 {
212         char *title = "user mode linux framebuffer";
213         struct x11_window *win;
214         XSizeHints hints;
215         XTextProperty prop;
216         XVisualInfo *info, template;
217         void *old_handler;
218         int n,bytes_pp;
219         
220         win = malloc(sizeof(*win));
221         if (NULL == win)
222                 goto fail;
223         
224         win->dpy = XOpenDisplay(NULL);
225         if (NULL == win->dpy)
226                 goto fail_free;
227
228         /* get visual info */
229         template.screen = XDefaultScreen(win->dpy);
230         template.depth  = DefaultDepth(win->dpy, DefaultScreen(win->dpy));
231         info = XGetVisualInfo(win->dpy, VisualScreenMask | VisualDepthMask,
232                               &template, &n);
233         if (0 == n)
234                 goto fail_free;
235         win->vi = info[0];
236         bytes_pp = (win->vi.depth+7)/8;
237         XFree(info);
238         if (win->vi.class != TrueColor && win->vi.class != DirectColor)
239                 goto fail_free;
240
241         /* create pixmap */
242         mitshm_err  = 0;
243         old_handler = XSetErrorHandler(catch_no_mitshm);
244         win->ximage = XShmCreateImage(win->dpy,win->vi.visual,win->vi.depth,
245                                       ZPixmap, NULL, &win->shminfo,
246                                       width, height);
247         if (NULL == win->ximage)
248                 goto shm_error;
249         win->shminfo.shmid = shmget(IPC_PRIVATE,
250                                     win->ximage->bytes_per_line * win->ximage->height,
251                                     IPC_CREAT | 0777);
252         if (-1 == win->shminfo.shmid)
253                 goto shm_error;
254         win->shminfo.shmaddr = (char *) shmat(win->shminfo.shmid, 0, 0);
255         if ((void *)-1 == win->shminfo.shmaddr)
256                 goto shm_error;
257
258         win->ximage->data = win->shminfo.shmaddr;
259         win->shminfo.readOnly = False;
260         XShmAttach(win->dpy, &win->shminfo);
261         XSync(win->dpy, False);
262         if (mitshm_err)
263                 goto shm_error;
264         shmctl(win->shminfo.shmid, IPC_RMID, 0);
265         XSetErrorHandler(old_handler);
266         goto have_ximage;
267
268 shm_error:
269         /* can't use shared memory -- cleanup and try without */
270         if (win->ximage) {
271                 XDestroyImage(win->ximage);
272                 win->ximage = NULL;
273         }
274         if ((void *)-1 != win->shminfo.shmaddr  &&  NULL != win->shminfo.shmaddr)
275                 shmdt(win->shminfo.shmaddr);
276         XSetErrorHandler(old_handler);
277
278         memset(&win->shminfo,0,sizeof(win->shminfo));
279         if (NULL == (win->xidata = malloc(width * height * bytes_pp)))
280                 goto fail_free;
281
282         win->ximage = XCreateImage(win->dpy, win->vi.visual, win->vi.depth,
283                                    ZPixmap, 0,  win->xidata,
284                                    width, height, 8, 0);
285
286 have_ximage:
287         /* fill structs */
288         win->var.xres           = width;
289         win->var.xres_virtual   = width;
290         win->var.yres           = height;
291         win->var.yres_virtual   = height;
292         win->var.bits_per_pixel = bytes_pp * 8;
293         win->var.pixclock       = 10000000 / win->var.xres * 1000 / win->var.yres;
294         win->var.left_margin    = (win->var.xres / 8) & 0xf8;
295         win->var.hsync_len      = (win->var.xres / 8) & 0xf8;
296
297         init_color(win->vi.red_mask,   &win->var.red);
298         init_color(win->vi.green_mask, &win->var.green);
299         init_color(win->vi.blue_mask,  &win->var.blue);
300         
301         win->var.activate       = FB_ACTIVATE_NOW;
302         win->var.height         = -1;
303         win->var.width          = -1;
304         win->var.right_margin   = 32;
305         win->var.upper_margin   = 16;
306         win->var.lower_margin   = 4;
307         win->var.vsync_len      = 4;
308         win->var.vmode          = FB_VMODE_NONINTERLACED;
309
310 #if 0
311         win->fix.smem_start     = ;
312         win->fix.smem_len       = ;
313 #endif
314         win->fix.line_length    = win->ximage->bytes_per_line;
315         win->fix.visual         = FB_VISUAL_TRUECOLOR;
316         
317         strcpy(win->fix.id,"x11");
318         win->fix.type           = FB_TYPE_PACKED_PIXELS;
319         win->fix.accel          = FB_ACCEL_NONE;
320         
321         /* create + init window */
322         hints.flags      = PMinSize | PMaxSize;
323         hints.min_width  = width;
324         hints.min_height = height;
325         hints.max_width  = width;
326         hints.max_height = height;
327         XStringListToTextProperty(&title,1,&prop);
328         
329         win->root  = RootWindow(win->dpy, DefaultScreen(win->dpy));
330         win->win = XCreateSimpleWindow(win->dpy, win->root,
331                                        0, 0, width, height,
332                                        CopyFromParent, CopyFromParent,
333                                        BlackPixel(win->dpy, DefaultScreen(win->dpy)));
334         win->gc = XCreateGC(win->dpy, win->win, 0, NULL);
335         XSelectInput(win->dpy, win->win,
336                      KeyPressMask    | KeyReleaseMask    | /* virtual keyboard */
337                      ButtonPressMask | ButtonReleaseMask | /* mouse (touchscreen?) */
338                      PointerMotionMask | ExposureMask | StructureNotifyMask |
339                      PropertyChangeMask);
340         XMapWindow(win->dpy,win->win);
341         XSetWMNormalHints(win->dpy,win->win,&hints);
342         XSetWMName(win->dpy,win->win,&prop);
343         win->delete_window = XInternAtom(win->dpy, "WM_DELETE_WINDOW", False);
344         XSetWMProtocols(win->dpy, win->win, &win->delete_window, 1);
345
346         XFlush(win->dpy);
347         return win;
348         
349 fail_free:
350         free(win);
351 fail:
352         return NULL;
353 }
354
355 int x11_get_fd(struct x11_window *win)
356 {
357         return ConnectionNumber(win->dpy);
358 }
359
360 struct fb_fix_screeninfo* x11_get_fix(struct x11_window *win)
361 {
362         return &win->fix;
363 }
364
365 struct fb_var_screeninfo* x11_get_var(struct x11_window *win)
366 {
367         return &win->var;
368 }
369
370 void* x11_get_fbmem(struct x11_window *win)
371 {
372         return win->ximage->data;
373 }
374
375 int x11_blit_fb(struct x11_window *win, int x1, int y1, int x2, int y2)
376 {
377         if (win->shminfo.shmid)
378                 XShmPutImage(win->dpy, win->win, win->gc, win->ximage,
379                              x1,y1,x1,y1, x2-x1,y2-y1, True);
380         else
381                 XPutImage(win->dpy, win->win, win->gc, win->ximage,
382                           x1,y1,x1,y1, x2-x1,y2-y1);
383         XFlush(win->dpy);
384         return 0;
385 }
386
387 int x11_has_data(struct x11_window *win, struct x11_kerndata *kd)
388 {
389         XEvent e;
390         int count = 0;
391         
392         while (True == XCheckMaskEvent(win->dpy, ~0, &e)) {
393                 count++;
394                 switch (e.type) {
395                 case KeyPress:
396                 case KeyRelease:
397                         x11_kbd(win, kd, &e);
398                         break;
399                 case ButtonPress:
400                 case ButtonRelease:
401                         x11_mouse_input(kd, e.xbutton.state, e.xbutton.x, e.xbutton.y);
402                         break;
403                 case MotionNotify:
404                         x11_mouse_input(kd, e.xmotion.state, e.xmotion.x, e.xmotion.y);
405                         break;
406                 case Expose:
407                         if (0 == e.xexpose.count)
408                                 x11_blit_fb(win, 0,0, win->var.xres, win->var.yres);
409                         break;
410                 case ClientMessage:
411                         /* hmm, don't get client messages ... */
412                         if (e.xclient.data.l[0] == win->delete_window)
413                                 x11_cad(kd);
414                         break;
415                 }
416         }
417         return count;
418 }
419
420 /*
421  * Local variables:
422  * c-basic-offset: 8
423  * End:
424  */