ia64/xen-unstable

view extras/mini-os/fbfront.c @ 18811:390ef36eb596

Remove Xen-private definitions from kexec public header.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 19 13:13:39 2008 +0000 (2008-11-19)
parents 433d1b26fd51
children 18c8270da77c
line source
1 /*
2 * Frame Buffer + Keyboard driver for Mini-OS.
3 * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
4 * Based on blkfront.c.
5 */
7 #include <os.h>
8 #include <xenbus.h>
9 #include <events.h>
10 #include <xen/io/kbdif.h>
11 #include <xen/io/fbif.h>
12 #include <xen/io/protocols.h>
13 #include <gnttab.h>
14 #include <xmalloc.h>
15 #include <fbfront.h>
16 #include <lib.h>
18 DECLARE_WAIT_QUEUE_HEAD(kbdfront_queue);
25 struct kbdfront_dev {
26 domid_t dom;
28 struct xenkbd_page *page;
29 evtchn_port_t evtchn;
31 char *nodename;
32 char *backend;
34 xenbus_event_queue events;
36 #ifdef HAVE_LIBC
37 int fd;
38 #endif
39 };
41 void kbdfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
42 {
43 #ifdef HAVE_LIBC
44 struct kbdfront_dev *dev = data;
45 int fd = dev->fd;
47 if (fd != -1)
48 files[fd].read = 1;
49 #endif
50 wake_up(&kbdfront_queue);
51 }
53 static void free_kbdfront(struct kbdfront_dev *dev)
54 {
55 mask_evtchn(dev->evtchn);
57 free(dev->backend);
59 free_page(dev->page);
61 unbind_evtchn(dev->evtchn);
63 free(dev->nodename);
64 free(dev);
65 }
67 struct kbdfront_dev *init_kbdfront(char *_nodename, int abs_pointer)
68 {
69 xenbus_transaction_t xbt;
70 char* err;
71 char* message=NULL;
72 struct xenkbd_page *s;
73 int retry=0;
74 char* msg;
75 char* nodename = _nodename ? _nodename : "device/vkbd/0";
76 struct kbdfront_dev *dev;
78 char path[strlen(nodename) + 1 + 10 + 1];
80 printk("******************* KBDFRONT for %s **********\n\n\n", nodename);
82 dev = malloc(sizeof(*dev));
83 dev->nodename = strdup(nodename);
84 #ifdef HAVE_LIBC
85 dev->fd = -1;
86 #endif
88 snprintf(path, sizeof(path), "%s/backend-id", nodename);
89 dev->dom = xenbus_read_integer(path);
90 evtchn_alloc_unbound(dev->dom, kbdfront_handler, dev, &dev->evtchn);
92 dev->page = s = (struct xenkbd_page*) alloc_page();
93 memset(s,0,PAGE_SIZE);
95 dev->events = NULL;
97 s->in_cons = s->in_prod = 0;
98 s->out_cons = s->out_prod = 0;
100 again:
101 err = xenbus_transaction_start(&xbt);
102 if (err) {
103 printk("starting transaction\n");
104 }
106 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
107 if (err) {
108 message = "writing page-ref";
109 goto abort_transaction;
110 }
111 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
112 if (err) {
113 message = "writing event-channel";
114 goto abort_transaction;
115 }
116 if (abs_pointer) {
117 err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1");
118 if (err) {
119 message = "writing event-channel";
120 goto abort_transaction;
121 }
122 }
124 err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
125 if (err)
126 printk("error writing initialized: %s\n", err);
129 err = xenbus_transaction_end(xbt, 0, &retry);
130 if (retry) {
131 goto again;
132 printk("completing transaction\n");
133 }
135 goto done;
137 abort_transaction:
138 xenbus_transaction_end(xbt, 1, &retry);
139 goto error;
141 done:
143 snprintf(path, sizeof(path), "%s/backend", nodename);
144 msg = xenbus_read(XBT_NIL, path, &dev->backend);
145 if (msg) {
146 printk("Error %s when reading the backend path %s\n", msg, path);
147 goto error;
148 }
150 printk("backend at %s\n", dev->backend);
152 {
153 char path[strlen(dev->backend) + 1 + 6 + 1];
155 snprintf(path, sizeof(path), "%s/state", dev->backend);
157 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
159 xenbus_wait_for_value(path, "4", &dev->events);
161 printk("%s connected\n", dev->backend);
163 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
164 }
165 unmask_evtchn(dev->evtchn);
167 printk("************************** KBDFRONT\n");
169 return dev;
170 error:
171 free_kbdfront(dev);
172 return NULL;
173 }
175 int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
176 {
177 struct xenkbd_page *page = dev->page;
178 uint32_t prod, cons;
179 int i;
181 #ifdef HAVE_LIBC
182 if (dev->fd != -1) {
183 files[dev->fd].read = 0;
184 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
185 }
186 #endif
188 prod = page->in_prod;
190 if (prod == page->in_cons)
191 return 0;
193 rmb(); /* ensure we see ring contents up to prod */
195 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
196 memcpy(buf + i, &XENKBD_IN_RING_REF(page, cons), sizeof(*buf));
198 mb(); /* ensure we got ring contents */
199 page->in_cons = cons;
200 notify_remote_via_evtchn(dev->evtchn);
202 #ifdef HAVE_LIBC
203 if (cons != prod && dev->fd != -1)
204 /* still some events to read */
205 files[dev->fd].read = 1;
206 #endif
208 return i;
209 }
212 void shutdown_kbdfront(struct kbdfront_dev *dev)
213 {
214 char* err;
215 char *nodename = dev->nodename;
217 char path[strlen(dev->backend) + 1 + 5 + 1];
219 printk("close kbd: backend at %s\n",dev->backend);
221 snprintf(path, sizeof(path), "%s/state", dev->backend);
222 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
223 xenbus_wait_for_value(path, "5", &dev->events);
225 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
226 xenbus_wait_for_value(path, "6", &dev->events);
228 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
229 // does not work yet.
230 //xenbus_wait_for_value(path, "2", &dev->events);
232 xenbus_unwatch_path(XBT_NIL, path);
234 snprintf(path, sizeof(path), "%s/page-ref", nodename);
235 xenbus_rm(XBT_NIL, path);
236 snprintf(path, sizeof(path), "%s/event-channel", nodename);
237 xenbus_rm(XBT_NIL, path);
238 snprintf(path, sizeof(path), "%s/request-abs-pointer", nodename);
239 xenbus_rm(XBT_NIL, path);
241 free_kbdfront(dev);
242 }
244 #ifdef HAVE_LIBC
245 int kbdfront_open(struct kbdfront_dev *dev)
246 {
247 dev->fd = alloc_fd(FTYPE_KBD);
248 printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
249 files[dev->fd].kbd.dev = dev;
250 return dev->fd;
251 }
252 #endif
258 DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
265 struct fbfront_dev {
266 domid_t dom;
268 struct xenfb_page *page;
269 evtchn_port_t evtchn;
271 char *nodename;
272 char *backend;
273 int request_update;
275 int width;
276 int height;
277 int depth;
278 int stride;
279 int mem_length;
280 int offset;
282 xenbus_event_queue events;
284 #ifdef HAVE_LIBC
285 int fd;
286 #endif
287 };
289 void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
290 {
291 #ifdef HAVE_LIBC
292 struct fbfront_dev *dev = data;
293 int fd = dev->fd;
295 if (fd != -1)
296 files[fd].read = 1;
297 #endif
298 wake_up(&fbfront_queue);
299 }
301 static void free_fbfront(struct fbfront_dev *dev)
302 {
303 mask_evtchn(dev->evtchn);
305 free(dev->backend);
307 free_page(dev->page);
309 unbind_evtchn(dev->evtchn);
311 free(dev->nodename);
312 free(dev);
313 }
315 int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
316 {
317 struct xenfb_page *page = dev->page;
318 uint32_t prod, cons;
319 int i;
321 #ifdef HAVE_LIBC
322 if (dev->fd != -1) {
323 files[dev->fd].read = 0;
324 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
325 }
326 #endif
328 prod = page->in_prod;
330 if (prod == page->in_cons)
331 return 0;
333 rmb(); /* ensure we see ring contents up to prod */
335 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
336 memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
338 mb(); /* ensure we got ring contents */
339 page->in_cons = cons;
340 notify_remote_via_evtchn(dev->evtchn);
342 #ifdef HAVE_LIBC
343 if (cons != prod && dev->fd != -1)
344 /* still some events to read */
345 files[dev->fd].read = 1;
346 #endif
348 return i;
349 }
351 struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
352 {
353 xenbus_transaction_t xbt;
354 char* err;
355 char* message=NULL;
356 struct xenfb_page *s;
357 int retry=0;
358 char* msg;
359 int i, j;
360 struct fbfront_dev *dev;
361 int max_pd;
362 unsigned long mapped;
363 char* nodename = _nodename ? _nodename : "device/vfb/0";
365 char path[strlen(nodename) + 1 + 10 + 1];
367 printk("******************* FBFRONT for %s **********\n\n\n", nodename);
369 dev = malloc(sizeof(*dev));
370 dev->nodename = strdup(nodename);
371 #ifdef HAVE_LIBC
372 dev->fd = -1;
373 #endif
375 snprintf(path, sizeof(path), "%s/backend-id", nodename);
376 dev->dom = xenbus_read_integer(path);
377 evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn);
379 dev->page = s = (struct xenfb_page*) alloc_page();
380 memset(s,0,PAGE_SIZE);
382 s->in_cons = s->in_prod = 0;
383 s->out_cons = s->out_prod = 0;
384 dev->width = s->width = width;
385 dev->height = s->height = height;
386 dev->depth = s->depth = depth;
387 dev->stride = s->line_length = stride;
388 dev->mem_length = s->mem_length = n * PAGE_SIZE;
389 dev->offset = 0;
390 dev->events = NULL;
392 max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
393 mapped = 0;
395 for (i = 0; mapped < n && i < max_pd; i++) {
396 unsigned long *pd = (unsigned long *) alloc_page();
397 for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
398 pd[j] = mfns[mapped++];
399 for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
400 pd[j] = 0;
401 s->pd[i] = virt_to_mfn(pd);
402 }
403 for ( ; i < max_pd; i++)
404 s->pd[i] = 0;
407 again:
408 err = xenbus_transaction_start(&xbt);
409 if (err) {
410 printk("starting transaction\n");
411 }
413 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
414 if (err) {
415 message = "writing page-ref";
416 goto abort_transaction;
417 }
418 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
419 if (err) {
420 message = "writing event-channel";
421 goto abort_transaction;
422 }
423 err = xenbus_printf(xbt, nodename, "protocol", "%s",
424 XEN_IO_PROTO_ABI_NATIVE);
425 if (err) {
426 message = "writing event-channel";
427 goto abort_transaction;
428 }
429 err = xenbus_printf(xbt, nodename, "feature-update", "1");
430 if (err) {
431 message = "writing event-channel";
432 goto abort_transaction;
433 }
435 err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
438 err = xenbus_transaction_end(xbt, 0, &retry);
439 if (retry) {
440 goto again;
441 printk("completing transaction\n");
442 }
444 goto done;
446 abort_transaction:
447 xenbus_transaction_end(xbt, 1, &retry);
448 goto error;
450 done:
452 snprintf(path, sizeof(path), "%s/backend", nodename);
453 msg = xenbus_read(XBT_NIL, path, &dev->backend);
454 if (msg) {
455 printk("Error %s when reading the backend path %s\n", msg, path);
456 goto error;
457 }
459 printk("backend at %s\n", dev->backend);
461 {
462 char path[strlen(dev->backend) + 1 + 14 + 1];
464 snprintf(path, sizeof(path), "%s/state", dev->backend);
466 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
468 xenbus_wait_for_value(path, "4", &dev->events);
470 printk("%s connected\n", dev->backend);
472 snprintf(path, sizeof(path), "%s/request-update", dev->backend);
473 dev->request_update = xenbus_read_integer(path);
475 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
476 }
477 unmask_evtchn(dev->evtchn);
479 printk("************************** FBFRONT\n");
481 return dev;
483 error:
484 free_fbfront(dev);
485 return NULL;
486 }
488 static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
489 {
490 struct xenfb_page *page = dev->page;
491 uint32_t prod;
492 DEFINE_WAIT(w);
494 add_waiter(w, fbfront_queue);
495 while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
496 schedule();
497 remove_waiter(w);
499 prod = page->out_prod;
500 mb(); /* ensure ring space available */
501 XENFB_OUT_RING_REF(page, prod) = *event;
502 wmb(); /* ensure ring contents visible */
503 page->out_prod = prod + 1;
504 notify_remote_via_evtchn(dev->evtchn);
505 }
507 void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
508 {
509 struct xenfb_update update;
511 if (dev->request_update <= 0)
512 return;
514 if (x < 0) {
515 width += x;
516 x = 0;
517 }
518 if (x + width > dev->width)
519 width = dev->width - x;
521 if (y < 0) {
522 height += y;
523 y = 0;
524 }
525 if (y + height > dev->height)
526 height = dev->height - y;
528 if (width <= 0 || height <= 0)
529 return;
531 update.type = XENFB_TYPE_UPDATE;
532 update.x = x;
533 update.y = y;
534 update.width = width;
535 update.height = height;
536 fbfront_out_event(dev, (union xenfb_out_event *) &update);
537 }
539 void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
540 {
541 struct xenfb_resize resize;
543 resize.type = XENFB_TYPE_RESIZE;
544 dev->width = resize.width = width;
545 dev->height = resize.height = height;
546 dev->stride = resize.stride = stride;
547 dev->depth = resize.depth = depth;
548 dev->offset = resize.offset = offset;
549 fbfront_out_event(dev, (union xenfb_out_event *) &resize);
550 }
552 void shutdown_fbfront(struct fbfront_dev *dev)
553 {
554 char* err;
555 char *nodename = dev->nodename;
557 char path[strlen(dev->backend) + 1 + 5 + 1];
559 printk("close fb: backend at %s\n",dev->backend);
561 snprintf(path, sizeof(path), "%s/state", dev->backend);
562 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
563 xenbus_wait_for_value(path, "5", &dev->events);
565 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
566 xenbus_wait_for_value(path, "6", &dev->events);
568 err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
569 // does not work yet
570 //xenbus_wait_for_value(path, "2", &dev->events);
572 xenbus_unwatch_path(XBT_NIL, path);
574 snprintf(path, sizeof(path), "%s/page-ref", nodename);
575 xenbus_rm(XBT_NIL, path);
576 snprintf(path, sizeof(path), "%s/event-channel", nodename);
577 xenbus_rm(XBT_NIL, path);
578 snprintf(path, sizeof(path), "%s/protocol", nodename);
579 xenbus_rm(XBT_NIL, path);
580 snprintf(path, sizeof(path), "%s/feature-update", nodename);
581 xenbus_rm(XBT_NIL, path);
583 unbind_evtchn(dev->evtchn);
585 free_fbfront(dev);
586 }
588 #ifdef HAVE_LIBC
589 int fbfront_open(struct fbfront_dev *dev)
590 {
591 dev->fd = alloc_fd(FTYPE_FB);
592 printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
593 files[dev->fd].fb.dev = dev;
594 return dev->fd;
595 }
596 #endif