diff options
author | Alan Cox <alan@redhat.com> | 2008-07-22 06:09:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-22 16:03:22 -0400 |
commit | 95da310e66ee8090119596c70ca8432e57f9a97f (patch) | |
tree | 7f18c30e9c9ad4d7d53df6453fa338be06f09a85 /drivers/usb/serial/usb-serial.c | |
parent | 1aa3692da57c773e5c76de55c5c4a953962d360e (diff) |
usb_serial: API all change
USB serial likes to use port->tty back pointers for the real work it does and
to do so without any actual locking. Unfortunately when you consider hangup
events, hangup/parallel reopen or even worse hangup followed by parallel close
events the tty->port and port->tty pointers are not guaranteed to be the same
as port->tty is the active tty while tty->port is the port the tty may or
may not still be attached to.
So rework the entire API to pass the tty struct. For console cases we need
to pass both for now. This shows up multiple drivers that immediately crash
with USB console some of which have been fixed in the process.
Longer term we need a proper tty as console abstraction
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 82 |
1 files changed, 41 insertions, 41 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 353798631903..ffaed8ace066 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -143,7 +143,7 @@ static void destroy_serial(struct kref *kref) | |||
143 | return_serial(serial); | 143 | return_serial(serial); |
144 | 144 | ||
145 | for (i = 0; i < serial->num_ports; ++i) | 145 | for (i = 0; i < serial->num_ports; ++i) |
146 | serial->port[i]->open_count = 0; | 146 | serial->port[i]->port.count = 0; |
147 | 147 | ||
148 | /* the ports are cleaned up and released in port_release() */ | 148 | /* the ports are cleaned up and released in port_release() */ |
149 | for (i = 0; i < serial->num_ports; ++i) | 149 | for (i = 0; i < serial->num_ports; ++i) |
@@ -208,14 +208,14 @@ static int serial_open (struct tty_struct *tty, struct file * filp) | |||
208 | goto bailout_kref_put; | 208 | goto bailout_kref_put; |
209 | } | 209 | } |
210 | 210 | ||
211 | ++port->open_count; | 211 | ++port->port.count; |
212 | 212 | ||
213 | /* set up our port structure making the tty driver | 213 | /* set up our port structure making the tty driver |
214 | * remember our port object, and us it */ | 214 | * remember our port object, and us it */ |
215 | tty->driver_data = port; | 215 | tty->driver_data = port; |
216 | port->tty = tty; | 216 | port->port.tty = tty; |
217 | 217 | ||
218 | if (port->open_count == 1) { | 218 | if (port->port.count == 1) { |
219 | 219 | ||
220 | /* lock this module before we call it | 220 | /* lock this module before we call it |
221 | * this may fail, which means we must bail out, | 221 | * this may fail, which means we must bail out, |
@@ -230,7 +230,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) | |||
230 | goto bailout_module_put; | 230 | goto bailout_module_put; |
231 | /* only call the device specific open if this | 231 | /* only call the device specific open if this |
232 | * is the first time the port is opened */ | 232 | * is the first time the port is opened */ |
233 | retval = serial->type->open(port, filp); | 233 | retval = serial->type->open(tty, port, filp); |
234 | if (retval) | 234 | if (retval) |
235 | goto bailout_interface_put; | 235 | goto bailout_interface_put; |
236 | } | 236 | } |
@@ -243,9 +243,9 @@ bailout_interface_put: | |||
243 | bailout_module_put: | 243 | bailout_module_put: |
244 | module_put(serial->type->driver.owner); | 244 | module_put(serial->type->driver.owner); |
245 | bailout_mutex_unlock: | 245 | bailout_mutex_unlock: |
246 | port->open_count = 0; | 246 | port->port.count = 0; |
247 | tty->driver_data = NULL; | 247 | tty->driver_data = NULL; |
248 | port->tty = NULL; | 248 | port->port.tty = NULL; |
249 | mutex_unlock(&port->mutex); | 249 | mutex_unlock(&port->mutex); |
250 | bailout_kref_put: | 250 | bailout_kref_put: |
251 | usb_serial_put(serial); | 251 | usb_serial_put(serial); |
@@ -263,26 +263,26 @@ static void serial_close(struct tty_struct *tty, struct file * filp) | |||
263 | 263 | ||
264 | mutex_lock(&port->mutex); | 264 | mutex_lock(&port->mutex); |
265 | 265 | ||
266 | if (port->open_count == 0) { | 266 | if (port->port.count == 0) { |
267 | mutex_unlock(&port->mutex); | 267 | mutex_unlock(&port->mutex); |
268 | return; | 268 | return; |
269 | } | 269 | } |
270 | 270 | ||
271 | --port->open_count; | 271 | --port->port.count; |
272 | if (port->open_count == 0) | 272 | if (port->port.count == 0) |
273 | /* only call the device specific close if this | 273 | /* only call the device specific close if this |
274 | * port is being closed by the last owner */ | 274 | * port is being closed by the last owner */ |
275 | port->serial->type->close(port, filp); | 275 | port->serial->type->close(tty, port, filp); |
276 | 276 | ||
277 | if (port->open_count == (port->console? 1 : 0)) { | 277 | if (port->port.count == (port->console? 1 : 0)) { |
278 | if (port->tty) { | 278 | if (port->port.tty) { |
279 | if (port->tty->driver_data) | 279 | if (port->port.tty->driver_data) |
280 | port->tty->driver_data = NULL; | 280 | port->port.tty->driver_data = NULL; |
281 | port->tty = NULL; | 281 | port->port.tty = NULL; |
282 | } | 282 | } |
283 | } | 283 | } |
284 | 284 | ||
285 | if (port->open_count == 0) { | 285 | if (port->port.count == 0) { |
286 | mutex_lock(&port->serial->disc_mutex); | 286 | mutex_lock(&port->serial->disc_mutex); |
287 | if (!port->serial->disconnected) | 287 | if (!port->serial->disconnected) |
288 | usb_autopm_put_interface(port->serial->interface); | 288 | usb_autopm_put_interface(port->serial->interface); |
@@ -304,12 +304,12 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int | |||
304 | 304 | ||
305 | dbg("%s - port %d, %d byte(s)", __func__, port->number, count); | 305 | dbg("%s - port %d, %d byte(s)", __func__, port->number, count); |
306 | 306 | ||
307 | /* open_count is managed under the mutex lock for the tty so cannot | 307 | /* count is managed under the mutex lock for the tty so cannot |
308 | drop to zero until after the last close completes */ | 308 | drop to zero until after the last close completes */ |
309 | WARN_ON(!port->open_count); | 309 | WARN_ON(!port->port.count); |
310 | 310 | ||
311 | /* pass on to the driver specific version of this function */ | 311 | /* pass on to the driver specific version of this function */ |
312 | retval = port->serial->type->write(port, buf, count); | 312 | retval = port->serial->type->write(tty, port, buf, count); |
313 | 313 | ||
314 | exit: | 314 | exit: |
315 | return retval; | 315 | return retval; |
@@ -319,9 +319,9 @@ static int serial_write_room (struct tty_struct *tty) | |||
319 | { | 319 | { |
320 | struct usb_serial_port *port = tty->driver_data; | 320 | struct usb_serial_port *port = tty->driver_data; |
321 | dbg("%s - port %d", __func__, port->number); | 321 | dbg("%s - port %d", __func__, port->number); |
322 | WARN_ON(!port->open_count); | 322 | WARN_ON(!port->port.count); |
323 | /* pass on to the driver specific version of this function */ | 323 | /* pass on to the driver specific version of this function */ |
324 | return port->serial->type->write_room(port); | 324 | return port->serial->type->write_room(tty); |
325 | } | 325 | } |
326 | 326 | ||
327 | static int serial_chars_in_buffer (struct tty_struct *tty) | 327 | static int serial_chars_in_buffer (struct tty_struct *tty) |
@@ -329,9 +329,9 @@ static int serial_chars_in_buffer (struct tty_struct *tty) | |||
329 | struct usb_serial_port *port = tty->driver_data; | 329 | struct usb_serial_port *port = tty->driver_data; |
330 | dbg("%s = port %d", __func__, port->number); | 330 | dbg("%s = port %d", __func__, port->number); |
331 | 331 | ||
332 | WARN_ON(!port->open_count); | 332 | WARN_ON(!port->port.count); |
333 | /* pass on to the driver specific version of this function */ | 333 | /* pass on to the driver specific version of this function */ |
334 | return port->serial->type->chars_in_buffer(port); | 334 | return port->serial->type->chars_in_buffer(tty); |
335 | } | 335 | } |
336 | 336 | ||
337 | static void serial_throttle (struct tty_struct * tty) | 337 | static void serial_throttle (struct tty_struct * tty) |
@@ -339,10 +339,10 @@ static void serial_throttle (struct tty_struct * tty) | |||
339 | struct usb_serial_port *port = tty->driver_data; | 339 | struct usb_serial_port *port = tty->driver_data; |
340 | dbg("%s - port %d", __func__, port->number); | 340 | dbg("%s - port %d", __func__, port->number); |
341 | 341 | ||
342 | WARN_ON(!port->open_count); | 342 | WARN_ON(!port->port.count); |
343 | /* pass on to the driver specific version of this function */ | 343 | /* pass on to the driver specific version of this function */ |
344 | if (port->serial->type->throttle) | 344 | if (port->serial->type->throttle) |
345 | port->serial->type->throttle(port); | 345 | port->serial->type->throttle(tty); |
346 | } | 346 | } |
347 | 347 | ||
348 | static void serial_unthrottle (struct tty_struct * tty) | 348 | static void serial_unthrottle (struct tty_struct * tty) |
@@ -350,10 +350,10 @@ static void serial_unthrottle (struct tty_struct * tty) | |||
350 | struct usb_serial_port *port = tty->driver_data; | 350 | struct usb_serial_port *port = tty->driver_data; |
351 | dbg("%s - port %d", __func__, port->number); | 351 | dbg("%s - port %d", __func__, port->number); |
352 | 352 | ||
353 | WARN_ON(!port->open_count); | 353 | WARN_ON(!port->port.count); |
354 | /* pass on to the driver specific version of this function */ | 354 | /* pass on to the driver specific version of this function */ |
355 | if (port->serial->type->unthrottle) | 355 | if (port->serial->type->unthrottle) |
356 | port->serial->type->unthrottle(port); | 356 | port->serial->type->unthrottle(tty); |
357 | } | 357 | } |
358 | 358 | ||
359 | static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) | 359 | static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) |
@@ -363,12 +363,12 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in | |||
363 | 363 | ||
364 | dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); | 364 | dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); |
365 | 365 | ||
366 | WARN_ON(!port->open_count); | 366 | WARN_ON(!port->port.count); |
367 | 367 | ||
368 | /* pass on to the driver specific version of this function if it is available */ | 368 | /* pass on to the driver specific version of this function if it is available */ |
369 | if (port->serial->type->ioctl) { | 369 | if (port->serial->type->ioctl) { |
370 | lock_kernel(); | 370 | lock_kernel(); |
371 | retval = port->serial->type->ioctl(port, file, cmd, arg); | 371 | retval = port->serial->type->ioctl(tty, file, cmd, arg); |
372 | unlock_kernel(); | 372 | unlock_kernel(); |
373 | } | 373 | } |
374 | else | 374 | else |
@@ -381,10 +381,10 @@ static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) | |||
381 | struct usb_serial_port *port = tty->driver_data; | 381 | struct usb_serial_port *port = tty->driver_data; |
382 | dbg("%s - port %d", __func__, port->number); | 382 | dbg("%s - port %d", __func__, port->number); |
383 | 383 | ||
384 | WARN_ON(!port->open_count); | 384 | WARN_ON(!port->port.count); |
385 | /* pass on to the driver specific version of this function if it is available */ | 385 | /* pass on to the driver specific version of this function if it is available */ |
386 | if (port->serial->type->set_termios) | 386 | if (port->serial->type->set_termios) |
387 | port->serial->type->set_termios(port, old); | 387 | port->serial->type->set_termios(tty, port, old); |
388 | else | 388 | else |
389 | tty_termios_copy_hw(tty->termios, old); | 389 | tty_termios_copy_hw(tty->termios, old); |
390 | } | 390 | } |
@@ -395,11 +395,11 @@ static void serial_break (struct tty_struct *tty, int break_state) | |||
395 | 395 | ||
396 | dbg("%s - port %d", __func__, port->number); | 396 | dbg("%s - port %d", __func__, port->number); |
397 | 397 | ||
398 | WARN_ON(!port->open_count); | 398 | WARN_ON(!port->port.count); |
399 | /* pass on to the driver specific version of this function if it is available */ | 399 | /* pass on to the driver specific version of this function if it is available */ |
400 | if (port->serial->type->break_ctl) { | 400 | if (port->serial->type->break_ctl) { |
401 | lock_kernel(); | 401 | lock_kernel(); |
402 | port->serial->type->break_ctl(port, break_state); | 402 | port->serial->type->break_ctl(tty, break_state); |
403 | unlock_kernel(); | 403 | unlock_kernel(); |
404 | } | 404 | } |
405 | } | 405 | } |
@@ -457,9 +457,9 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file) | |||
457 | 457 | ||
458 | dbg("%s - port %d", __func__, port->number); | 458 | dbg("%s - port %d", __func__, port->number); |
459 | 459 | ||
460 | WARN_ON(!port->open_count); | 460 | WARN_ON(!port->port.count); |
461 | if (port->serial->type->tiocmget) | 461 | if (port->serial->type->tiocmget) |
462 | return port->serial->type->tiocmget(port, file); | 462 | return port->serial->type->tiocmget(tty, file); |
463 | return -EINVAL; | 463 | return -EINVAL; |
464 | } | 464 | } |
465 | 465 | ||
@@ -470,9 +470,9 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file, | |||
470 | 470 | ||
471 | dbg("%s - port %d", __func__, port->number); | 471 | dbg("%s - port %d", __func__, port->number); |
472 | 472 | ||
473 | WARN_ON(!port->open_count); | 473 | WARN_ON(!port->port.count); |
474 | if (port->serial->type->tiocmset) | 474 | if (port->serial->type->tiocmset) |
475 | return port->serial->type->tiocmset(port, file, set, clear); | 475 | return port->serial->type->tiocmset(tty, file, set, clear); |
476 | return -EINVAL; | 476 | return -EINVAL; |
477 | } | 477 | } |
478 | 478 | ||
@@ -497,7 +497,7 @@ static void usb_serial_port_work(struct work_struct *work) | |||
497 | if (!port) | 497 | if (!port) |
498 | return; | 498 | return; |
499 | 499 | ||
500 | tty = port->tty; | 500 | tty = port->port.tty; |
501 | if (!tty) | 501 | if (!tty) |
502 | return; | 502 | return; |
503 | 503 | ||
@@ -1010,8 +1010,8 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1010 | for (i = 0; i < serial->num_ports; ++i) { | 1010 | for (i = 0; i < serial->num_ports; ++i) { |
1011 | port = serial->port[i]; | 1011 | port = serial->port[i]; |
1012 | if (port) { | 1012 | if (port) { |
1013 | if (port->tty) | 1013 | if (port->port.tty) |
1014 | tty_hangup(port->tty); | 1014 | tty_hangup(port->port.tty); |
1015 | kill_traffic(port); | 1015 | kill_traffic(port); |
1016 | } | 1016 | } |
1017 | } | 1017 | } |