mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
gcc (GCC) 4.6.2 20111027 (Red Hat 4.6.2-1) complains about unused variables in mini-os drivers Signed-off-by: John McDermott <john.mcdermott@nrl.navy.mil> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
700 lines
18 KiB
C
700 lines
18 KiB
C
/*
|
|
* Frame Buffer + Keyboard driver for Mini-OS.
|
|
* Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
|
|
* Based on blkfront.c.
|
|
*/
|
|
|
|
#include <mini-os/os.h>
|
|
#include <mini-os/xenbus.h>
|
|
#include <mini-os/events.h>
|
|
#include <xen/io/kbdif.h>
|
|
#include <xen/io/fbif.h>
|
|
#include <xen/io/protocols.h>
|
|
#include <mini-os/gnttab.h>
|
|
#include <mini-os/xmalloc.h>
|
|
#include <mini-os/fbfront.h>
|
|
#include <mini-os/lib.h>
|
|
|
|
DECLARE_WAIT_QUEUE_HEAD(kbdfront_queue);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct kbdfront_dev {
|
|
domid_t dom;
|
|
|
|
struct xenkbd_page *page;
|
|
evtchn_port_t evtchn;
|
|
|
|
char *nodename;
|
|
char *backend;
|
|
|
|
xenbus_event_queue events;
|
|
|
|
#ifdef HAVE_LIBC
|
|
int fd;
|
|
#endif
|
|
};
|
|
|
|
void kbdfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
|
|
{
|
|
#ifdef HAVE_LIBC
|
|
struct kbdfront_dev *dev = data;
|
|
int fd = dev->fd;
|
|
|
|
if (fd != -1)
|
|
files[fd].read = 1;
|
|
#endif
|
|
wake_up(&kbdfront_queue);
|
|
}
|
|
|
|
static void free_kbdfront(struct kbdfront_dev *dev)
|
|
{
|
|
mask_evtchn(dev->evtchn);
|
|
|
|
free(dev->backend);
|
|
|
|
free_page(dev->page);
|
|
|
|
unbind_evtchn(dev->evtchn);
|
|
|
|
free(dev->nodename);
|
|
free(dev);
|
|
}
|
|
|
|
struct kbdfront_dev *init_kbdfront(char *_nodename, int abs_pointer)
|
|
{
|
|
xenbus_transaction_t xbt;
|
|
char* err;
|
|
char* message=NULL;
|
|
struct xenkbd_page *s;
|
|
int retry=0;
|
|
char* msg = NULL;
|
|
char* nodename = _nodename ? _nodename : "device/vkbd/0";
|
|
struct kbdfront_dev *dev;
|
|
|
|
char path[strlen(nodename) + 1 + 10 + 1];
|
|
|
|
printk("******************* KBDFRONT for %s **********\n\n\n", nodename);
|
|
|
|
dev = malloc(sizeof(*dev));
|
|
memset(dev, 0, sizeof(*dev));
|
|
dev->nodename = strdup(nodename);
|
|
#ifdef HAVE_LIBC
|
|
dev->fd = -1;
|
|
#endif
|
|
|
|
snprintf(path, sizeof(path), "%s/backend-id", nodename);
|
|
dev->dom = xenbus_read_integer(path);
|
|
evtchn_alloc_unbound(dev->dom, kbdfront_handler, dev, &dev->evtchn);
|
|
|
|
dev->page = s = (struct xenkbd_page*) alloc_page();
|
|
memset(s,0,PAGE_SIZE);
|
|
|
|
dev->events = NULL;
|
|
|
|
s->in_cons = s->in_prod = 0;
|
|
s->out_cons = s->out_prod = 0;
|
|
|
|
again:
|
|
err = xenbus_transaction_start(&xbt);
|
|
if (err) {
|
|
printk("starting transaction\n");
|
|
free(err);
|
|
}
|
|
|
|
err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
|
|
if (err) {
|
|
message = "writing page-ref";
|
|
goto abort_transaction;
|
|
}
|
|
err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
|
|
if (err) {
|
|
message = "writing event-channel";
|
|
goto abort_transaction;
|
|
}
|
|
if (abs_pointer) {
|
|
err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1");
|
|
if (err) {
|
|
message = "writing event-channel";
|
|
goto abort_transaction;
|
|
}
|
|
}
|
|
|
|
snprintf(path, sizeof(path), "%s/state", nodename);
|
|
err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
|
|
if (err) {
|
|
printk("error writing initialized: %s\n", err);
|
|
free(err);
|
|
}
|
|
|
|
err = xenbus_transaction_end(xbt, 0, &retry);
|
|
if (err) free(err);
|
|
if (retry) {
|
|
goto again;
|
|
printk("completing transaction\n");
|
|
}
|
|
|
|
goto done;
|
|
|
|
abort_transaction:
|
|
free(err);
|
|
err = xenbus_transaction_end(xbt, 1, &retry);
|
|
printk("Abort transaction %s\n", message);
|
|
goto error;
|
|
|
|
done:
|
|
|
|
snprintf(path, sizeof(path), "%s/backend", nodename);
|
|
msg = xenbus_read(XBT_NIL, path, &dev->backend);
|
|
if (msg) {
|
|
printk("Error %s when reading the backend path %s\n", msg, path);
|
|
goto error;
|
|
}
|
|
|
|
printk("backend at %s\n", dev->backend);
|
|
|
|
{
|
|
XenbusState state;
|
|
char path[strlen(dev->backend) + 1 + 6 + 1];
|
|
char frontpath[strlen(nodename) + 1 + 6 + 1];
|
|
|
|
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
|
|
|
xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
|
|
|
|
err = NULL;
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && state < XenbusStateConnected)
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (state != XenbusStateConnected) {
|
|
printk("backend not available, state=%d\n", state);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
goto error;
|
|
}
|
|
|
|
printk("%s connected\n", dev->backend);
|
|
|
|
snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
|
|
if((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
|
|
!= NULL) {
|
|
printk("error switching state: %s\n", err);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
goto error;
|
|
}
|
|
}
|
|
unmask_evtchn(dev->evtchn);
|
|
|
|
printk("************************** KBDFRONT\n");
|
|
|
|
return dev;
|
|
error:
|
|
free(msg);
|
|
free(err);
|
|
free_kbdfront(dev);
|
|
return NULL;
|
|
}
|
|
|
|
int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n)
|
|
{
|
|
struct xenkbd_page *page = dev->page;
|
|
uint32_t prod, cons;
|
|
int i;
|
|
|
|
#ifdef HAVE_LIBC
|
|
if (dev->fd != -1) {
|
|
files[dev->fd].read = 0;
|
|
mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
|
|
}
|
|
#endif
|
|
|
|
prod = page->in_prod;
|
|
|
|
if (prod == page->in_cons)
|
|
return 0;
|
|
|
|
rmb(); /* ensure we see ring contents up to prod */
|
|
|
|
for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
|
|
memcpy(buf + i, &XENKBD_IN_RING_REF(page, cons), sizeof(*buf));
|
|
|
|
mb(); /* ensure we got ring contents */
|
|
page->in_cons = cons;
|
|
notify_remote_via_evtchn(dev->evtchn);
|
|
|
|
#ifdef HAVE_LIBC
|
|
if (cons != prod && dev->fd != -1)
|
|
/* still some events to read */
|
|
files[dev->fd].read = 1;
|
|
#endif
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
void shutdown_kbdfront(struct kbdfront_dev *dev)
|
|
{
|
|
char* err = NULL;
|
|
XenbusState state;
|
|
|
|
char path[strlen(dev->backend) + 1 + 5 + 1];
|
|
char nodename[strlen(dev->nodename) + 1 + 5 + 1];
|
|
|
|
printk("close kbd: backend at %s\n",dev->backend);
|
|
|
|
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
|
snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
|
|
printk("shutdown_kbdfront: error changing state to %d: %s\n",
|
|
XenbusStateClosing, err);
|
|
goto close_kbdfront;
|
|
}
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && state < XenbusStateClosing)
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (err) free(err);
|
|
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
|
|
printk("shutdown_kbdfront: error changing state to %d: %s\n",
|
|
XenbusStateClosed, err);
|
|
goto close_kbdfront;
|
|
}
|
|
state = xenbus_read_integer(path);
|
|
while (state < XenbusStateClosed) {
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (err) free(err);
|
|
}
|
|
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
|
|
printk("shutdown_kbdfront: error changing state to %d: %s\n",
|
|
XenbusStateInitialising, err);
|
|
goto close_kbdfront;
|
|
}
|
|
err = NULL;
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
|
|
close_kbdfront:
|
|
if (err) free(err);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
|
|
snprintf(path, sizeof(path), "%s/page-ref", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
snprintf(path, sizeof(path), "%s/event-channel", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
snprintf(path, sizeof(path), "%s/request-abs-pointer", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
|
|
if (!err)
|
|
free_kbdfront(dev);
|
|
}
|
|
|
|
#ifdef HAVE_LIBC
|
|
int kbdfront_open(struct kbdfront_dev *dev)
|
|
{
|
|
dev->fd = alloc_fd(FTYPE_KBD);
|
|
printk("kbd_open(%s) -> %d\n", dev->nodename, dev->fd);
|
|
files[dev->fd].kbd.dev = dev;
|
|
return dev->fd;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
DECLARE_WAIT_QUEUE_HEAD(fbfront_queue);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct fbfront_dev {
|
|
domid_t dom;
|
|
|
|
struct xenfb_page *page;
|
|
evtchn_port_t evtchn;
|
|
|
|
char *nodename;
|
|
char *backend;
|
|
int request_update;
|
|
|
|
int width;
|
|
int height;
|
|
int depth;
|
|
int stride;
|
|
int mem_length;
|
|
int offset;
|
|
|
|
xenbus_event_queue events;
|
|
|
|
#ifdef HAVE_LIBC
|
|
int fd;
|
|
#endif
|
|
};
|
|
|
|
void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
|
|
{
|
|
#ifdef HAVE_LIBC
|
|
struct fbfront_dev *dev = data;
|
|
int fd = dev->fd;
|
|
|
|
if (fd != -1)
|
|
files[fd].read = 1;
|
|
#endif
|
|
wake_up(&fbfront_queue);
|
|
}
|
|
|
|
static void free_fbfront(struct fbfront_dev *dev)
|
|
{
|
|
mask_evtchn(dev->evtchn);
|
|
|
|
free(dev->backend);
|
|
|
|
free_page(dev->page);
|
|
|
|
unbind_evtchn(dev->evtchn);
|
|
|
|
free(dev->nodename);
|
|
free(dev);
|
|
}
|
|
|
|
int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
|
|
{
|
|
struct xenfb_page *page = dev->page;
|
|
uint32_t prod, cons;
|
|
int i;
|
|
|
|
#ifdef HAVE_LIBC
|
|
if (dev->fd != -1) {
|
|
files[dev->fd].read = 0;
|
|
mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
|
|
}
|
|
#endif
|
|
|
|
prod = page->in_prod;
|
|
|
|
if (prod == page->in_cons)
|
|
return 0;
|
|
|
|
rmb(); /* ensure we see ring contents up to prod */
|
|
|
|
for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
|
|
memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
|
|
|
|
mb(); /* ensure we got ring contents */
|
|
page->in_cons = cons;
|
|
notify_remote_via_evtchn(dev->evtchn);
|
|
|
|
#ifdef HAVE_LIBC
|
|
if (cons != prod && dev->fd != -1)
|
|
/* still some events to read */
|
|
files[dev->fd].read = 1;
|
|
#endif
|
|
|
|
return i;
|
|
}
|
|
|
|
struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n)
|
|
{
|
|
xenbus_transaction_t xbt;
|
|
char* err;
|
|
char* message=NULL;
|
|
struct xenfb_page *s;
|
|
int retry=0;
|
|
char* msg;
|
|
int i, j;
|
|
struct fbfront_dev *dev;
|
|
int max_pd;
|
|
unsigned long mapped;
|
|
char* nodename = _nodename ? _nodename : "device/vfb/0";
|
|
|
|
char path[strlen(nodename) + 1 + 10 + 1];
|
|
|
|
printk("******************* FBFRONT for %s **********\n\n\n", nodename);
|
|
|
|
dev = malloc(sizeof(*dev));
|
|
memset(dev, 0, sizeof(*dev));
|
|
dev->nodename = strdup(nodename);
|
|
#ifdef HAVE_LIBC
|
|
dev->fd = -1;
|
|
#endif
|
|
|
|
snprintf(path, sizeof(path), "%s/backend-id", nodename);
|
|
dev->dom = xenbus_read_integer(path);
|
|
evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn);
|
|
|
|
dev->page = s = (struct xenfb_page*) alloc_page();
|
|
memset(s,0,PAGE_SIZE);
|
|
|
|
s->in_cons = s->in_prod = 0;
|
|
s->out_cons = s->out_prod = 0;
|
|
dev->width = s->width = width;
|
|
dev->height = s->height = height;
|
|
dev->depth = s->depth = depth;
|
|
dev->stride = s->line_length = stride;
|
|
dev->mem_length = s->mem_length = n * PAGE_SIZE;
|
|
dev->offset = 0;
|
|
dev->events = NULL;
|
|
|
|
max_pd = sizeof(s->pd) / sizeof(s->pd[0]);
|
|
mapped = 0;
|
|
|
|
for (i = 0; mapped < n && i < max_pd; i++) {
|
|
unsigned long *pd = (unsigned long *) alloc_page();
|
|
for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++)
|
|
pd[j] = mfns[mapped++];
|
|
for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++)
|
|
pd[j] = 0;
|
|
s->pd[i] = virt_to_mfn(pd);
|
|
}
|
|
for ( ; i < max_pd; i++)
|
|
s->pd[i] = 0;
|
|
|
|
|
|
again:
|
|
err = xenbus_transaction_start(&xbt);
|
|
if (err) {
|
|
printk("starting transaction\n");
|
|
free(err);
|
|
}
|
|
|
|
err = xenbus_printf(xbt, nodename, "page-ref","%u", virt_to_mfn(s));
|
|
if (err) {
|
|
message = "writing page-ref";
|
|
goto abort_transaction;
|
|
}
|
|
err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn);
|
|
if (err) {
|
|
message = "writing event-channel";
|
|
goto abort_transaction;
|
|
}
|
|
err = xenbus_printf(xbt, nodename, "protocol", "%s",
|
|
XEN_IO_PROTO_ABI_NATIVE);
|
|
if (err) {
|
|
message = "writing event-channel";
|
|
goto abort_transaction;
|
|
}
|
|
err = xenbus_printf(xbt, nodename, "feature-update", "1");
|
|
if (err) {
|
|
message = "writing event-channel";
|
|
goto abort_transaction;
|
|
}
|
|
|
|
snprintf(path, sizeof(path), "%s/state", nodename);
|
|
err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
|
|
if (err) {
|
|
message = "switching state";
|
|
goto abort_transaction;
|
|
}
|
|
|
|
err = xenbus_transaction_end(xbt, 0, &retry);
|
|
if (err) free(err);
|
|
if (retry) {
|
|
goto again;
|
|
printk("completing transaction\n");
|
|
}
|
|
|
|
goto done;
|
|
|
|
abort_transaction:
|
|
free(err);
|
|
err = xenbus_transaction_end(xbt, 1, &retry);
|
|
printk("Abort transaction %s\n", message);
|
|
goto error;
|
|
|
|
done:
|
|
|
|
snprintf(path, sizeof(path), "%s/backend", nodename);
|
|
msg = xenbus_read(XBT_NIL, path, &dev->backend);
|
|
if (msg) {
|
|
printk("Error %s when reading the backend path %s\n", msg, path);
|
|
goto error;
|
|
}
|
|
|
|
printk("backend at %s\n", dev->backend);
|
|
|
|
{
|
|
XenbusState state;
|
|
char path[strlen(dev->backend) + 1 + 14 + 1];
|
|
char frontpath[strlen(nodename) + 1 + 6 + 1];
|
|
|
|
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
|
|
|
xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
|
|
|
|
err = NULL;
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && state < XenbusStateConnected)
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (state != XenbusStateConnected) {
|
|
printk("backend not available, state=%d\n", state);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
goto error;
|
|
}
|
|
|
|
printk("%s connected\n", dev->backend);
|
|
|
|
snprintf(path, sizeof(path), "%s/request-update", dev->backend);
|
|
dev->request_update = xenbus_read_integer(path);
|
|
|
|
snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
|
|
if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
|
|
!= NULL) {
|
|
printk("error switching state: %s\n", err);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
goto error;
|
|
}
|
|
}
|
|
unmask_evtchn(dev->evtchn);
|
|
|
|
printk("************************** FBFRONT\n");
|
|
|
|
return dev;
|
|
|
|
error:
|
|
free(err);
|
|
free_fbfront(dev);
|
|
return NULL;
|
|
}
|
|
|
|
static void fbfront_out_event(struct fbfront_dev *dev, union xenfb_out_event *event)
|
|
{
|
|
struct xenfb_page *page = dev->page;
|
|
uint32_t prod;
|
|
DEFINE_WAIT(w);
|
|
|
|
add_waiter(w, fbfront_queue);
|
|
while (page->out_prod - page->out_cons == XENFB_OUT_RING_LEN)
|
|
schedule();
|
|
remove_waiter(w, fbfront_queue);
|
|
|
|
prod = page->out_prod;
|
|
mb(); /* ensure ring space available */
|
|
XENFB_OUT_RING_REF(page, prod) = *event;
|
|
wmb(); /* ensure ring contents visible */
|
|
page->out_prod = prod + 1;
|
|
notify_remote_via_evtchn(dev->evtchn);
|
|
}
|
|
|
|
void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int height)
|
|
{
|
|
struct xenfb_update update;
|
|
|
|
if (dev->request_update <= 0)
|
|
return;
|
|
|
|
if (x < 0) {
|
|
width += x;
|
|
x = 0;
|
|
}
|
|
if (x + width > dev->width)
|
|
width = dev->width - x;
|
|
|
|
if (y < 0) {
|
|
height += y;
|
|
y = 0;
|
|
}
|
|
if (y + height > dev->height)
|
|
height = dev->height - y;
|
|
|
|
if (width <= 0 || height <= 0)
|
|
return;
|
|
|
|
update.type = XENFB_TYPE_UPDATE;
|
|
update.x = x;
|
|
update.y = y;
|
|
update.width = width;
|
|
update.height = height;
|
|
fbfront_out_event(dev, (union xenfb_out_event *) &update);
|
|
}
|
|
|
|
void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride, int depth, int offset)
|
|
{
|
|
struct xenfb_resize resize;
|
|
|
|
resize.type = XENFB_TYPE_RESIZE;
|
|
dev->width = resize.width = width;
|
|
dev->height = resize.height = height;
|
|
dev->stride = resize.stride = stride;
|
|
dev->depth = resize.depth = depth;
|
|
dev->offset = resize.offset = offset;
|
|
fbfront_out_event(dev, (union xenfb_out_event *) &resize);
|
|
}
|
|
|
|
void shutdown_fbfront(struct fbfront_dev *dev)
|
|
{
|
|
char* err = NULL;
|
|
XenbusState state;
|
|
|
|
char path[strlen(dev->backend) + 1 + 5 + 1];
|
|
char nodename[strlen(dev->nodename) + 1 + 5 + 1];
|
|
|
|
printk("close fb: backend at %s\n",dev->backend);
|
|
|
|
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
|
snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
|
|
printk("shutdown_fbfront: error changing state to %d: %s\n",
|
|
XenbusStateClosing, err);
|
|
goto close_fbfront;
|
|
}
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && state < XenbusStateClosing)
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (err) free(err);
|
|
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
|
|
printk("shutdown_fbfront: error changing state to %d: %s\n",
|
|
XenbusStateClosed, err);
|
|
goto close_fbfront;
|
|
}
|
|
state = xenbus_read_integer(path);
|
|
if (state < XenbusStateClosed) {
|
|
xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
if (err) free(err);
|
|
}
|
|
|
|
if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
|
|
printk("shutdown_fbfront: error changing state to %d: %s\n",
|
|
XenbusStateInitialising, err);
|
|
goto close_fbfront;
|
|
}
|
|
|
|
err = NULL;
|
|
state = xenbus_read_integer(path);
|
|
while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
|
|
err = xenbus_wait_for_state_change(path, &state, &dev->events);
|
|
|
|
close_fbfront:
|
|
if (err) free(err);
|
|
xenbus_unwatch_path_token(XBT_NIL, path, path);
|
|
|
|
snprintf(path, sizeof(path), "%s/page-ref", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
snprintf(path, sizeof(path), "%s/event-channel", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
snprintf(path, sizeof(path), "%s/protocol", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
snprintf(path, sizeof(path), "%s/feature-update", nodename);
|
|
xenbus_rm(XBT_NIL, path);
|
|
|
|
if (!err)
|
|
free_fbfront(dev);
|
|
}
|
|
|
|
#ifdef HAVE_LIBC
|
|
int fbfront_open(struct fbfront_dev *dev)
|
|
{
|
|
dev->fd = alloc_fd(FTYPE_FB);
|
|
printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
|
|
files[dev->fd].fb.dev = dev;
|
|
return dev->fd;
|
|
}
|
|
#endif
|
|
|