diff options
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1967a7edc10c..d595aa5586a7 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -141,6 +141,14 @@ static void destroy_serial(struct kref *kref) | |||
141 | if (serial->minor != SERIAL_TTY_NO_MINOR) | 141 | if (serial->minor != SERIAL_TTY_NO_MINOR) |
142 | return_serial(serial); | 142 | return_serial(serial); |
143 | 143 | ||
144 | serial->type->release(serial); | ||
145 | |||
146 | for (i = 0; i < serial->num_ports; ++i) { | ||
147 | port = serial->port[i]; | ||
148 | if (port) | ||
149 | put_device(&port->dev); | ||
150 | } | ||
151 | |||
144 | /* If this is a "fake" port, we have to clean it up here, as it will | 152 | /* If this is a "fake" port, we have to clean it up here, as it will |
145 | * not get cleaned up in port_release() as it was never registered with | 153 | * not get cleaned up in port_release() as it was never registered with |
146 | * the driver core */ | 154 | * the driver core */ |
@@ -148,9 +156,8 @@ static void destroy_serial(struct kref *kref) | |||
148 | for (i = serial->num_ports; | 156 | for (i = serial->num_ports; |
149 | i < serial->num_port_pointers; ++i) { | 157 | i < serial->num_port_pointers; ++i) { |
150 | port = serial->port[i]; | 158 | port = serial->port[i]; |
151 | if (!port) | 159 | if (port) |
152 | continue; | 160 | port_free(port); |
153 | port_free(port); | ||
154 | } | 161 | } |
155 | } | 162 | } |
156 | 163 | ||
@@ -1046,10 +1053,15 @@ int usb_serial_probe(struct usb_interface *interface, | |||
1046 | 1053 | ||
1047 | dev_set_name(&port->dev, "ttyUSB%d", port->number); | 1054 | dev_set_name(&port->dev, "ttyUSB%d", port->number); |
1048 | dbg ("%s - registering %s", __func__, dev_name(&port->dev)); | 1055 | dbg ("%s - registering %s", __func__, dev_name(&port->dev)); |
1056 | port->dev_state = PORT_REGISTERING; | ||
1049 | retval = device_register(&port->dev); | 1057 | retval = device_register(&port->dev); |
1050 | if (retval) | 1058 | if (retval) { |
1051 | dev_err(&port->dev, "Error registering port device, " | 1059 | dev_err(&port->dev, "Error registering port device, " |
1052 | "continuing\n"); | 1060 | "continuing\n"); |
1061 | port->dev_state = PORT_UNREGISTERED; | ||
1062 | } else { | ||
1063 | port->dev_state = PORT_REGISTERED; | ||
1064 | } | ||
1053 | } | 1065 | } |
1054 | 1066 | ||
1055 | usb_serial_console_init(debug, minor); | 1067 | usb_serial_console_init(debug, minor); |
@@ -1113,10 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1113 | serial->disconnected = 1; | 1125 | serial->disconnected = 1; |
1114 | mutex_unlock(&serial->disc_mutex); | 1126 | mutex_unlock(&serial->disc_mutex); |
1115 | 1127 | ||
1116 | /* Unfortunately, many of the sub-drivers expect the port structures | ||
1117 | * to exist when their shutdown method is called, so we have to go | ||
1118 | * through this awkward two-step unregistration procedure. | ||
1119 | */ | ||
1120 | for (i = 0; i < serial->num_ports; ++i) { | 1128 | for (i = 0; i < serial->num_ports; ++i) { |
1121 | port = serial->port[i]; | 1129 | port = serial->port[i]; |
1122 | if (port) { | 1130 | if (port) { |
@@ -1130,17 +1138,25 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1130 | } | 1138 | } |
1131 | kill_traffic(port); | 1139 | kill_traffic(port); |
1132 | cancel_work_sync(&port->work); | 1140 | cancel_work_sync(&port->work); |
1133 | device_del(&port->dev); | 1141 | if (port->dev_state == PORT_REGISTERED) { |
1134 | } | 1142 | |
1135 | } | 1143 | /* Make sure the port is bound so that the |
1136 | serial->type->shutdown(serial); | 1144 | * driver's port_remove method is called. |
1137 | for (i = 0; i < serial->num_ports; ++i) { | 1145 | */ |
1138 | port = serial->port[i]; | 1146 | if (!port->dev.driver) { |
1139 | if (port) { | 1147 | int rc; |
1140 | put_device(&port->dev); | 1148 | |
1141 | serial->port[i] = NULL; | 1149 | port->dev.driver = |
1150 | &serial->type->driver; | ||
1151 | rc = device_bind_driver(&port->dev); | ||
1152 | } | ||
1153 | port->dev_state = PORT_UNREGISTERING; | ||
1154 | device_del(&port->dev); | ||
1155 | port->dev_state = PORT_UNREGISTERED; | ||
1156 | } | ||
1142 | } | 1157 | } |
1143 | } | 1158 | } |
1159 | serial->type->disconnect(serial); | ||
1144 | 1160 | ||
1145 | /* let the last holder of this object | 1161 | /* let the last holder of this object |
1146 | * cause it to be cleaned up */ | 1162 | * cause it to be cleaned up */ |
@@ -1318,7 +1334,8 @@ static void fixup_generic(struct usb_serial_driver *device) | |||
1318 | set_to_generic_if_null(device, chars_in_buffer); | 1334 | set_to_generic_if_null(device, chars_in_buffer); |
1319 | set_to_generic_if_null(device, read_bulk_callback); | 1335 | set_to_generic_if_null(device, read_bulk_callback); |
1320 | set_to_generic_if_null(device, write_bulk_callback); | 1336 | set_to_generic_if_null(device, write_bulk_callback); |
1321 | set_to_generic_if_null(device, shutdown); | 1337 | set_to_generic_if_null(device, disconnect); |
1338 | set_to_generic_if_null(device, release); | ||
1322 | } | 1339 | } |
1323 | 1340 | ||
1324 | int usb_serial_register(struct usb_serial_driver *driver) | 1341 | int usb_serial_register(struct usb_serial_driver *driver) |