xen_backend.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /*
  2. * xen backend driver infrastructure
  3. * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; under version 2 of the License.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * Contributions after 2012-01-13 are licensed under the terms of the
  18. * GNU GPL, version 2 or (at your option) any later version.
  19. */
  20. /*
  21. * TODO: add some xenbus / xenstore concepts overview here.
  22. */
  23. #include "qemu/osdep.h"
  24. #include <sys/signal.h>
  25. #include "hw/hw.h"
  26. #include "hw/sysbus.h"
  27. #include "hw/boards.h"
  28. #include "qemu/log.h"
  29. #include "qapi/error.h"
  30. #include "hw/xen/xen_backend.h"
  31. #include "hw/xen/xen_pvdev.h"
  32. #include "monitor/qdev.h"
  33. #include <xen/grant_table.h>
  34. DeviceState *xen_sysdev;
  35. BusState *xen_sysbus;
  36. /* ------------------------------------------------------------- */
  37. /* public */
  38. struct xs_handle *xenstore = NULL;
  39. const char *xen_protocol;
  40. /* private */
  41. static int debug;
  42. int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
  43. {
  44. return xenstore_write_str(xendev->be, node, val);
  45. }
  46. int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
  47. {
  48. return xenstore_write_int(xendev->be, node, ival);
  49. }
  50. int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
  51. {
  52. return xenstore_write_int64(xendev->be, node, ival);
  53. }
  54. char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
  55. {
  56. return xenstore_read_str(xendev->be, node);
  57. }
  58. int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
  59. {
  60. return xenstore_read_int(xendev->be, node, ival);
  61. }
  62. char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
  63. {
  64. return xenstore_read_str(xendev->fe, node);
  65. }
  66. int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
  67. {
  68. return xenstore_read_int(xendev->fe, node, ival);
  69. }
  70. int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
  71. uint64_t *uval)
  72. {
  73. return xenstore_read_uint64(xendev->fe, node, uval);
  74. }
  75. /* ------------------------------------------------------------- */
  76. int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
  77. {
  78. int rc;
  79. rc = xenstore_write_be_int(xendev, "state", state);
  80. if (rc < 0) {
  81. return rc;
  82. }
  83. xen_pv_printf(xendev, 1, "backend state: %s -> %s\n",
  84. xenbus_strstate(xendev->be_state), xenbus_strstate(state));
  85. xendev->be_state = state;
  86. return 0;
  87. }
  88. /*
  89. * get xen backend device, allocate a new one if it doesn't exist.
  90. */
  91. static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
  92. struct XenDevOps *ops)
  93. {
  94. struct XenDevice *xendev;
  95. xendev = xen_pv_find_xendev(type, dom, dev);
  96. if (xendev) {
  97. return xendev;
  98. }
  99. /* init new xendev */
  100. xendev = g_malloc0(ops->size);
  101. object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
  102. OBJECT(xendev)->free = g_free;
  103. qdev_set_parent_bus(DEVICE(xendev), xen_sysbus);
  104. qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev));
  105. qdev_init_nofail(DEVICE(xendev));
  106. object_unref(OBJECT(xendev));
  107. xendev->type = type;
  108. xendev->dom = dom;
  109. xendev->dev = dev;
  110. xendev->ops = ops;
  111. snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
  112. xendev->type, xendev->dom, xendev->dev);
  113. snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
  114. xendev->type, xendev->dev);
  115. xendev->debug = debug;
  116. xendev->local_port = -1;
  117. xendev->evtchndev = xenevtchn_open(NULL, 0);
  118. if (xendev->evtchndev == NULL) {
  119. xen_pv_printf(NULL, 0, "can't open evtchn device\n");
  120. qdev_unplug(DEVICE(xendev), NULL);
  121. return NULL;
  122. }
  123. qemu_set_cloexec(xenevtchn_fd(xendev->evtchndev));
  124. if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
  125. xendev->gnttabdev = xengnttab_open(NULL, 0);
  126. if (xendev->gnttabdev == NULL) {
  127. xen_pv_printf(NULL, 0, "can't open gnttab device\n");
  128. xenevtchn_close(xendev->evtchndev);
  129. qdev_unplug(DEVICE(xendev), NULL);
  130. return NULL;
  131. }
  132. } else {
  133. xendev->gnttabdev = NULL;
  134. }
  135. xen_pv_insert_xendev(xendev);
  136. if (xendev->ops->alloc) {
  137. xendev->ops->alloc(xendev);
  138. }
  139. return xendev;
  140. }
  141. /*
  142. * Sync internal data structures on xenstore updates.
  143. * Node specifies the changed field. node = NULL means
  144. * update all fields (used for initialization).
  145. */
  146. static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
  147. {
  148. if (node == NULL || strcmp(node, "online") == 0) {
  149. if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
  150. xendev->online = 0;
  151. }
  152. }
  153. if (node) {
  154. xen_pv_printf(xendev, 2, "backend update: %s\n", node);
  155. if (xendev->ops->backend_changed) {
  156. xendev->ops->backend_changed(xendev, node);
  157. }
  158. }
  159. }
  160. static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
  161. {
  162. int fe_state;
  163. if (node == NULL || strcmp(node, "state") == 0) {
  164. if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
  165. fe_state = XenbusStateUnknown;
  166. }
  167. if (xendev->fe_state != fe_state) {
  168. xen_pv_printf(xendev, 1, "frontend state: %s -> %s\n",
  169. xenbus_strstate(xendev->fe_state),
  170. xenbus_strstate(fe_state));
  171. }
  172. xendev->fe_state = fe_state;
  173. }
  174. if (node == NULL || strcmp(node, "protocol") == 0) {
  175. g_free(xendev->protocol);
  176. xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
  177. if (xendev->protocol) {
  178. xen_pv_printf(xendev, 1, "frontend protocol: %s\n",
  179. xendev->protocol);
  180. }
  181. }
  182. if (node) {
  183. xen_pv_printf(xendev, 2, "frontend update: %s\n", node);
  184. if (xendev->ops->frontend_changed) {
  185. xendev->ops->frontend_changed(xendev, node);
  186. }
  187. }
  188. }
  189. /* ------------------------------------------------------------- */
  190. /* Check for possible state transitions and perform them. */
  191. /*
  192. * Initial xendev setup. Read frontend path, register watch for it.
  193. * Should succeed once xend finished setting up the backend device.
  194. *
  195. * Also sets initial state (-> Initializing) when done. Which
  196. * only affects the xendev->be_state variable as xenbus should
  197. * already be put into that state by xend.
  198. */
  199. static int xen_be_try_setup(struct XenDevice *xendev)
  200. {
  201. char token[XEN_BUFSIZE];
  202. int be_state;
  203. if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
  204. xen_pv_printf(xendev, 0, "reading backend state failed\n");
  205. return -1;
  206. }
  207. if (be_state != XenbusStateInitialising) {
  208. xen_pv_printf(xendev, 0, "initial backend state is wrong (%s)\n",
  209. xenbus_strstate(be_state));
  210. return -1;
  211. }
  212. xendev->fe = xenstore_read_be_str(xendev, "frontend");
  213. if (xendev->fe == NULL) {
  214. xen_pv_printf(xendev, 0, "reading frontend path failed\n");
  215. return -1;
  216. }
  217. /* setup frontend watch */
  218. snprintf(token, sizeof(token), "fe:%p", xendev);
  219. if (!xs_watch(xenstore, xendev->fe, token)) {
  220. xen_pv_printf(xendev, 0, "watching frontend path (%s) failed\n",
  221. xendev->fe);
  222. return -1;
  223. }
  224. xen_be_set_state(xendev, XenbusStateInitialising);
  225. xen_be_backend_changed(xendev, NULL);
  226. xen_be_frontend_changed(xendev, NULL);
  227. return 0;
  228. }
  229. /*
  230. * Try initialize xendev. Prepare everything the backend can do
  231. * without synchronizing with the frontend. Fakes hotplug-status. No
  232. * hotplug involved here because this is about userspace drivers, thus
  233. * there are kernel backend devices which could invoke hotplug.
  234. *
  235. * Goes to InitWait on success.
  236. */
  237. static int xen_be_try_init(struct XenDevice *xendev)
  238. {
  239. int rc = 0;
  240. if (!xendev->online) {
  241. xen_pv_printf(xendev, 1, "not online\n");
  242. return -1;
  243. }
  244. if (xendev->ops->init) {
  245. rc = xendev->ops->init(xendev);
  246. }
  247. if (rc != 0) {
  248. xen_pv_printf(xendev, 1, "init() failed\n");
  249. return rc;
  250. }
  251. xenstore_write_be_str(xendev, "hotplug-status", "connected");
  252. xen_be_set_state(xendev, XenbusStateInitWait);
  253. return 0;
  254. }
  255. /*
  256. * Try to initialise xendev. Depends on the frontend being ready
  257. * for it (shared ring and evtchn info in xenstore, state being
  258. * Initialised or Connected).
  259. *
  260. * Goes to Connected on success.
  261. */
  262. static int xen_be_try_initialise(struct XenDevice *xendev)
  263. {
  264. int rc = 0;
  265. if (xendev->fe_state != XenbusStateInitialised &&
  266. xendev->fe_state != XenbusStateConnected) {
  267. if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
  268. xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n");
  269. } else {
  270. xen_pv_printf(xendev, 2, "frontend not ready (yet)\n");
  271. return -1;
  272. }
  273. }
  274. if (xendev->ops->initialise) {
  275. rc = xendev->ops->initialise(xendev);
  276. }
  277. if (rc != 0) {
  278. xen_pv_printf(xendev, 0, "initialise() failed\n");
  279. return rc;
  280. }
  281. xen_be_set_state(xendev, XenbusStateConnected);
  282. return 0;
  283. }
  284. /*
  285. * Try to let xendev know that it is connected. Depends on the
  286. * frontend being Connected. Note that this may be called more
  287. * than once since the backend state is not modified.
  288. */
  289. static void xen_be_try_connected(struct XenDevice *xendev)
  290. {
  291. if (!xendev->ops->connected) {
  292. return;
  293. }
  294. if (xendev->fe_state != XenbusStateConnected) {
  295. if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
  296. xen_pv_printf(xendev, 2, "frontend not ready, ignoring\n");
  297. } else {
  298. xen_pv_printf(xendev, 2, "frontend not ready (yet)\n");
  299. return;
  300. }
  301. }
  302. xendev->ops->connected(xendev);
  303. }
  304. /*
  305. * Teardown connection.
  306. *
  307. * Goes to Closed when done.
  308. */
  309. static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
  310. {
  311. if (xendev->be_state != XenbusStateClosing &&
  312. xendev->be_state != XenbusStateClosed &&
  313. xendev->ops->disconnect) {
  314. xendev->ops->disconnect(xendev);
  315. }
  316. if (xendev->be_state != state) {
  317. xen_be_set_state(xendev, state);
  318. }
  319. }
  320. /*
  321. * Try to reset xendev, for reconnection by another frontend instance.
  322. */
  323. static int xen_be_try_reset(struct XenDevice *xendev)
  324. {
  325. if (xendev->fe_state != XenbusStateInitialising) {
  326. return -1;
  327. }
  328. xen_pv_printf(xendev, 1, "device reset (for re-connect)\n");
  329. xen_be_set_state(xendev, XenbusStateInitialising);
  330. return 0;
  331. }
  332. /*
  333. * state change dispatcher function
  334. */
  335. void xen_be_check_state(struct XenDevice *xendev)
  336. {
  337. int rc = 0;
  338. /* frontend may request shutdown from almost anywhere */
  339. if (xendev->fe_state == XenbusStateClosing ||
  340. xendev->fe_state == XenbusStateClosed) {
  341. xen_be_disconnect(xendev, xendev->fe_state);
  342. return;
  343. }
  344. /* check for possible backend state transitions */
  345. for (;;) {
  346. switch (xendev->be_state) {
  347. case XenbusStateUnknown:
  348. rc = xen_be_try_setup(xendev);
  349. break;
  350. case XenbusStateInitialising:
  351. rc = xen_be_try_init(xendev);
  352. break;
  353. case XenbusStateInitWait:
  354. rc = xen_be_try_initialise(xendev);
  355. break;
  356. case XenbusStateConnected:
  357. /* xendev->be_state doesn't change */
  358. xen_be_try_connected(xendev);
  359. rc = -1;
  360. break;
  361. case XenbusStateClosed:
  362. rc = xen_be_try_reset(xendev);
  363. break;
  364. default:
  365. rc = -1;
  366. }
  367. if (rc != 0) {
  368. break;
  369. }
  370. }
  371. }
  372. /* ------------------------------------------------------------- */
  373. static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
  374. {
  375. struct XenDevice *xendev;
  376. char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
  377. char **dev = NULL;
  378. unsigned int cdev, j;
  379. /* setup watch */
  380. snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
  381. snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
  382. if (!xs_watch(xenstore, path, token)) {
  383. xen_pv_printf(NULL, 0, "xen be: watching backend path (%s) failed\n",
  384. path);
  385. return -1;
  386. }
  387. /* look for backends */
  388. dev = xs_directory(xenstore, 0, path, &cdev);
  389. if (!dev) {
  390. return 0;
  391. }
  392. for (j = 0; j < cdev; j++) {
  393. xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
  394. if (xendev == NULL) {
  395. continue;
  396. }
  397. xen_be_check_state(xendev);
  398. }
  399. free(dev);
  400. return 0;
  401. }
  402. void xenstore_update_be(char *watch, char *type, int dom,
  403. struct XenDevOps *ops)
  404. {
  405. struct XenDevice *xendev;
  406. char path[XEN_BUFSIZE], *bepath;
  407. unsigned int len, dev;
  408. len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
  409. if (strncmp(path, watch, len) != 0) {
  410. return;
  411. }
  412. if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
  413. strcpy(path, "");
  414. if (sscanf(watch+len, "/%u", &dev) != 1) {
  415. dev = -1;
  416. }
  417. }
  418. if (dev == -1) {
  419. return;
  420. }
  421. xendev = xen_be_get_xendev(type, dom, dev, ops);
  422. if (xendev != NULL) {
  423. bepath = xs_read(xenstore, 0, xendev->be, &len);
  424. if (bepath == NULL) {
  425. xen_pv_del_xendev(xendev);
  426. } else {
  427. free(bepath);
  428. xen_be_backend_changed(xendev, path);
  429. xen_be_check_state(xendev);
  430. }
  431. }
  432. }
  433. void xenstore_update_fe(char *watch, struct XenDevice *xendev)
  434. {
  435. char *node;
  436. unsigned int len;
  437. len = strlen(xendev->fe);
  438. if (strncmp(xendev->fe, watch, len) != 0) {
  439. return;
  440. }
  441. if (watch[len] != '/') {
  442. return;
  443. }
  444. node = watch + len + 1;
  445. xen_be_frontend_changed(xendev, node);
  446. xen_be_check_state(xendev);
  447. }
  448. /* -------------------------------------------------------------------- */
  449. int xen_be_init(void)
  450. {
  451. xenstore = xs_daemon_open();
  452. if (!xenstore) {
  453. xen_pv_printf(NULL, 0, "can't connect to xenstored\n");
  454. return -1;
  455. }
  456. qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
  457. if (xen_xc == NULL || xen_fmem == NULL) {
  458. /* Check if xen_init() have been called */
  459. goto err;
  460. }
  461. xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV);
  462. qdev_init_nofail(xen_sysdev);
  463. xen_sysbus = qbus_create(TYPE_XENSYSBUS, DEVICE(xen_sysdev), "xen-sysbus");
  464. qbus_set_bus_hotplug_handler(xen_sysbus, &error_abort);
  465. return 0;
  466. err:
  467. qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
  468. xs_daemon_close(xenstore);
  469. xenstore = NULL;
  470. return -1;
  471. }
  472. static void xen_set_dynamic_sysbus(void)
  473. {
  474. Object *machine = qdev_get_machine();
  475. ObjectClass *oc = object_get_class(machine);
  476. MachineClass *mc = MACHINE_CLASS(oc);
  477. mc->has_dynamic_sysbus = true;
  478. }
  479. int xen_be_register(const char *type, struct XenDevOps *ops)
  480. {
  481. char path[50];
  482. int rc;
  483. if (ops->backend_register) {
  484. rc = ops->backend_register();
  485. if (rc) {
  486. return rc;
  487. }
  488. }
  489. snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid,
  490. type);
  491. xenstore_mkdir(path, XS_PERM_NONE);
  492. return xenstore_scan(type, xen_domid, ops);
  493. }
  494. void xen_be_register_common(void)
  495. {
  496. xen_set_dynamic_sysbus();
  497. xen_be_register("console", &xen_console_ops);
  498. xen_be_register("vkbd", &xen_kbdmouse_ops);
  499. xen_be_register("qdisk", &xen_blkdev_ops);
  500. #ifdef CONFIG_VIRTFS
  501. xen_be_register("9pfs", &xen_9pfs_ops);
  502. #endif
  503. #ifdef CONFIG_USB_LIBUSB
  504. xen_be_register("qusb", &xen_usb_ops);
  505. #endif
  506. }
  507. int xen_be_bind_evtchn(struct XenDevice *xendev)
  508. {
  509. if (xendev->local_port != -1) {
  510. return 0;
  511. }
  512. xendev->local_port = xenevtchn_bind_interdomain
  513. (xendev->evtchndev, xendev->dom, xendev->remote_port);
  514. if (xendev->local_port == -1) {
  515. xen_pv_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
  516. return -1;
  517. }
  518. xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
  519. qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev),
  520. xen_pv_evtchn_event, NULL, xendev);
  521. return 0;
  522. }
  523. static Property xendev_properties[] = {
  524. DEFINE_PROP_END_OF_LIST(),
  525. };
  526. static void xendev_class_init(ObjectClass *klass, void *data)
  527. {
  528. DeviceClass *dc = DEVICE_CLASS(klass);
  529. dc->props = xendev_properties;
  530. set_bit(DEVICE_CATEGORY_MISC, dc->categories);
  531. /* xen-backend devices can be plugged/unplugged dynamically */
  532. dc->user_creatable = true;
  533. }
  534. static const TypeInfo xendev_type_info = {
  535. .name = TYPE_XENBACKEND,
  536. .parent = TYPE_XENSYSDEV,
  537. .class_init = xendev_class_init,
  538. .instance_size = sizeof(struct XenDevice),
  539. };
  540. static void xen_sysbus_class_init(ObjectClass *klass, void *data)
  541. {
  542. HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
  543. hc->unplug = qdev_simple_device_unplug_cb;
  544. }
  545. static const TypeInfo xensysbus_info = {
  546. .name = TYPE_XENSYSBUS,
  547. .parent = TYPE_BUS,
  548. .class_init = xen_sysbus_class_init,
  549. .interfaces = (InterfaceInfo[]) {
  550. { TYPE_HOTPLUG_HANDLER },
  551. { }
  552. }
  553. };
  554. static int xen_sysdev_init(SysBusDevice *dev)
  555. {
  556. return 0;
  557. }
  558. static Property xen_sysdev_properties[] = {
  559. {/* end of property list */},
  560. };
  561. static void xen_sysdev_class_init(ObjectClass *klass, void *data)
  562. {
  563. DeviceClass *dc = DEVICE_CLASS(klass);
  564. SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
  565. k->init = xen_sysdev_init;
  566. dc->props = xen_sysdev_properties;
  567. dc->bus_type = TYPE_XENSYSBUS;
  568. }
  569. static const TypeInfo xensysdev_info = {
  570. .name = TYPE_XENSYSDEV,
  571. .parent = TYPE_SYS_BUS_DEVICE,
  572. .instance_size = sizeof(SysBusDevice),
  573. .class_init = xen_sysdev_class_init,
  574. };
  575. static void xenbe_register_types(void)
  576. {
  577. type_register_static(&xensysbus_info);
  578. type_register_static(&xensysdev_info);
  579. type_register_static(&xendev_type_info);
  580. }
  581. type_init(xenbe_register_types)