Just an update on my findings. It appears that this was either a design decision or a bug within the kernel. If anyone can answer that I'd love to know the answer.
It looks to me to be a problem with the ref counting in the USB serial driver. When the kref is created it starts with a value one. Once a device connects it increments. The destroy_serial triggers the sending of the uevent which would notify my program that the device has disconnected. But within serial_disconnect there is a only single kref_put, therefore the destory_serial is not called until the open device is closed. So, once the port is closed the kref_put is called and results in the proper cleanup and the uevent is sent.
To fix this problem for the USB serial you can use the following change within serial_disconnect:
Code:
if (serial) {
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port && port->tty)
{
tty_hangup(port->tty);
/* prevents a close from an open device crashing the driver */
port->tty->driver_data = NULL;
/* we are also done with the reference used by tty */
usb_serial_put(serial);
}
}
/* let the last holder of this object
* cause it to be cleaned up */
usb_serial_put(serial);
}
I have also seen the same behavior when using cdc-acm, therefore it is unclear if this is a bug or a design decision.
It seems to me that it should be a bug because how else is an application to know that the device has disconnected?