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

Commit c706ebdf authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

USB: usb-serial: call port_probe and port_remove at the right times



This patch (as1253) prevents the usb-serial core from calling a
driver's port_probe and port_remove methods more than once per port.
It also removes some unnecessary try_module_get() calls and adds a
missing port_remove method call in a failure path.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c6994e6f
Loading
Loading
Loading
Loading
+11 −16
Original line number Diff line number Diff line
@@ -59,23 +59,22 @@ static int usb_serial_device_probe(struct device *dev)
		retval = -ENODEV;
		goto exit;
	}
	if (port->dev_state != PORT_REGISTERING)
		goto exit;

	driver = port->serial->type;
	if (driver->port_probe) {
		if (!try_module_get(driver->driver.owner)) {
			dev_err(dev, "module get failed, exiting\n");
			retval = -EIO;
			goto exit;
		}
		retval = driver->port_probe(port);
		module_put(driver->driver.owner);
		if (retval)
			goto exit;
	}

	retval = device_create_file(dev, &dev_attr_port_number);
	if (retval)
	if (retval) {
		if (driver->port_remove)
			retval = driver->port_remove(port);
		goto exit;
	}

	minor = port->number;
	tty_register_device(usb_serial_tty_driver, minor, dev);
@@ -98,19 +97,15 @@ static int usb_serial_device_remove(struct device *dev)
	if (!port)
		return -ENODEV;

	if (port->dev_state != PORT_UNREGISTERING)
		return retval;

	device_remove_file(&port->dev, &dev_attr_port_number);

	driver = port->serial->type;
	if (driver->port_remove) {
		if (!try_module_get(driver->driver.owner)) {
			dev_err(dev, "module get failed, exiting\n");
			retval = -EIO;
			goto exit;
		}
	if (driver->port_remove)
		retval = driver->port_remove(port);
		module_put(driver->driver.owner);
	}
exit:

	minor = port->number;
	tty_unregister_device(usb_serial_tty_driver, minor);
	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
+22 −2
Original line number Diff line number Diff line
@@ -1046,10 +1046,15 @@ int usb_serial_probe(struct usb_interface *interface,

		dev_set_name(&port->dev, "ttyUSB%d", port->number);
		dbg ("%s - registering %s", __func__, dev_name(&port->dev));
		port->dev_state = PORT_REGISTERING;
		retval = device_register(&port->dev);
		if (retval)
		if (retval) {
			dev_err(&port->dev, "Error registering port device, "
				"continuing\n");
			port->dev_state = PORT_UNREGISTERED;
		} else {
			port->dev_state = PORT_REGISTERED;
		}
	}

	usb_serial_console_init(debug, minor);
@@ -1130,7 +1135,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
			}
			kill_traffic(port);
			cancel_work_sync(&port->work);
			if (port->dev_state == PORT_REGISTERED) {

				/* Make sure the port is bound so that the
				 * driver's port_remove method is called.
				 */
				if (!port->dev.driver) {
					int rc;

					port->dev.driver =
							&serial->type->driver;
					rc = device_bind_driver(&port->dev);
				}
				port->dev_state = PORT_UNREGISTERING;
				device_del(&port->dev);
				port->dev_state = PORT_UNREGISTERED;
			}
		}
	}
	serial->type->shutdown(serial);
+8 −0
Original line number Diff line number Diff line
@@ -27,6 +27,13 @@
/* parity check flag */
#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))

enum port_dev_state {
	PORT_UNREGISTERED,
	PORT_REGISTERING,
	PORT_REGISTERED,
	PORT_UNREGISTERING,
};

/**
 * usb_serial_port: structure for the specific ports of a device.
 * @serial: pointer back to the struct usb_serial owner of this port.
@@ -102,6 +109,7 @@ struct usb_serial_port {
	char			console;
	unsigned long		sysrq; /* sysrq timeout */
	struct device		dev;
	enum port_dev_state	dev_state;
};
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)