1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include <sys/signal.h>
27
28#include "hw/hw.h"
29#include "hw/sysbus.h"
30#include "sysemu/char.h"
31#include "qemu/log.h"
32#include "hw/xen/xen_backend.h"
33
34#include <xen/grant_table.h>
35
36#define TYPE_XENSYSDEV "xensysdev"
37
38DeviceState *xen_sysdev;
39
40
41
42
43xc_interface *xen_xc = NULL;
44xenforeignmemory_handle *xen_fmem = NULL;
45struct xs_handle *xenstore = NULL;
46const char *xen_protocol;
47
48
49struct xs_dirs {
50 char *xs_dir;
51 QTAILQ_ENTRY(xs_dirs) list;
52};
53static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
54 QTAILQ_HEAD_INITIALIZER(xs_cleanup);
55
56static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
57static int debug = 0;
58
59
60
61static void xenstore_cleanup_dir(char *dir)
62{
63 struct xs_dirs *d;
64
65 d = g_malloc(sizeof(*d));
66 d->xs_dir = dir;
67 QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
68}
69
70void xen_config_cleanup(void)
71{
72 struct xs_dirs *d;
73
74 QTAILQ_FOREACH(d, &xs_cleanup, list) {
75 xs_rm(xenstore, 0, d->xs_dir);
76 }
77}
78
79int xenstore_write_str(const char *base, const char *node, const char *val)
80{
81 char abspath[XEN_BUFSIZE];
82
83 snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
84 if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
85 return -1;
86 }
87 return 0;
88}
89
90char *xenstore_read_str(const char *base, const char *node)
91{
92 char abspath[XEN_BUFSIZE];
93 unsigned int len;
94 char *str, *ret = NULL;
95
96 snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
97 str = xs_read(xenstore, 0, abspath, &len);
98 if (str != NULL) {
99
100
101 ret = g_strdup(str);
102 free(str);
103 }
104 return ret;
105}
106
107int xenstore_mkdir(char *path, int p)
108{
109 struct xs_permissions perms[2] = {
110 {
111 .id = 0,
112 }, {
113 .id = xen_domid,
114 .perms = p,
115 }
116 };
117
118 if (!xs_mkdir(xenstore, 0, path)) {
119 xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
120 return -1;
121 }
122 xenstore_cleanup_dir(g_strdup(path));
123
124 if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
125 xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
126 return -1;
127 }
128 return 0;
129}
130
131int xenstore_write_int(const char *base, const char *node, int ival)
132{
133 char val[12];
134
135 snprintf(val, sizeof(val), "%d", ival);
136 return xenstore_write_str(base, node, val);
137}
138
139int xenstore_write_int64(const char *base, const char *node, int64_t ival)
140{
141 char val[21];
142
143 snprintf(val, sizeof(val), "%"PRId64, ival);
144 return xenstore_write_str(base, node, val);
145}
146
147int xenstore_read_int(const char *base, const char *node, int *ival)
148{
149 char *val;
150 int rc = -1;
151
152 val = xenstore_read_str(base, node);
153 if (val && 1 == sscanf(val, "%d", ival)) {
154 rc = 0;
155 }
156 g_free(val);
157 return rc;
158}
159
160int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
161{
162 char *val;
163 int rc = -1;
164
165 val = xenstore_read_str(base, node);
166 if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
167 rc = 0;
168 }
169 g_free(val);
170 return rc;
171}
172
173int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
174{
175 return xenstore_write_str(xendev->be, node, val);
176}
177
178int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
179{
180 return xenstore_write_int(xendev->be, node, ival);
181}
182
183int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
184{
185 return xenstore_write_int64(xendev->be, node, ival);
186}
187
188char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
189{
190 return xenstore_read_str(xendev->be, node);
191}
192
193int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
194{
195 return xenstore_read_int(xendev->be, node, ival);
196}
197
198char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
199{
200 return xenstore_read_str(xendev->fe, node);
201}
202
203int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
204{
205 return xenstore_read_int(xendev->fe, node, ival);
206}
207
208int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval)
209{
210 return xenstore_read_uint64(xendev->fe, node, uval);
211}
212
213
214
215const char *xenbus_strstate(enum xenbus_state state)
216{
217 static const char *const name[] = {
218 [ XenbusStateUnknown ] = "Unknown",
219 [ XenbusStateInitialising ] = "Initialising",
220 [ XenbusStateInitWait ] = "InitWait",
221 [ XenbusStateInitialised ] = "Initialised",
222 [ XenbusStateConnected ] = "Connected",
223 [ XenbusStateClosing ] = "Closing",
224 [ XenbusStateClosed ] = "Closed",
225 };
226 return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
227}
228
229int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
230{
231 int rc;
232
233 rc = xenstore_write_be_int(xendev, "state", state);
234 if (rc < 0) {
235 return rc;
236 }
237 xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
238 xenbus_strstate(xendev->be_state), xenbus_strstate(state));
239 xendev->be_state = state;
240 return 0;
241}
242
243
244
245struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
246{
247 struct XenDevice *xendev;
248
249 QTAILQ_FOREACH(xendev, &xendevs, next) {
250 if (xendev->dom != dom) {
251 continue;
252 }
253 if (xendev->dev != dev) {
254 continue;
255 }
256 if (strcmp(xendev->type, type) != 0) {
257 continue;
258 }
259 return xendev;
260 }
261 return NULL;
262}
263
264
265
266
267static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
268 struct XenDevOps *ops)
269{
270 struct XenDevice *xendev;
271
272 xendev = xen_be_find_xendev(type, dom, dev);
273 if (xendev) {
274 return xendev;
275 }
276
277
278 xendev = g_malloc0(ops->size);
279 xendev->type = type;
280 xendev->dom = dom;
281 xendev->dev = dev;
282 xendev->ops = ops;
283
284 snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
285 xendev->type, xendev->dom, xendev->dev);
286 snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
287 xendev->type, xendev->dev);
288
289 xendev->debug = debug;
290 xendev->local_port = -1;
291
292 xendev->evtchndev = xenevtchn_open(NULL, 0);
293 if (xendev->evtchndev == NULL) {
294 xen_be_printf(NULL, 0, "can't open evtchn device\n");
295 g_free(xendev);
296 return NULL;
297 }
298 fcntl(xenevtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
299
300 if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
301 xendev->gnttabdev = xengnttab_open(NULL, 0);
302 if (xendev->gnttabdev == NULL) {
303 xen_be_printf(NULL, 0, "can't open gnttab device\n");
304 xenevtchn_close(xendev->evtchndev);
305 g_free(xendev);
306 return NULL;
307 }
308 } else {
309 xendev->gnttabdev = NULL;
310 }
311
312 QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
313
314 if (xendev->ops->alloc) {
315 xendev->ops->alloc(xendev);
316 }
317
318 return xendev;
319}
320
321
322
323
324static void xen_be_del_xendev(struct XenDevice *xendev)
325{
326 if (xendev->ops->free) {
327 xendev->ops->free(xendev);
328 }
329
330 if (xendev->fe) {
331 char token[XEN_BUFSIZE];
332 snprintf(token, sizeof(token), "fe:%p", xendev);
333 xs_unwatch(xenstore, xendev->fe, token);
334 g_free(xendev->fe);
335 }
336
337 if (xendev->evtchndev != NULL) {
338 xenevtchn_close(xendev->evtchndev);
339 }
340 if (xendev->gnttabdev != NULL) {
341 xengnttab_close(xendev->gnttabdev);
342 }
343
344 QTAILQ_REMOVE(&xendevs, xendev, next);
345 g_free(xendev);
346}
347
348
349
350
351
352
353static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
354{
355 if (node == NULL || strcmp(node, "online") == 0) {
356 if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
357 xendev->online = 0;
358 }
359 }
360
361 if (node) {
362 xen_be_printf(xendev, 2, "backend update: %s\n", node);
363 if (xendev->ops->backend_changed) {
364 xendev->ops->backend_changed(xendev, node);
365 }
366 }
367}
368
369static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
370{
371 int fe_state;
372
373 if (node == NULL || strcmp(node, "state") == 0) {
374 if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
375 fe_state = XenbusStateUnknown;
376 }
377 if (xendev->fe_state != fe_state) {
378 xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
379 xenbus_strstate(xendev->fe_state),
380 xenbus_strstate(fe_state));
381 }
382 xendev->fe_state = fe_state;
383 }
384 if (node == NULL || strcmp(node, "protocol") == 0) {
385 g_free(xendev->protocol);
386 xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
387 if (xendev->protocol) {
388 xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
389 }
390 }
391
392 if (node) {
393 xen_be_printf(xendev, 2, "frontend update: %s\n", node);
394 if (xendev->ops->frontend_changed) {
395 xendev->ops->frontend_changed(xendev, node);
396 }
397 }
398}
399
400
401
402
403
404
405
406
407
408
409
410
411static int xen_be_try_setup(struct XenDevice *xendev)
412{
413 char token[XEN_BUFSIZE];
414 int be_state;
415
416 if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
417 xen_be_printf(xendev, 0, "reading backend state failed\n");
418 return -1;
419 }
420
421 if (be_state != XenbusStateInitialising) {
422 xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
423 xenbus_strstate(be_state));
424 return -1;
425 }
426
427 xendev->fe = xenstore_read_be_str(xendev, "frontend");
428 if (xendev->fe == NULL) {
429 xen_be_printf(xendev, 0, "reading frontend path failed\n");
430 return -1;
431 }
432
433
434 snprintf(token, sizeof(token), "fe:%p", xendev);
435 if (!xs_watch(xenstore, xendev->fe, token)) {
436 xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
437 xendev->fe);
438 return -1;
439 }
440 xen_be_set_state(xendev, XenbusStateInitialising);
441
442 xen_be_backend_changed(xendev, NULL);
443 xen_be_frontend_changed(xendev, NULL);
444 return 0;
445}
446
447
448
449
450
451
452
453
454
455static int xen_be_try_init(struct XenDevice *xendev)
456{
457 int rc = 0;
458
459 if (!xendev->online) {
460 xen_be_printf(xendev, 1, "not online\n");
461 return -1;
462 }
463
464 if (xendev->ops->init) {
465 rc = xendev->ops->init(xendev);
466 }
467 if (rc != 0) {
468 xen_be_printf(xendev, 1, "init() failed\n");
469 return rc;
470 }
471
472 xenstore_write_be_str(xendev, "hotplug-status", "connected");
473 xen_be_set_state(xendev, XenbusStateInitWait);
474 return 0;
475}
476
477
478
479
480
481
482
483
484static int xen_be_try_initialise(struct XenDevice *xendev)
485{
486 int rc = 0;
487
488 if (xendev->fe_state != XenbusStateInitialised &&
489 xendev->fe_state != XenbusStateConnected) {
490 if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
491 xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
492 } else {
493 xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
494 return -1;
495 }
496 }
497
498 if (xendev->ops->initialise) {
499 rc = xendev->ops->initialise(xendev);
500 }
501 if (rc != 0) {
502 xen_be_printf(xendev, 0, "initialise() failed\n");
503 return rc;
504 }
505
506 xen_be_set_state(xendev, XenbusStateConnected);
507 return 0;
508}
509
510
511
512
513
514
515static void xen_be_try_connected(struct XenDevice *xendev)
516{
517 if (!xendev->ops->connected) {
518 return;
519 }
520
521 if (xendev->fe_state != XenbusStateConnected) {
522 if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
523 xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
524 } else {
525 xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
526 return;
527 }
528 }
529
530 xendev->ops->connected(xendev);
531}
532
533
534
535
536
537
538static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
539{
540 if (xendev->be_state != XenbusStateClosing &&
541 xendev->be_state != XenbusStateClosed &&
542 xendev->ops->disconnect) {
543 xendev->ops->disconnect(xendev);
544 }
545 if (xendev->be_state != state) {
546 xen_be_set_state(xendev, state);
547 }
548}
549
550
551
552
553static int xen_be_try_reset(struct XenDevice *xendev)
554{
555 if (xendev->fe_state != XenbusStateInitialising) {
556 return -1;
557 }
558
559 xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
560 xen_be_set_state(xendev, XenbusStateInitialising);
561 return 0;
562}
563
564
565
566
567void xen_be_check_state(struct XenDevice *xendev)
568{
569 int rc = 0;
570
571
572 if (xendev->fe_state == XenbusStateClosing ||
573 xendev->fe_state == XenbusStateClosed) {
574 xen_be_disconnect(xendev, xendev->fe_state);
575 return;
576 }
577
578
579 for (;;) {
580 switch (xendev->be_state) {
581 case XenbusStateUnknown:
582 rc = xen_be_try_setup(xendev);
583 break;
584 case XenbusStateInitialising:
585 rc = xen_be_try_init(xendev);
586 break;
587 case XenbusStateInitWait:
588 rc = xen_be_try_initialise(xendev);
589 break;
590 case XenbusStateConnected:
591
592 xen_be_try_connected(xendev);
593 rc = -1;
594 break;
595 case XenbusStateClosed:
596 rc = xen_be_try_reset(xendev);
597 break;
598 default:
599 rc = -1;
600 }
601 if (rc != 0) {
602 break;
603 }
604 }
605}
606
607
608
609static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
610{
611 struct XenDevice *xendev;
612 char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
613 char **dev = NULL;
614 unsigned int cdev, j;
615
616
617 snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
618 snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
619 if (!xs_watch(xenstore, path, token)) {
620 xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
621 return -1;
622 }
623
624
625 dev = xs_directory(xenstore, 0, path, &cdev);
626 if (!dev) {
627 return 0;
628 }
629 for (j = 0; j < cdev; j++) {
630 xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
631 if (xendev == NULL) {
632 continue;
633 }
634 xen_be_check_state(xendev);
635 }
636 free(dev);
637 return 0;
638}
639
640static void xenstore_update_be(char *watch, char *type, int dom,
641 struct XenDevOps *ops)
642{
643 struct XenDevice *xendev;
644 char path[XEN_BUFSIZE], *bepath;
645 unsigned int len, dev;
646
647 len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
648 if (strncmp(path, watch, len) != 0) {
649 return;
650 }
651 if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
652 strcpy(path, "");
653 if (sscanf(watch+len, "/%u", &dev) != 1) {
654 dev = -1;
655 }
656 }
657 if (dev == -1) {
658 return;
659 }
660
661 xendev = xen_be_get_xendev(type, dom, dev, ops);
662 if (xendev != NULL) {
663 bepath = xs_read(xenstore, 0, xendev->be, &len);
664 if (bepath == NULL) {
665 xen_be_del_xendev(xendev);
666 } else {
667 free(bepath);
668 xen_be_backend_changed(xendev, path);
669 xen_be_check_state(xendev);
670 }
671 }
672}
673
674static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
675{
676 char *node;
677 unsigned int len;
678
679 len = strlen(xendev->fe);
680 if (strncmp(xendev->fe, watch, len) != 0) {
681 return;
682 }
683 if (watch[len] != '/') {
684 return;
685 }
686 node = watch + len + 1;
687
688 xen_be_frontend_changed(xendev, node);
689 xen_be_check_state(xendev);
690}
691
692static void xenstore_update(void *unused)
693{
694 char **vec = NULL;
695 intptr_t type, ops, ptr;
696 unsigned int dom, count;
697
698 vec = xs_read_watch(xenstore, &count);
699 if (vec == NULL) {
700 goto cleanup;
701 }
702
703 if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
704 &type, &dom, &ops) == 3) {
705 xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
706 }
707 if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
708 xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
709 }
710
711cleanup:
712 free(vec);
713}
714
715static void xen_be_evtchn_event(void *opaque)
716{
717 struct XenDevice *xendev = opaque;
718 evtchn_port_t port;
719
720 port = xenevtchn_pending(xendev->evtchndev);
721 if (port != xendev->local_port) {
722 xen_be_printf(xendev, 0,
723 "xenevtchn_pending returned %d (expected %d)\n",
724 port, xendev->local_port);
725 return;
726 }
727 xenevtchn_unmask(xendev->evtchndev, port);
728
729 if (xendev->ops->event) {
730 xendev->ops->event(xendev);
731 }
732}
733
734
735
736int xen_be_init(void)
737{
738 xenstore = xs_daemon_open();
739 if (!xenstore) {
740 xen_be_printf(NULL, 0, "can't connect to xenstored\n");
741 return -1;
742 }
743
744 qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
745
746 if (xen_xc == NULL || xen_fmem == NULL) {
747
748 goto err;
749 }
750
751 xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV);
752 qdev_init_nofail(xen_sysdev);
753
754 return 0;
755
756err:
757 qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
758 xs_daemon_close(xenstore);
759 xenstore = NULL;
760
761 return -1;
762}
763
764int xen_be_register(const char *type, struct XenDevOps *ops)
765{
766 char path[50];
767 int rc;
768
769 if (ops->backend_register) {
770 rc = ops->backend_register();
771 if (rc) {
772 return rc;
773 }
774 }
775
776 snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid,
777 type);
778 xenstore_mkdir(path, XS_PERM_NONE);
779
780 return xenstore_scan(type, xen_domid, ops);
781}
782
783void xen_be_register_common(void)
784{
785 xen_be_register("console", &xen_console_ops);
786 xen_be_register("vkbd", &xen_kbdmouse_ops);
787 xen_be_register("qdisk", &xen_blkdev_ops);
788#ifdef CONFIG_USB_LIBUSB
789 xen_be_register("qusb", &xen_usb_ops);
790#endif
791}
792
793int xen_be_bind_evtchn(struct XenDevice *xendev)
794{
795 if (xendev->local_port != -1) {
796 return 0;
797 }
798 xendev->local_port = xenevtchn_bind_interdomain
799 (xendev->evtchndev, xendev->dom, xendev->remote_port);
800 if (xendev->local_port == -1) {
801 xen_be_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
802 return -1;
803 }
804 xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
805 qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev),
806 xen_be_evtchn_event, NULL, xendev);
807 return 0;
808}
809
810void xen_be_unbind_evtchn(struct XenDevice *xendev)
811{
812 if (xendev->local_port == -1) {
813 return;
814 }
815 qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
816 xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
817 xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
818 xendev->local_port = -1;
819}
820
821int xen_be_send_notify(struct XenDevice *xendev)
822{
823 return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
824}
825
826
827
828
829
830
831
832
833void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
834{
835 va_list args;
836
837 if (xendev) {
838 if (msg_level > xendev->debug) {
839 return;
840 }
841 qemu_log("xen be: %s: ", xendev->name);
842 if (msg_level == 0) {
843 fprintf(stderr, "xen be: %s: ", xendev->name);
844 }
845 } else {
846 if (msg_level > debug) {
847 return;
848 }
849 qemu_log("xen be core: ");
850 if (msg_level == 0) {
851 fprintf(stderr, "xen be core: ");
852 }
853 }
854 va_start(args, fmt);
855 qemu_log_vprintf(fmt, args);
856 va_end(args);
857 if (msg_level == 0) {
858 va_start(args, fmt);
859 vfprintf(stderr, fmt, args);
860 va_end(args);
861 }
862 qemu_log_flush();
863}
864
865static int xen_sysdev_init(SysBusDevice *dev)
866{
867 return 0;
868}
869
870static Property xen_sysdev_properties[] = {
871 {},
872};
873
874static void xen_sysdev_class_init(ObjectClass *klass, void *data)
875{
876 DeviceClass *dc = DEVICE_CLASS(klass);
877 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
878
879 k->init = xen_sysdev_init;
880 dc->props = xen_sysdev_properties;
881}
882
883static const TypeInfo xensysdev_info = {
884 .name = TYPE_XENSYSDEV,
885 .parent = TYPE_SYS_BUS_DEVICE,
886 .instance_size = sizeof(SysBusDevice),
887 .class_init = xen_sysdev_class_init,
888};
889
890static void xenbe_register_types(void)
891{
892 type_register_static(&xensysdev_info);
893}
894
895type_init(xenbe_register_types);
896