static struct usbip_imported_device *imported_device_init(struct usbip_vhci_driver *driver, struct usbip_imported_device *idev, char *busid) { struct sysfs_device *sudev; sudev = sysfs_open_device("usb", busid); if(!sudev) { err("sysfs_open_device %s", busid); goto err; } read_usb_device(sudev, &idev->udev); sysfs_close_device(sudev); /* add class devices of this imported device */ struct class_device *cdev; dlist_for_each_data(driver->cdev_list, cdev, struct class_device) { if(!strncmp(cdev->devpath, idev->udev.path, strlen(idev->udev.path))) { struct class_device *new_cdev; /* alloc and copy because dlist is linked from only one list */ new_cdev = calloc(1, sizeof(*new_cdev)); if(!new_cdev) goto err; memcpy(new_cdev, cdev, sizeof(*new_cdev)); dlist_unshift(idev->cdev_list, (void*) new_cdev); } } return idev; err: return NULL; }
static void usbip_exported_device_delete(void *dev) { struct usbip_exported_device *edev = (struct usbip_exported_device *) dev; sysfs_close_device(edev->sudev); free(dev); }
int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) { char product_name[100]; char host[NI_MAXHOST] = "unknown host"; char serv[NI_MAXSERV] = "unknown port"; char remote_busid[SYSFS_BUS_ID_SIZE]; int ret; int i; if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) { info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status)); return 0; } ret = read_record(idev->port, host, serv, remote_busid); if (ret) { err("read_record"); return -1; } info("Port %02d: <%s> at %s", idev->port, usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed)); usbip_names_get_product(product_name, sizeof(product_name), idev->udev.idVendor, idev->udev.idProduct); info(" %s", product_name); info("%10s -> usbip://%s:%s/%s (remote devid %08x (bus/dev %03d/%03d))", idev->udev.busid, host, serv, remote_busid, idev->devid, idev->busnum, idev->devnum); for (i=0; i < idev->udev.bNumInterfaces; i++) { /* show interface information */ struct sysfs_device *suinf; suinf = open_usb_interface(&idev->udev, i); if (!suinf) continue; info(" %6s used by %-17s", suinf->bus_id, suinf->driver_name); sysfs_close_device(suinf); /* show class device information */ struct class_device *cdev; dlist_for_each_data(idev->cdev_list, cdev, struct class_device) { int ifnum = get_interface_number(cdev->devpath); if (ifnum == i) { info(" %s", cdev->clspath); } } } return 0; }
/** * sysfs_close_class_device: closes a single class device. * @dev: class device to close. */ void sysfs_close_class_device(struct sysfs_class_device *dev) { if (dev) { if (dev->parent) sysfs_close_class_device(dev->parent); if (dev->sysdevice) sysfs_close_device(dev->sysdevice); if (dev->attrlist) dlist_destroy(dev->attrlist); free(dev); } }
static struct usbip_imported_device *usbip_imported_device_new(struct usbip_vhci_driver *driver, char *busid) { struct usbip_imported_device *idev = NULL; struct sysfs_device *sudev; idev = (struct usbip_imported_device *) calloc(1, sizeof(*idev)); if(!idev) return NULL; /* * The members of idev->cdev_list are also linked from * driver->cdev_list. They are freed by destroy of driver->cdev_list. * */ idev->cdev_list = dlist_new(sizeof(struct class_device)); if(!idev->cdev_list) goto err; sudev = sysfs_open_device("usb", busid); if(!sudev) { err("sysfs_open_device %s", busid); goto err; } read_usb_device(sudev, &idev->udev); sysfs_close_device(sudev); /* add class devices of this imported device */ struct class_device *cdev; dlist_for_each_data(driver->cdev_list, cdev, struct class_device) { if(!strncmp(cdev->devpath, idev->udev.path, strlen(idev->udev.path))) { struct class_device *new_cdev; new_cdev = calloc(1, sizeof(*new_cdev)); if(!new_cdev) goto err; memcpy(new_cdev, cdev, sizeof(*new_cdev)); dlist_unshift(idev->cdev_list, (void*) new_cdev); } } return idev; err: if(idev->cdev_list) dlist_destroy(idev->cdev_list); if(idev) free(idev); return NULL; }
const char *lookup_bus(const char *dname,topdev_info *tinf){ struct sysfs_device *dev; const struct bus *b; free(tinf->devname); tinf->devname = NULL; for(b = buses ; b->bus ; ++b){ if( (dev = sysfs_open_device(b->bus,dname)) ){ if(b->bus_lookup){ b->bus_lookup(dname,dev,tinf); } sysfs_close_device(dev); return b->bus; } } return NULL; }
static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) { struct usbip_exported_device *edev = NULL; size_t size; int i; edev = calloc(1, sizeof(*edev)); if (!edev) { dbg("calloc failed"); return NULL; } edev->sudev = sysfs_open_device_path(sdevpath); if (!edev->sudev) { dbg("sysfs_open_device_path failed: %s", sdevpath); goto err; } read_usb_device(edev->sudev, &edev->udev); edev->status = read_attr_usbip_status(&edev->udev); if (edev->status < 0) goto err; /* reallocate buffer to include usb interface data */ size = sizeof(*edev) + edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); edev = realloc(edev, size); if (!edev) { dbg("realloc failed"); goto err; } for (i = 0; i < edev->udev.bNumInterfaces; i++) read_usb_interface(&edev->udev, i, &edev->uinf[i]); return edev; err: if (edev && edev->sudev) sysfs_close_device(edev->sudev); if (edev) free(edev); return NULL; }
int read_usb_interface(struct usb_device *udev, int i, struct usb_interface *uinf) { char busid[SYSFS_BUS_ID_SIZE]; struct sysfs_device *sif; sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); sif = sysfs_open_device("usb", busid); if(!sif) { err("open sif of %s", busid); return -1; } READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n"); READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); sysfs_close_device(sif); return 0; }
static int list_devices(bool parsable) { char bus_type[] = "usb"; char busid[SYSFS_BUS_ID_SIZE]; char product_name[128]; struct sysfs_bus *ubus; struct sysfs_device *dev; struct sysfs_device *intf; struct sysfs_attribute *idVendor; struct sysfs_attribute *idProduct; struct sysfs_attribute *bConfValue; struct sysfs_attribute *bNumIntfs; struct dlist *devlist; int i; int ret = -1; ubus = sysfs_open_bus(bus_type); if (!ubus) { err("could not open %s bus: %s", bus_type, strerror(errno)); return -1; } devlist = sysfs_get_bus_devices(ubus); if (!devlist) { err("could not get %s bus devices: %s", bus_type, strerror(errno)); goto err_out; } /* remove interfaces and root hubs from device list */ dlist_filter_sort(devlist, is_device, devcmp); if (!parsable) { printf("Local USB devices\n"); printf("=================\n"); } dlist_for_each_data(devlist, dev, struct sysfs_device) { idVendor = sysfs_get_device_attr(dev, "idVendor"); idProduct = sysfs_get_device_attr(dev, "idProduct"); bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { err("problem getting device attributes: %s", strerror(errno)); goto err_out; } /* get product name */ usbip_names_get_product(product_name, sizeof(product_name), strtol(idVendor->value, NULL, 16), strtol(idProduct->value, NULL, 16)); print_device(dev->bus_id, idVendor->value, idProduct->value, parsable); print_product_name(product_name, parsable); for (i = 0; i < atoi(bNumIntfs->value); i++) { snprintf(busid, sizeof(busid), "%s:%.1s.%d", dev->bus_id, bConfValue->value, i); intf = sysfs_open_device(bus_type, busid); if (!intf) { err("could not open device interface: %s", strerror(errno)); goto err_out; } print_interface(busid, intf->driver_name, parsable); sysfs_close_device(intf); } printf("\n"); }
static void sysfs_close_driver_device(void *device) { sysfs_close_device((struct sysfs_device *)device); }
static void sysfs_close_dev(void *dev) { sysfs_close_device((struct sysfs_device *)dev); }
void get_usb_devs(hd_data_t *hd_data) { uint64_t ul0; unsigned u1, u2, u3; hd_t *hd, *hd1; usb_t *usb; str_list_t *sl, *usb_devs = NULL; char *s, *s1, *t; hd_res_t *res; size_t l; struct sysfs_bus *sf_bus; struct dlist *sf_dev_list; struct sysfs_device *sf_dev; struct sysfs_device *sf_dev_2; sf_bus = sysfs_open_bus("usb"); if(!sf_bus) { ADD2LOG("sysfs: no such bus: usb\n"); return; } sf_dev_list = sysfs_get_bus_devices(sf_bus); if(sf_dev_list) dlist_for_each_data(sf_dev_list, sf_dev, struct sysfs_device) { if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bNumInterfaces"), &ul0, 0)) { add_str_list(&usb_devs, sf_dev->path); ADD2LOG(" usb dev: %s\n", hd_sysfs_id(sf_dev->path)); } } if(sf_dev_list) dlist_for_each_data(sf_dev_list, sf_dev, struct sysfs_device) { ADD2LOG( " usb device: name = %s, bus_id = %s, bus = %s\n path = %s\n", sf_dev->name, sf_dev->bus_id, sf_dev->bus, hd_sysfs_id(sf_dev->path) ); if( hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceNumber"), &ul0, 16) ) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->detail = new_mem(sizeof *hd->detail); hd->detail->type = hd_detail_usb; hd->detail->usb.data = usb = new_mem(sizeof *usb); hd->sysfs_id = new_str(hd_sysfs_id(sf_dev->path)); hd->sysfs_bus_id = new_str(sf_dev->bus_id); hd->bus.id = bus_usb; hd->func = ul0; usb->ifdescr = ul0; if((s = hd_attr_str(sysfs_get_device_attr(sf_dev, "modalias")))) { s = canon_str(s, strlen(s)); ADD2LOG(" modalias = \"%s\"\n", s); if(s && *s) { hd->modalias = s; s = NULL; } s = free_mem(s); } ADD2LOG(" bInterfaceNumber = %u\n", hd->func); if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceClass"), &ul0, 16)) { usb->i_cls = ul0; ADD2LOG(" bInterfaceClass = %u\n", usb->i_cls); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceSubClass"), &ul0, 16)) { usb->i_sub = ul0; ADD2LOG(" bInterfaceSubClass = %u\n", usb->i_sub); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceProtocol"), &ul0, 16)) { usb->i_prot = ul0; ADD2LOG(" bInterfaceProtocol = %u\n", usb->i_prot); } /* device has longest matching sysfs id */ u2 = strlen(sf_dev->path); s = NULL; for(u3 = 0, sl = usb_devs; sl; sl = sl->next) { u1 = strlen(sl->str); if(u1 > u3 && u1 <= u2 && !strncmp(sf_dev->path, sl->str, u1)) { u3 = u1; s = sl->str; } } if(s) { ADD2LOG(" if: %s @ %s\n", hd->sysfs_bus_id, hd_sysfs_id(s)); sf_dev_2 = sysfs_open_device_path(s); if(sf_dev_2) { if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceClass"), &ul0, 16)) { usb->d_cls = ul0; ADD2LOG(" bDeviceClass = %u\n", usb->d_cls); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceSubClass"), &ul0, 16)) { usb->d_sub = ul0; ADD2LOG(" bDeviceSubClass = %u\n", usb->d_sub); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceProtocol"), &ul0, 16)) { usb->d_prot = ul0; ADD2LOG(" bDeviceProtocol = %u\n", usb->d_prot); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "idVendor"), &ul0, 16)) { usb->vendor = ul0; ADD2LOG(" idVendor = 0x%04x\n", usb->vendor); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "idProduct"), &ul0, 16)) { usb->device = ul0; ADD2LOG(" idProduct = 0x%04x\n", usb->device); } if((s = hd_attr_str(sysfs_get_device_attr(sf_dev_2, "manufacturer")))) { usb->manufact = canon_str(s, strlen(s)); ADD2LOG(" manufacturer = \"%s\"\n", usb->manufact); } if((s = hd_attr_str(sysfs_get_device_attr(sf_dev_2, "product")))) { usb->product = canon_str(s, strlen(s)); ADD2LOG(" product = \"%s\"\n", usb->product); } if((s = hd_attr_str(sysfs_get_device_attr(sf_dev_2, "serial")))) { usb->serial = canon_str(s, strlen(s)); ADD2LOG(" serial = \"%s\"\n", usb->serial); } if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bcdDevice"), &ul0, 16)) { usb->rev = ul0; ADD2LOG(" bcdDevice = %04x\n", usb->rev); } if((s = hd_attr_str(sysfs_get_device_attr(sf_dev_2, "speed")))) { s = canon_str(s, strlen(s)); if(!strcmp(s, "1.5")) usb->speed = 15*100000; else if(!strcmp(s, "12")) usb->speed = 12*1000000; else if(!strcmp(s, "480")) usb->speed = 480*1000000; ADD2LOG(" speed = \"%s\"\n", s); s = free_mem(s); } sysfs_close_device(sf_dev_2); } } if(usb->vendor || usb->device) { hd->vendor.id = MAKE_ID(TAG_USB, usb->vendor); hd->device.id = MAKE_ID(TAG_USB, usb->device); } if(usb->manufact) hd->vendor.name = new_str(usb->manufact); if(usb->product) hd->device.name = new_str(usb->product); if(usb->serial) hd->serial = new_str(usb->serial); if(usb->rev) str_printf(&hd->revision.name, 0, "%x.%02x", usb->rev >> 8, usb->rev & 0xff); if(usb->speed) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->baud.type = res_baud; res->baud.speed = usb->speed; } s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1); if(s) add_str_list(&hd->drivers, s); set_class_entries(hd_data, hd, usb); if(!hd_data->scanner_db) { hd_data->scanner_db = hd_module_list(hd_data, 1); } if( hd->drivers && search_str_list(hd_data->scanner_db, hd->drivers->str) ) { hd->base_class.id = bc_scanner; } // ###### FIXME if(hd->base_class.id == bc_modem) { hd->unix_dev_name = new_str("/dev/ttyACM0"); } }
/* call at unbound state */ static int bind_usbip(char *busid) { char bus_type[] = "usb"; char attr_name[] = "bind"; char sysfs_mntpath[SYSFS_PATH_MAX]; char bind_attr_path[SYSFS_PATH_MAX]; char intf_busid[SYSFS_BUS_ID_SIZE]; struct sysfs_device *busid_dev; struct sysfs_attribute *bind_attr; struct sysfs_attribute *bConfValue; struct sysfs_attribute *bNumIntfs; int i, failed = 0; int rc, ret = -1; rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); if (rc < 0) { err("sysfs must be mounted: %s", strerror(errno)); return -1; } snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); bind_attr = sysfs_open_attribute(bind_attr_path); if (!bind_attr) { dbg("problem getting bind attribute: %s", strerror(errno)); return -1; } busid_dev = sysfs_open_device(bus_type, busid); if (!busid_dev) { dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); goto err_close_bind_attr; } bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); if (!bConfValue || !bNumIntfs) { dbg("problem getting device attributes: %s", strerror(errno)); goto err_close_busid_dev; } for (i = 0; i < atoi(bNumIntfs->value); i++) { snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, bConfValue->value, i); rc = sysfs_write_attribute(bind_attr, intf_busid, SYSFS_BUS_ID_SIZE); if (rc < 0) { dbg("bind driver at %s failed", intf_busid); failed = 1; } } if (!failed) ret = 0; err_close_busid_dev: sysfs_close_device(busid_dev); err_close_bind_attr: sysfs_close_attribute(bind_attr); return ret; }
/* buggy driver may cause dead lock */ static int unbind_other(char *busid) { char bus_type[] = "usb"; char intf_busid[SYSFS_BUS_ID_SIZE]; struct sysfs_device *busid_dev; struct sysfs_device *intf_dev; struct sysfs_driver *intf_drv; struct sysfs_attribute *unbind_attr; struct sysfs_attribute *bConfValue; struct sysfs_attribute *bDevClass; struct sysfs_attribute *bNumIntfs; int i, rc; enum unbind_status status = UNBIND_ST_OK; busid_dev = sysfs_open_device(bus_type, busid); if (!busid_dev) { dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); return -1; } bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass"); bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); if (!bConfValue || !bDevClass || !bNumIntfs) { dbg("problem getting device attributes: %s", strerror(errno)); goto err_close_busid_dev; } if (!strncmp(bDevClass->value, "09", bDevClass->len)) { dbg("skip unbinding of hub"); goto err_close_busid_dev; } for (i = 0; i < atoi(bNumIntfs->value); i++) { snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, bConfValue->value, i); intf_dev = sysfs_open_device(bus_type, intf_busid); if (!intf_dev) { dbg("could not open interface device: %s", strerror(errno)); goto err_close_busid_dev; } dbg("%s -> %s", intf_dev->name, intf_dev->driver_name); if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN)) /* unbound interface */ continue; if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name, SYSFS_NAME_LEN)) { /* already bound to usbip-host */ status = UNBIND_ST_USBIP_HOST; continue; } /* unbinding */ intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name); if (!intf_drv) { dbg("could not open interface driver on %s: %s", intf_dev->name, strerror(errno)); goto err_close_intf_dev; } unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind"); if (!unbind_attr) { dbg("problem getting interface driver attribute: %s", strerror(errno)); goto err_close_intf_drv; } rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id, SYSFS_BUS_ID_SIZE); if (rc < 0) { /* NOTE: why keep unbinding other interfaces? */ dbg("unbind driver at %s failed", intf_dev->bus_id); status = UNBIND_ST_FAILED; } sysfs_close_driver(intf_drv); sysfs_close_device(intf_dev); } goto out; err_close_intf_drv: sysfs_close_driver(intf_drv); err_close_intf_dev: sysfs_close_device(intf_dev); err_close_busid_dev: status = UNBIND_ST_FAILED; out: sysfs_close_device(busid_dev); return status; }