Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7945b77 authored by Valentina Manea's avatar Valentina Manea Committed by Greg Kroah-Hartman
Browse files

staging: usbip: convert usbip-host driver to usb_device_driver



This driver was previously an interface driver. Since USB/IP
exports a whole device, not just an interface, it would make
sense to be a device driver.

This patch also modifies the way userspace sees and uses a
shared device:

* the usbip_status file is no longer created for interface 0, but for
the whole device (such as
/sys/devices/pci0000:00/0000:00:01.2/usb1/1-1/usbip_status).
* per interface information, such as interface class or protocol, is
no longer sent/received; only device specific information is
transmitted.
* since the driver was moved one level below in the USB architecture,
there is no need to bind/unbind each interface, just the device as a
whole.

Signed-off-by: default avatarValentina Manea <valentina.manea.m@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a6646ea6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ struct bus_id_priv {
extern struct kmem_cache *stub_priv_cache;

/* stub_dev.c */
extern struct usb_driver stub_driver;
extern struct usb_device_driver stub_driver;

/* stub_main.c */
struct bus_id_priv *get_busid_priv(const char *busid);
+53 −97
Original line number Diff line number Diff line
@@ -279,21 +279,19 @@ static void stub_device_unusable(struct usbip_device *ud)
 *
 * Allocates and initializes a new stub_device struct.
 */
static struct stub_device *stub_device_alloc(struct usb_device *udev,
					     struct usb_interface *interface)
static struct stub_device *stub_device_alloc(struct usb_device *udev)
{
	struct stub_device *sdev;
	int busnum = interface_to_busnum(interface);
	int devnum = interface_to_devnum(interface);
	int busnum = udev->bus->busnum;
	int devnum = udev->devnum;

	dev_dbg(&interface->dev, "allocating stub device");
	dev_dbg(&udev->dev, "allocating stub device");

	/* yes, it's a new device */
	sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
	if (!sdev)
		return NULL;

	sdev->interface = usb_get_intf(interface);
	sdev->udev = usb_get_dev(udev);

	/*
@@ -322,7 +320,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev,

	usbip_start_eh(&sdev->ud);

	dev_dbg(&interface->dev, "register new interface\n");
	dev_dbg(&udev->dev, "register new device\n");

	return sdev;
}
@@ -332,32 +330,20 @@ static void stub_device_free(struct stub_device *sdev)
	kfree(sdev);
}

/*
 * If a usb device has multiple active interfaces, this driver is bound to all
 * the active interfaces. However, usbip exports *a* usb device (i.e., not *an*
 * active interface). Currently, a userland program must ensure that it
 * looks at the usbip's sysfs entries of only the first active interface.
 *
 * TODO: use "struct usb_device_driver" to bind a usb device.
 * However, it seems it is not fully supported in mainline kernel yet
 * (2.6.19.2).
 */
static int stub_probe(struct usb_interface *interface,
		      const struct usb_device_id *id)
static int stub_probe(struct usb_device *udev)
{
	struct usb_device *udev = interface_to_usbdev(interface);
	struct stub_device *sdev = NULL;
	const char *udev_busid = dev_name(interface->dev.parent);
	int err = 0;
	const char *udev_busid = dev_name(&udev->dev);
	int err = 0, config;
	struct bus_id_priv *busid_priv;

	dev_dbg(&interface->dev, "Enter\n");
	dev_dbg(&udev->dev, "Enter\n");

	/* check we should claim or not by busid_table */
	busid_priv = get_busid_priv(udev_busid);
	if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
	    (busid_priv->status == STUB_BUSID_OTHER)) {
		dev_info(&interface->dev,
		dev_info(&udev->dev,
			"%s is not in match_busid table... skip!\n",
			udev_busid);

@@ -383,60 +369,36 @@ static int stub_probe(struct usb_interface *interface,
		return -ENODEV;
	}

	if (busid_priv->status == STUB_BUSID_ALLOC) {
		sdev = busid_priv->sdev;
		if (!sdev)
			return -ENODEV;

		busid_priv->interf_count++;
		dev_info(&interface->dev,
			"usbip-host: register new interface (bus %u dev %u ifn %u)\n",
			udev->bus->busnum, udev->devnum,
			interface->cur_altsetting->desc.bInterfaceNumber);

		/* set private data to usb_interface */
		usb_set_intfdata(interface, sdev);

		err = stub_add_files(&interface->dev);
		if (err) {
			dev_err(&interface->dev, "stub_add_files for %s\n",
				udev_busid);
			usb_set_intfdata(interface, NULL);
			busid_priv->interf_count--;
			return err;
		}

		usb_get_intf(interface);
		return 0;
	}

	/* ok, this is my device */
	sdev = stub_device_alloc(udev, interface);
	sdev = stub_device_alloc(udev);
	if (!sdev)
		return -ENOMEM;

	dev_info(&interface->dev,
		"usbip-host: register new device (bus %u dev %u ifn %u)\n",
		udev->bus->busnum, udev->devnum,
		interface->cur_altsetting->desc.bInterfaceNumber);
	dev_info(&udev->dev,
		"usbip-host: register new device (bus %u dev %u)\n",
		udev->bus->busnum, udev->devnum);

	busid_priv->interf_count = 0;
	busid_priv->shutdown_busid = 0;

	/* set private data to usb_interface */
	usb_set_intfdata(interface, sdev);
	busid_priv->interf_count++;
	config = usb_choose_configuration(udev);
	if (config >= 0) {
		err = usb_set_configuration(udev, config);
		if (err && err != -ENODEV)
			dev_err(&udev->dev, "can't set config #%d, error %d\n",
				config, err);
	}

	/* set private data to usb_device */
	dev_set_drvdata(&udev->dev, sdev);
	busid_priv->sdev = sdev;

	err = stub_add_files(&interface->dev);
	err = stub_add_files(&udev->dev);
	if (err) {
		dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid);
		usb_set_intfdata(interface, NULL);
		usb_put_intf(interface);
		dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
		dev_set_drvdata(&udev->dev, NULL);
		usb_put_dev(udev);
		kthread_stop_put(sdev->ud.eh);

		busid_priv->interf_count = 0;
		busid_priv->sdev = NULL;
		stub_device_free(sdev);
		return err;
@@ -461,13 +423,13 @@ static void shutdown_busid(struct bus_id_priv *busid_priv)
 * called in usb_disconnect() or usb_deregister()
 * but only if actconfig(active configuration) exists
 */
static void stub_disconnect(struct usb_interface *interface)
static void stub_disconnect(struct usb_device *udev)
{
	struct stub_device *sdev;
	const char *udev_busid = dev_name(interface->dev.parent);
	const char *udev_busid = dev_name(&udev->dev);
	struct bus_id_priv *busid_priv;

	dev_dbg(&interface->dev, "Enter\n");
	dev_dbg(&udev->dev, "Enter\n");

	busid_priv = get_busid_priv(udev_busid);
	if (!busid_priv) {
@@ -475,41 +437,29 @@ static void stub_disconnect(struct usb_interface *interface)
		return;
	}

	sdev = usb_get_intfdata(interface);
	sdev = dev_get_drvdata(&udev->dev);

	/* get stub_device */
	if (!sdev) {
		dev_err(&interface->dev, "could not get device");
		dev_err(&udev->dev, "could not get device");
		return;
	}

	usb_set_intfdata(interface, NULL);
	dev_set_drvdata(&udev->dev, NULL);

	/*
	 * NOTE: rx/tx threads are invoked for each usb_device.
	 */
	stub_remove_files(&interface->dev);
	stub_remove_files(&udev->dev);

	/* If usb reset is called from event handler */
	if (busid_priv->sdev->ud.eh == current) {
		busid_priv->interf_count--;
		return;
	}

	if (busid_priv->interf_count > 1) {
		busid_priv->interf_count--;
		shutdown_busid(busid_priv);
		usb_put_intf(interface);
	if (busid_priv->sdev->ud.eh == current)
		return;
	}

	busid_priv->interf_count = 0;

	/* shutdown the current connection */
	shutdown_busid(busid_priv);

	usb_put_dev(sdev->udev);
	usb_put_intf(interface);

	/* free sdev */
	busid_priv->sdev = NULL;
@@ -523,28 +473,34 @@ static void stub_disconnect(struct usb_interface *interface)
	}
}

/*
 * Presence of pre_reset and post_reset prevents the driver from being unbound
 * when the device is being reset
 */
#ifdef CONFIG_PM

/* These functions need usb_port_suspend and usb_port_resume,
 * which reside in drivers/usb/core/usb.h. Skip for now. */

static int stub_pre_reset(struct usb_interface *interface)
static int stub_suspend(struct usb_device *udev, pm_message_t message)
{
	dev_dbg(&interface->dev, "pre_reset\n");
	dev_dbg(&udev->dev, "stub_suspend\n");

	return 0;
}

static int stub_post_reset(struct usb_interface *interface)
static int stub_resume(struct usb_device *udev, pm_message_t message)
{
	dev_dbg(&interface->dev, "post_reset\n");
	dev_dbg(&udev->dev, "stub_resume\n");

	return 0;
}

struct usb_driver stub_driver = {
#endif	/* CONFIG_PM */

struct usb_device_driver stub_driver = {
	.name		= "usbip-host",
	.probe		= stub_probe,
	.disconnect	= stub_disconnect,
	.id_table	= stub_table,
	.pre_reset	= stub_pre_reset,
	.post_reset	= stub_post_reset,
#ifdef CONFIG_PM
	.suspend	= stub_suspend,
	.resume		= stub_resume,
#endif
	.supports_autosuspend	=	0,
};
+3 −3
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ static int __init usbip_host_init(void)
		return -ENOMEM;
	}

	ret = usb_register(&stub_driver);
	ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
	if (ret) {
		pr_err("usb_register failed %d\n", ret);
		goto err_usb_register;
@@ -271,7 +271,7 @@ static int __init usbip_host_init(void)
	return ret;

err_create_file:
	usb_deregister(&stub_driver);
	usb_deregister_device_driver(&stub_driver);
err_usb_register:
	kmem_cache_destroy(stub_priv_cache);
	return ret;
@@ -286,7 +286,7 @@ static void __exit usbip_host_exit(void)
	 * deregister() calls stub_disconnect() for all devices. Device
	 * specific data is cleared in stub_disconnect().
	 */
	usb_deregister(&stub_driver);
	usb_deregister_device_driver(&stub_driver);

	kmem_cache_destroy(stub_priv_cache);
}
+1 −1
Original line number Diff line number Diff line
@@ -550,7 +550,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
	int ret;
	struct usbip_header pdu;
	struct stub_device *sdev = container_of(ud, struct stub_device, ud);
	struct device *dev = &sdev->interface->dev;
	struct device *dev = &sdev->udev->dev;

	usbip_dbg_stub_rx("Enter\n");

+16 −29
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ struct usbip_host_driver *host_driver;

#define SYSFS_OPEN_RETRIES 100

/* only the first interface value is true! */
static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
{
	char attrpath[SYSFS_PATH_MAX];
@@ -56,8 +55,8 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
	 * usbip_status to reappear.
	 */

	snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status",
		 udev->path, udev->busid, udev->bConfigurationValue, 0);
	snprintf(attrpath, SYSFS_PATH_MAX, "%s/usbip_status",
		 udev->path);

	while (retries > 0) {
		if (stat(attrpath, &s) == 0)
@@ -168,19 +167,18 @@ static void delete_nothing(void *unused_data)

static int refresh_exported_devices(void)
{
	/* sysfs_device of usb_interface */
	struct sysfs_device	*suintf;
	struct dlist		*suintf_list;
	/* sysfs_device of usb_device */
	struct sysfs_device	*sudev;
	struct dlist		*sudev_list;
	struct dlist		*sudev_unique_list;
	struct usbip_exported_device *edev;

	sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device),
	sudev_unique_list = dlist_new_with_delete(sizeof(struct sysfs_device),
						  delete_nothing);

	suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver);
	if (!suintf_list) {
	sudev_list = sysfs_get_driver_devices(host_driver->sysfs_driver);

	if (!sudev_list) {
		/*
		 * Not an error condition. There are simply no devices bound to
		 * the driver yet.
@@ -190,23 +188,13 @@ static int refresh_exported_devices(void)
		return 0;
	}

	/* collect unique USB devices (not interfaces) */
	dlist_for_each_data(suintf_list, suintf, struct sysfs_device) {
		/* get usb device of this usb interface */
		sudev = sysfs_get_device_parent(suintf);
		if (!sudev) {
			dbg("sysfs_get_device_parent failed: %s", suintf->name);
			continue;
		}
	dlist_for_each_data(sudev_list, sudev, struct sysfs_device)
		if (check_new(sudev_unique_list, sudev))
			dlist_unshift(sudev_unique_list, sudev);

		if (check_new(sudev_list, sudev)) {
			/* insert item at head of list */
			dlist_unshift(sudev_list, sudev);
		}
	}

	dlist_for_each_data(sudev_list, sudev, struct sysfs_device) {
	dlist_for_each_data(sudev_unique_list, sudev, struct sysfs_device) {
		edev = usbip_exported_device_new(sudev->path);

		if (!edev) {
			dbg("usbip_exported_device_new failed");
			continue;
@@ -216,7 +204,7 @@ static int refresh_exported_devices(void)
		host_driver->ndevs++;
	}

	dlist_destroy(sudev_list);
	dlist_destroy(sudev_unique_list);

	return 0;
}
@@ -356,9 +344,8 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
	}

	/* only the first interface is true */
	snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s",
		 edev->udev.path, edev->udev.busid,
		 edev->udev.bConfigurationValue, 0, attr_name);
	snprintf(attr_path, sizeof(attr_path), "%s/%s",
		 edev->udev.path, attr_name);

	attr = sysfs_open_attribute(attr_path);
	if (!attr) {
Loading