⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vhci_driver.c

📁 linux virtual usb host source
💻 C
字号:
/* * Copyright (C) 2005-2007 Takahiro Hirofuchi */#include "usbip.h"static const char vhci_driver_name[] = "vhci_hcd";struct usbip_vhci_driver *vhci_driver;static struct usbip_imported_device *imported_device_init(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(vhci_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 int parse_status(char *value){	int ret = 0;	char *c;	for (int i = 0; i < vhci_driver->nports; i++)		bzero(&vhci_driver->idev[i], sizeof(struct usbip_imported_device));	/* skip a header line */	c = strchr(value, '\n') + 1;	while (*c != '\0') {		int port, status, speed, devid;		unsigned long socket;		char lbusid[SYSFS_BUS_ID_SIZE];		ret = sscanf(c, "%d %d %d %x %lx %s\n",				&port, &status, &speed,				&devid, &socket, lbusid);		if (ret < 5) {			err("scanf %d", ret);			BUG();		}		dbg("port %d status %d speed %d devid %x",				port, status, speed, devid);		dbg("socket %lx lbusid %s", socket, lbusid);		/* if a device is connected, look at it */		{			struct usbip_imported_device *idev = &vhci_driver->idev[port];			idev->port	= port;			idev->status	= status;			idev->devid	= devid;			idev->busnum	= (devid >> 16);			idev->devnum	= (devid & 0x0000ffff);			idev->cdev_list = dlist_new(sizeof(struct class_device));			if (!idev->cdev_list) {				err("init new device");				return -1;			}			if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {				idev = imported_device_init(idev, lbusid);				if (!idev) {					err("init new device");					return -1;				}			}		}		/* go to the next line */		c = strchr(c, '\n') + 1;	}	dbg("exit");	return 0;}static int check_usbip_device(struct sysfs_class_device *cdev){	char clspath[SYSFS_PATH_MAX];	/* /sys/class/video4linux/video0/device     */	char devpath[SYSFS_PATH_MAX];	/* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1  */	int ret;	snprintf(clspath, sizeof(clspath), "%s/device", cdev->path);	ret = sysfs_get_link(clspath, devpath, SYSFS_PATH_MAX);	if (!ret) {		if (!strncmp(devpath, vhci_driver->hc_device->path,					strlen(vhci_driver->hc_device->path))) {			/* found usbip device */			struct class_device *cdev;			cdev = calloc(1, sizeof(*cdev));			if (!cdev) {				err("calloc cdev");				return -1;			}			dlist_unshift(vhci_driver->cdev_list, (void*) cdev);			strncpy(cdev->clspath, clspath, sizeof(cdev->clspath));			strncpy(cdev->devpath, devpath, sizeof(cdev->clspath));			dbg("  found %s %s", clspath, devpath);		}	}	return 0;}static int search_class_for_usbip_device(char *cname){	struct sysfs_class *class;	struct dlist *cdev_list;	struct sysfs_class_device *cdev;	int ret = 0;	class = sysfs_open_class(cname);	if (!class) {		err("open class");		return -1;	}	dbg("class %s", class->name);	cdev_list = sysfs_get_class_devices(class);	if (!cdev_list)		/* nothing */		goto out;	dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {		dbg("   cdev %s", cdev->name);		ret = check_usbip_device(cdev);		if (ret < 0)			goto out;	}out:	sysfs_close_class(class);	return ret;}static int refresh_class_device_list(void){	int ret;	struct dlist *cname_list;	char *cname;	/* search under /sys/class */	cname_list = sysfs_open_directory_list("/sys/class");	if (!cname_list) {		err("open class directory");		return -1;	}	dlist_for_each_data(cname_list, cname, char) {		ret = search_class_for_usbip_device(cname);		if (ret < 0) {			sysfs_close_list(cname_list);			return -1;		}	}	sysfs_close_list(cname_list);	/* seach under /sys/block */	ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);	if (ret < 0)		return -1;	return 0;}static int refresh_imported_device_list(void){	struct sysfs_attribute *attr_status;	attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");	if (!attr_status) {		err("get attr %s of %s", "status", vhci_driver->hc_device->name);		return -1;	}	dbg("name %s, path %s, len %d, method %d\n", attr_status->name,			attr_status->path, attr_status->len, attr_status->method);	dbg("%s", attr_status->value);	return parse_status(attr_status->value);}static int get_nports(void){	int nports = 0;	struct sysfs_attribute *attr_status;	attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");	if (!attr_status) {		err("get attr %s of %s", "status", vhci_driver->hc_device->name);		return -1;	}	dbg("name %s, path %s, len %d, method %d\n", attr_status->name,			attr_status->path, attr_status->len, attr_status->method);	dbg("%s", attr_status->value);	{		char *c;		/* skip a header line */		c = strchr(attr_status->value, '\n') + 1;		while (*c != '\0') {			/* go to the next line */			c = strchr(c, '\n') + 1;			nports += 1;		}	}	return nports;}static int get_hc_busid(char *sysfs_mntpath, char *hc_busid){        struct sysfs_driver *sdriver;        char sdriver_path[SYSFS_PATH_MAX];	struct sysfs_device *hc_dev;	struct dlist *hc_devs;	int found = 0;        snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/platform/%s/%s",                                sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME,                                vhci_driver_name);        sdriver = sysfs_open_driver_path(sdriver_path);        if (!sdriver) {		info("%s is not found", sdriver_path);                info("load usbip_common_mod.ko and vhci-hcd.ko !");                return -1;        }	hc_devs = sysfs_get_driver_devices(sdriver);	if (!hc_devs) {		err("get hc list");		goto err;	}	/* assume only one vhci_hcd */	dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {		strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);		found = 1;	}err:	sysfs_close_driver(sdriver);	if (found)		return 0;	err("not found usbip hc");	return -1;}/* ---------------------------------------------------------------------- */int usbip_vhci_driver_open(void){	int ret;	char hc_busid[SYSFS_BUS_ID_SIZE];	vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));	if (!vhci_driver) {		err("alloc vhci_driver");		return -1;	}	ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);	if (ret < 0) {		err("sysfs must be mounted");		goto err;	}	ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);	if (ret < 0)		goto err;	/* will be freed in usbip_driver_close() */	vhci_driver->hc_device = sysfs_open_device("platform", hc_busid);	if (!vhci_driver->hc_device) {		err("get sysfs vhci_driver");		goto err;	}	vhci_driver->nports = get_nports();	info("%d ports available\n", vhci_driver->nports);	vhci_driver->cdev_list = dlist_new(sizeof(struct class_device));	if (!vhci_driver->cdev_list)		goto err;	if (refresh_class_device_list())		goto err;	if (refresh_imported_device_list())		goto err;	return 0;err:	if (vhci_driver->cdev_list)		dlist_destroy(vhci_driver->cdev_list);	if (vhci_driver->hc_device)		sysfs_close_device(vhci_driver->hc_device);	if (vhci_driver)		free(vhci_driver);	vhci_driver = NULL;	return -1;}void usbip_vhci_driver_close(){	if (!vhci_driver)		return;	if (vhci_driver->cdev_list)		dlist_destroy(vhci_driver->cdev_list);	for (int i = 0; i < vhci_driver->nports; i++) {		if (vhci_driver->idev[i].cdev_list)			dlist_destroy(vhci_driver->idev[i].cdev_list);	}	if (vhci_driver->hc_device)		sysfs_close_device(vhci_driver->hc_device);	free(vhci_driver);	vhci_driver = NULL;}int usbip_vhci_refresh_device_list(void){	if (vhci_driver->cdev_list)		dlist_destroy(vhci_driver->cdev_list);	for (int i = 0; i < vhci_driver->nports; i++) {		if (vhci_driver->idev[i].cdev_list)			dlist_destroy(vhci_driver->idev[i].cdev_list);	}	vhci_driver->cdev_list = dlist_new(sizeof(struct class_device));	if (!vhci_driver->cdev_list)		goto err;	if (refresh_class_device_list())		goto err;	if (refresh_imported_device_list())		goto err;	return 0;err:	if (vhci_driver->cdev_list)		dlist_destroy(vhci_driver->cdev_list);	for (int i = 0; i < vhci_driver->nports; i++) {		if (vhci_driver->idev[i].cdev_list)			dlist_destroy(vhci_driver->idev[i].cdev_list);	}	err("refresh device list");	return -1;}int usbip_vhci_get_free_port(void){	for (int i = 0; i < vhci_driver->nports; i++) {		if (vhci_driver->idev[i].status == VDEV_ST_NULL)			return i;	}	return -1;}int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,		uint32_t speed) {	struct sysfs_attribute *attr_attach;	char buff[200]; /* what size should be ? */	int ret;	attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");	if (!attr_attach) {		err("get attach");		return -1;	}	snprintf(buff, sizeof(buff), "%u %u %u %u",			port, sockfd, devid, speed);	dbg("writing: %s", buff);	ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));	if (ret < 0) {		err("write to attach failed");		return -1;	}	info("port %d attached", port);	return 0;}static unsigned long get_devid(uint8_t busnum, uint8_t devnum){	return (busnum << 16) | devnum;}/* will be removed */int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,		uint8_t devnum, uint32_t speed){	int devid = get_devid(busnum, devnum);	return usbip_vhci_attach_device2(port, sockfd, devid, speed);}int usbip_vhci_detach_device(uint8_t port){	struct sysfs_attribute  *attr_detach;	char buff[200]; /* what size should be ? */	int ret;	attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");	if (!attr_detach) {		err("get detach");		return -1;	}	snprintf(buff, sizeof(buff), "%u", port);	dbg("writing to detach");	dbg("writing: %s", buff);	ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));	if (ret < 0) {		err("write to detach failed");		return -1;	}	info("port %d detached", port);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -