/** * "Unplug" a device from a VM. * vusb_unassign() will "unassign" it, then * xenstore_create_usb() will be called to "detach" the device. * * @param domid The domid of the VM to unplug the device from * @param bus The bus ID of the device * @param device The ID of the device on the bus * * @return 0 for success, 1 for failure */ int usbowls_unplug_device(int domid, int bus, int device) { dominfo_t di; usbinfo_t ui; int ret; ret = xenstore_get_dominfo(domid, &di); if (ret != 0) { xd_log(LOG_ERR, "Invalid domid %d", domid); return 1; } ret = get_usbinfo(bus, device, &ui); if (ret != 0) { xd_log(LOG_ERR, "Invalid device %d-%d", bus, device); return 1; } ret = vusb_assign(ui.usb_vendor, ui.usb_product, 0); if (ret != 0) { xd_log(LOG_ERR, "Failed to unassign device"); return 1; } ret = xenstore_destroy_usb(&di, &ui); if (ret != 0) { xd_log(LOG_ERR, "Failed to detach device"); return 1; } return 0; }
/** * "Plug" a device to a VM. * xenstore_create_usb() will be called to "attach" the device, then * vusb_assign() will "assign" it. * * @param domid The domid of the VM to plug the device to * @param bus The bus ID of the device * @param device The ID of the device on the bus * * @return 0 for success, 1 for failure */ int usbowls_plug_device(int domid, int bus, int device) { dominfo_t di; usbinfo_t ui; int ret; ret = xenstore_get_dominfo(domid, &di); if (ret != 0) { xd_log(LOG_ERR, "Invalid domid %d", domid); return 1; } ret = get_usbinfo(bus, device, &ui); if (ret != 0) { xd_log(LOG_ERR, "Invalid device %d-%d", bus, device); return 1; } /* FIXME: nicely unbind dom0 drivers on interfaces? * Or not, USB supports hot unplug doesn't it? :) */ ret = xenstore_create_usb(&di, &ui); if (ret != 0) { xd_log(LOG_ERR, "Failed to attach device"); return 1; } if (xenstore_wait_for_online(&di, &ui) < 0) xd_log(LOG_ERR, "The frontend or the backend didn't go online, continue anyway"); ret = vusb_assign(ui.usb_vendor, ui.usb_product, 1); if (ret != 0) { xd_log(LOG_ERR, "Failed to assign device"); xenstore_destroy_usb(&di, &ui); return 1; } return 0; }
int main(int argc, char **argv) { int option = 0; int domid = -1, bus = -1, device = -1; int vassign = 0, vunassign = 0, attach = 0, detach = 0, list = 0, dump = 0; char *action = NULL; dominfo_t di; usbinfo_t ui; int ret = 0; xs_handle = xs_daemon_open(); if (xs_handle == NULL) { xd_log(LOG_ERR, "Failed to connect to xenstore"); exit(1); } if ((xs_dom0path = xs_get_domain_path(xs_handle, 0)) == NULL) { xd_log(LOG_ERR, "Could not get domain 0 path from XenStore"); exit(1); } while ((option = getopt(argc, argv, "D:b:d:")) != -1) { switch (option) { case 'D': domid = atoi(optarg); if (get_dominfo(domid, &di)) exit(1); break; case 'b': bus = atoi(optarg); break; case 'd': device = atoi(optarg); break; } } if (optind != argc-1) { usage(); } action = argv[optind]; vassign = !strcmp(action, "assign"); vunassign = !strcmp(action, "unassign"); attach = !strcmp(action, "attach"); detach = !strcmp(action, "detach"); list = !strcmp(action, "list"); dump = !strcmp(action, "dump"); if (vassign || vunassign || attach || detach || dump) { if (bus < 0 || device < 0) usage(); if (get_usbinfo(bus, device, &ui)) { if (detach) { /* can proceed detaching without detailed device info, we only need bus & dev num */ } else if (vunassign) { /* no device so nothing to unassign */ exit(0); } else { xd_log(LOG_ERR, "Failed to find device %d:%d", bus, device); exit(1); } } } if (optind == argc) { dump_dev(&ui); return 0; } if (dump) dump_dev(&ui); else if (vassign) ret = vusb_assign(ui.usb_vendor, ui.usb_product, 1); else if (vunassign) ret = vusb_assign(ui.usb_vendor, ui.usb_product, 0); else if (attach) { if (domid < 0) usage(); ret = xenstore_create_usb(&di, &ui); } else if (detach) { if (domid < 0) usage(); ret = xenstore_destroy_usb(&di, &ui); } else if (list) { if (domid < 0) usage(); list_domain_devs(&di); } if (ret) xd_log(LOG_ERR, "Operation failed"); return ret == 0 ? 0 : 1; }