ia64/xen-unstable

view extras/mini-os/fbfront.c @ 19836:d9890e67d2b7

tools: add SHAREDIR to buildmakevars2file

c/s 19818 dropped SHAREDIR from xen/util/path.py, which broke the "xm
new" command. This patch adds SHAREDIR back to the new
buildmakevars2file-closure function.

Signed-off-by: Ryan O'Connor <rjo@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:05:10 2009 +0100 (2009-06-25)
parents 18c8270da77c
children
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 snprintf(path, sizeof(path), "%s/state", nodename);
125 err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
126 if (err)
127 printk("error writing initialized: %s\n", err);
130 err = xenbus_transaction_end(xbt, 0, &retry);
131 if (retry) {
132 goto again;
133 printk("completing transaction\n");
134 }
136 goto done;
138 abort_transaction:
139 xenbus_transaction_end(xbt, 1, &retry);
140 goto error;
142 done:
144 snprintf(path, sizeof(path), "%s/backend", nodename);
145 msg = xenbus_read(XBT_NIL, path, &dev->backend);
146 if (msg) {
147 printk("Error %s when reading the backend path %s\n", msg, path);
148 goto error;
149 }
151 printk("backend at %s\n", dev->backend);
153 {
154 XenbusState state;
155 char path[strlen(dev->backend) + 1 + 6 + 1];
156 char frontpath[strlen(nodename) + 1 + 6 + 1];
158 snprintf(path, sizeof(path), "%s/state", dev->backend);
160 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
162 err = NULL;
163 state = xenbus_read_integer(path);
164 while (err == NULL && state < XenbusStateConnected)
165 err = xenbus_wait_for_state_change(path, &state, &dev->events);
166 if (state != XenbusStateConnected) {
167 printk("backend not available, state=%d\n", state);
168 xenbus_unwatch_path(XBT_NIL, path);
169 goto error;
170 }
172 printk("%s connected\n", dev->backend);
174 snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
175 if((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
176 != NULL) {
177 printk("error switching state: %s\n", err);
178 xenbus_unwatch_path(XBT_NIL, path);
179 goto error;
180 }
181 }
182 unmask_evtchn(dev->evtchn);
184 printk("************************** KBDFRONT\n");
186 return dev;
187 error:
188 free_kbdfront(dev);
189 return NULL;
190 }
192 int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
193 {
194 struct xenkbd_page *page = dev->page;
195 uint32_t prod, cons;
196 int i;
198 #ifdef HAVE_LIBC
199 if (dev->fd != -1) {
200 files[dev->fd].read = 0;
201 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
202 }
203 #endif
205 prod = page->in_prod;
207 if (prod == page->in_cons)
208 return 0;
210 rmb(); /* ensure we see ring contents up to prod */
212 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
213 memcpy(buf + i, &XENKBD_IN_RING_REF(page, cons), sizeof(*buf));
215 mb(); /* ensure we got ring contents */
216 page->in_cons = cons;
217 notify_remote_via_evtchn(dev->evtchn);
219 #ifdef HAVE_LIBC
220 if (cons != prod && dev->fd != -1)
221 /* still some events to read */
222 files[dev->fd].read = 1;
223 #endif
225 return i;
226 }
229 void shutdown_kbdfront(struct kbdfront_dev *dev)
230 {
231 char* err = NULL;
232 XenbusState state;
234 char path[strlen(dev->backend) + 1 + 5 + 1];
235 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
237 printk("close kbd: backend at %s\n",dev->backend);
239 snprintf(path, sizeof(path), "%s/state", dev->backend);
240 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
241 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
242 printk("shutdown_kbdfront: error changing state to %d: %s\n",
243 XenbusStateClosing, err);
244 goto close_kbdfront;
245 }
246 state = xenbus_read_integer(path);
247 while (err == NULL && state < XenbusStateClosing)
248 err = xenbus_wait_for_state_change(path, &state, &dev->events);
250 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
251 printk("shutdown_kbdfront: error changing state to %d: %s\n",
252 XenbusStateClosed, err);
253 goto close_kbdfront;
254 }
255 state = xenbus_read_integer(path);
256 if (state < XenbusStateClosed)
257 xenbus_wait_for_state_change(path, &state, &dev->events);
259 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
260 printk("shutdown_kbdfront: error changing state to %d: %s\n",
261 XenbusStateInitialising, err);
262 goto close_kbdfront;
263 }
264 // does not work yet.
265 //xenbus_wait_for_value(path, "2", &dev->events);
267 close_kbdfront:
268 xenbus_unwatch_path(XBT_NIL, path);
270 snprintf(path, sizeof(path), "%s/page-ref", nodename);
271 xenbus_rm(XBT_NIL, path);
272 snprintf(path, sizeof(path), "%s/event-channel", nodename);
273 xenbus_rm(XBT_NIL, path);
274 snprintf(path, sizeof(path), "%s/request-abs-pointer", nodename);
275 xenbus_rm(XBT_NIL, path);
277 free_kbdfront(dev);
278 }
280 #ifdef HAVE_LIBC
281 int kbdfront_open(struct kbdfront_dev *dev)
282 {
283 dev->fd = alloc_fd(FTYPE_KBD);
284 printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
285 files[dev->fd].kbd.dev = dev;
286 return dev->fd;
287 }
288 #endif
294 DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
301 struct fbfront_dev {
302 domid_t dom;
304 struct xenfb_page *page;
305 evtchn_port_t evtchn;
307 char *nodename;
308 char *backend;
309 int request_update;
311 int width;
312 int height;
313 int depth;
314 int stride;
315 int mem_length;
316 int offset;
318 xenbus_event_queue events;
320 #ifdef HAVE_LIBC
321 int fd;
322 #endif
323 };
325 void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
326 {
327 #ifdef HAVE_LIBC
328 struct fbfront_dev *dev = data;
329 int fd = dev->fd;
331 if (fd != -1)
332 files[fd].read = 1;
333 #endif
334 wake_up(&fbfront_queue);
335 }
337 static void free_fbfront(struct fbfront_dev *dev)
338 {
339 mask_evtchn(dev->evtchn);
341 free(dev->backend);
343 free_page(dev->page);
345 unbind_evtchn(dev->evtchn);
347 free(dev->nodename);
348 free(dev);
349 }
351 int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
352 {
353 struct xenfb_page *page = dev->page;
354 uint32_t prod, cons;
355 int i;
357 #ifdef HAVE_LIBC
358 if (dev->fd != -1) {
359 files[dev->fd].read = 0;
360 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
361 }
362 #endif
364 prod = page->in_prod;
366 if (prod == page->in_cons)
367 return 0;
369 rmb(); /* ensure we see ring contents up to prod */
371 for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
372 memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
374 mb(); /* ensure we got ring contents */
375 page->in_cons = cons;
376 notify_remote_via_evtchn(dev->evtchn);
378 #ifdef HAVE_LIBC
379 if (cons != prod && dev->fd != -1)
380 /* still some events to read */
381 files[dev->fd].read = 1;
382 #endif
384 return i;
385 }
387 struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
388 {
389 xenbus_transaction_t xbt;
390 char* err;
391 char* message=NULL;
392 struct xenfb_page *s;
393 int retry=0;
394 char* msg;
395 int i, j;
396 struct fbfront_dev *dev;
397 int max_pd;
398 unsigned long mapped;
399 char* nodename = _nodename ? _nodename : "device/vfb/0";
401 char path[strlen(nodename) + 1 + 10 + 1];
403 printk("******************* FBFRONT for %s **********\n\n\n", nodename);
405 dev = malloc(sizeof(*dev));
406 dev->nodename = strdup(nodename);
407 #ifdef HAVE_LIBC
408 dev->fd = -1;
409 #endif
411 snprintf(path, sizeof(path), "%s/backend-id", nodename);
412 dev->dom = xenbus_read_integer(path);
413 evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn);
415 dev->page = s = (struct xenfb_page*) alloc_page();
416 memset(s,0,PAGE_SIZE);
418 s->in_cons = s->in_prod = 0;
419 s->out_cons = s->out_prod = 0;
420 dev->width = s->width = width;
421 dev->height = s->height = height;
422 dev->depth = s->depth = depth;
423 dev->stride = s->line_length = stride;
424 dev->mem_length = s->mem_length = n * PAGE_SIZE;
425 dev->offset = 0;
426 dev->events = NULL;
428 max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
429 mapped = 0;
431 for (i = 0; mapped < n && i < max_pd; i++) {
432 unsigned long *pd = (unsigned long *) alloc_page();
433 for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
434 pd[j] = mfns[mapped++];
435 for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
436 pd[j] = 0;
437 s->pd[i] = virt_to_mfn(pd);
438 }
439 for ( ; i < max_pd; i++)
440 s->pd[i] = 0;
443 again:
444 err = xenbus_transaction_start(&xbt);
445 if (err) {
446 printk("starting transaction\n");
447 }
449 err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
450 if (err) {
451 message = "writing page-ref";
452 goto abort_transaction;
453 }
454 err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
455 if (err) {
456 message = "writing event-channel";
457 goto abort_transaction;
458 }
459 err = xenbus_printf(xbt, nodename, "protocol", "%s",
460 XEN_IO_PROTO_ABI_NATIVE);
461 if (err) {
462 message = "writing event-channel";
463 goto abort_transaction;
464 }
465 err = xenbus_printf(xbt, nodename, "feature-update", "1");
466 if (err) {
467 message = "writing event-channel";
468 goto abort_transaction;
469 }
471 snprintf(path, sizeof(path), "%s/state", nodename);
472 err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
473 if (err) {
474 message = "switching state";
475 goto abort_transaction;
476 }
478 err = xenbus_transaction_end(xbt, 0, &retry);
479 if (retry) {
480 goto again;
481 printk("completing transaction\n");
482 }
484 goto done;
486 abort_transaction:
487 xenbus_transaction_end(xbt, 1, &retry);
488 goto error;
490 done:
492 snprintf(path, sizeof(path), "%s/backend", nodename);
493 msg = xenbus_read(XBT_NIL, path, &dev->backend);
494 if (msg) {
495 printk("Error %s when reading the backend path %s\n", msg, path);
496 goto error;
497 }
499 printk("backend at %s\n", dev->backend);
501 {
502 XenbusState state;
503 char path[strlen(dev->backend) + 1 + 14 + 1];
504 char frontpath[strlen(nodename) + 1 + 6 + 1];
506 snprintf(path, sizeof(path), "%s/state", dev->backend);
508 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
510 err = NULL;
511 state = xenbus_read_integer(path);
512 while (err == NULL && state < XenbusStateConnected)
513 err = xenbus_wait_for_state_change(path, &state, &dev->events);
514 if (state != XenbusStateConnected) {
515 printk("backend not available, state=%d\n", state);
516 xenbus_unwatch_path(XBT_NIL, path);
517 goto error;
518 }
520 printk("%s connected\n", dev->backend);
522 snprintf(path, sizeof(path), "%s/request-update", dev->backend);
523 dev->request_update = xenbus_read_integer(path);
525 snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
526 if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
527 != NULL) {
528 printk("error switching state: %s\n", err);
529 xenbus_unwatch_path(XBT_NIL, path);
530 goto error;
531 }
532 }
533 unmask_evtchn(dev->evtchn);
535 printk("************************** FBFRONT\n");
537 return dev;
539 error:
540 free_fbfront(dev);
541 return NULL;
542 }
544 static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
545 {
546 struct xenfb_page *page = dev->page;
547 uint32_t prod;
548 DEFINE_WAIT(w);
550 add_waiter(w, fbfront_queue);
551 while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
552 schedule();
553 remove_waiter(w);
555 prod = page->out_prod;
556 mb(); /* ensure ring space available */
557 XENFB_OUT_RING_REF(page, prod) = *event;
558 wmb(); /* ensure ring contents visible */
559 page->out_prod = prod + 1;
560 notify_remote_via_evtchn(dev->evtchn);
561 }
563 void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
564 {
565 struct xenfb_update update;
567 if (dev->request_update <= 0)
568 return;
570 if (x < 0) {
571 width += x;
572 x = 0;
573 }
574 if (x + width > dev->width)
575 width = dev->width - x;
577 if (y < 0) {
578 height += y;
579 y = 0;
580 }
581 if (y + height > dev->height)
582 height = dev->height - y;
584 if (width <= 0 || height <= 0)
585 return;
587 update.type = XENFB_TYPE_UPDATE;
588 update.x = x;
589 update.y = y;
590 update.width = width;
591 update.height = height;
592 fbfront_out_event(dev, (union xenfb_out_event *) &update);
593 }
595 void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
596 {
597 struct xenfb_resize resize;
599 resize.type = XENFB_TYPE_RESIZE;
600 dev->width = resize.width = width;
601 dev->height = resize.height = height;
602 dev->stride = resize.stride = stride;
603 dev->depth = resize.depth = depth;
604 dev->offset = resize.offset = offset;
605 fbfront_out_event(dev, (union xenfb_out_event *) &resize);
606 }
608 void shutdown_fbfront(struct fbfront_dev *dev)
609 {
610 char* err = NULL;
611 XenbusState state;
613 char path[strlen(dev->backend) + 1 + 5 + 1];
614 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
616 printk("close fb: backend at %s\n",dev->backend);
618 snprintf(path, sizeof(path), "%s/state", dev->backend);
619 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
620 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
621 printk("shutdown_fbfront: error changing state to %d: %s\n",
622 XenbusStateClosing, err);
623 goto close_fbfront;
624 }
625 state = xenbus_read_integer(path);
626 while (err == NULL && state < XenbusStateClosing)
627 err = xenbus_wait_for_state_change(path, &state, &dev->events);
629 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
630 printk("shutdown_fbfront: error changing state to %d: %s\n",
631 XenbusStateClosed, err);
632 goto close_fbfront;
633 }
634 state = xenbus_read_integer(path);
635 if (state < XenbusStateClosed)
636 xenbus_wait_for_state_change(path, &state, &dev->events);
638 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
639 printk("shutdown_fbfront: error changing state to %d: %s\n",
640 XenbusStateInitialising, err);
641 goto close_fbfront;
642 }
643 // does not work yet
644 //xenbus_wait_for_value(path, "2", &dev->events);
646 close_fbfront:
647 xenbus_unwatch_path(XBT_NIL, path);
649 snprintf(path, sizeof(path), "%s/page-ref", nodename);
650 xenbus_rm(XBT_NIL, path);
651 snprintf(path, sizeof(path), "%s/event-channel", nodename);
652 xenbus_rm(XBT_NIL, path);
653 snprintf(path, sizeof(path), "%s/protocol", nodename);
654 xenbus_rm(XBT_NIL, path);
655 snprintf(path, sizeof(path), "%s/feature-update", nodename);
656 xenbus_rm(XBT_NIL, path);
658 unbind_evtchn(dev->evtchn);
660 free_fbfront(dev);
661 }
663 #ifdef HAVE_LIBC
664 int fbfront_open(struct fbfront_dev *dev)
665 {
666 dev->fd = alloc_fd(FTYPE_FB);
667 printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
668 files[dev->fd].fb.dev = dev;
669 return dev->fd;
670 }
671 #endif