diff options
Diffstat (limited to 'drivers/char/generic_serial.c')
-rw-r--r-- | drivers/char/generic_serial.c | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index c6090f84a2e4..9e4e569dc00d 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c | |||
@@ -376,7 +376,8 @@ static void gs_shutdown_port (struct gs_port *port) | |||
376 | 376 | ||
377 | void gs_hangup(struct tty_struct *tty) | 377 | void gs_hangup(struct tty_struct *tty) |
378 | { | 378 | { |
379 | struct gs_port *port; | 379 | struct gs_port *port; |
380 | unsigned long flags; | ||
380 | 381 | ||
381 | func_enter (); | 382 | func_enter (); |
382 | 383 | ||
@@ -386,9 +387,11 @@ void gs_hangup(struct tty_struct *tty) | |||
386 | return; | 387 | return; |
387 | 388 | ||
388 | gs_shutdown_port (port); | 389 | gs_shutdown_port (port); |
390 | spin_lock_irqsave(&port->port.lock, flags); | ||
389 | port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); | 391 | port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); |
390 | port->port.tty = NULL; | 392 | port->port.tty = NULL; |
391 | port->port.count = 0; | 393 | port->port.count = 0; |
394 | spin_unlock_irqrestore(&port->port.lock, flags); | ||
392 | 395 | ||
393 | wake_up_interruptible(&port->port.open_wait); | 396 | wake_up_interruptible(&port->port.open_wait); |
394 | func_exit (); | 397 | func_exit (); |
@@ -397,7 +400,8 @@ void gs_hangup(struct tty_struct *tty) | |||
397 | 400 | ||
398 | int gs_block_til_ready(void *port_, struct file * filp) | 401 | int gs_block_til_ready(void *port_, struct file * filp) |
399 | { | 402 | { |
400 | struct gs_port *port = port_; | 403 | struct gs_port *gp = port_; |
404 | struct tty_port *port = &gp->port; | ||
401 | DECLARE_WAITQUEUE(wait, current); | 405 | DECLARE_WAITQUEUE(wait, current); |
402 | int retval; | 406 | int retval; |
403 | int do_clocal = 0; | 407 | int do_clocal = 0; |
@@ -409,16 +413,16 @@ int gs_block_til_ready(void *port_, struct file * filp) | |||
409 | 413 | ||
410 | if (!port) return 0; | 414 | if (!port) return 0; |
411 | 415 | ||
412 | tty = port->port.tty; | 416 | tty = port->tty; |
413 | 417 | ||
414 | gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); | 418 | gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); |
415 | /* | 419 | /* |
416 | * If the device is in the middle of being closed, then block | 420 | * If the device is in the middle of being closed, then block |
417 | * until it's done, and then try again. | 421 | * until it's done, and then try again. |
418 | */ | 422 | */ |
419 | if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) { | 423 | if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { |
420 | interruptible_sleep_on(&port->port.close_wait); | 424 | interruptible_sleep_on(&port->close_wait); |
421 | if (port->port.flags & ASYNC_HUP_NOTIFY) | 425 | if (port->flags & ASYNC_HUP_NOTIFY) |
422 | return -EAGAIN; | 426 | return -EAGAIN; |
423 | else | 427 | else |
424 | return -ERESTARTSYS; | 428 | return -ERESTARTSYS; |
@@ -432,7 +436,7 @@ int gs_block_til_ready(void *port_, struct file * filp) | |||
432 | */ | 436 | */ |
433 | if ((filp->f_flags & O_NONBLOCK) || | 437 | if ((filp->f_flags & O_NONBLOCK) || |
434 | (tty->flags & (1 << TTY_IO_ERROR))) { | 438 | (tty->flags & (1 << TTY_IO_ERROR))) { |
435 | port->port.flags |= ASYNC_NORMAL_ACTIVE; | 439 | port->flags |= ASYNC_NORMAL_ACTIVE; |
436 | return 0; | 440 | return 0; |
437 | } | 441 | } |
438 | 442 | ||
@@ -444,34 +448,34 @@ int gs_block_til_ready(void *port_, struct file * filp) | |||
444 | /* | 448 | /* |
445 | * Block waiting for the carrier detect and the line to become | 449 | * Block waiting for the carrier detect and the line to become |
446 | * free (i.e., not in use by the callout). While we are in | 450 | * free (i.e., not in use by the callout). While we are in |
447 | * this loop, port->port.count is dropped by one, so that | 451 | * this loop, port->count is dropped by one, so that |
448 | * rs_close() knows when to free things. We restore it upon | 452 | * rs_close() knows when to free things. We restore it upon |
449 | * exit, either normal or abnormal. | 453 | * exit, either normal or abnormal. |
450 | */ | 454 | */ |
451 | retval = 0; | 455 | retval = 0; |
452 | 456 | ||
453 | add_wait_queue(&port->port.open_wait, &wait); | 457 | add_wait_queue(&port->open_wait, &wait); |
454 | 458 | ||
455 | gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); | 459 | gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); |
456 | spin_lock_irqsave(&port->driver_lock, flags); | 460 | spin_lock_irqsave(&port->lock, flags); |
457 | if (!tty_hung_up_p(filp)) { | 461 | if (!tty_hung_up_p(filp)) { |
458 | port->port.count--; | 462 | port->count--; |
459 | } | 463 | } |
460 | spin_unlock_irqrestore(&port->driver_lock, flags); | 464 | port->blocked_open++; |
461 | port->port.blocked_open++; | 465 | spin_unlock_irqrestore(&port->lock, flags); |
462 | while (1) { | 466 | while (1) { |
463 | CD = port->rd->get_CD (port); | 467 | CD = tty_port_carrier_raised(port); |
464 | gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); | 468 | gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); |
465 | set_current_state (TASK_INTERRUPTIBLE); | 469 | set_current_state (TASK_INTERRUPTIBLE); |
466 | if (tty_hung_up_p(filp) || | 470 | if (tty_hung_up_p(filp) || |
467 | !(port->port.flags & ASYNC_INITIALIZED)) { | 471 | !(port->flags & ASYNC_INITIALIZED)) { |
468 | if (port->port.flags & ASYNC_HUP_NOTIFY) | 472 | if (port->flags & ASYNC_HUP_NOTIFY) |
469 | retval = -EAGAIN; | 473 | retval = -EAGAIN; |
470 | else | 474 | else |
471 | retval = -ERESTARTSYS; | 475 | retval = -ERESTARTSYS; |
472 | break; | 476 | break; |
473 | } | 477 | } |
474 | if (!(port->port.flags & ASYNC_CLOSING) && | 478 | if (!(port->flags & ASYNC_CLOSING) && |
475 | (do_clocal || CD)) | 479 | (do_clocal || CD)) |
476 | break; | 480 | break; |
477 | gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", | 481 | gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", |
@@ -483,19 +487,20 @@ int gs_block_til_ready(void *port_, struct file * filp) | |||
483 | schedule(); | 487 | schedule(); |
484 | } | 488 | } |
485 | gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", | 489 | gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", |
486 | port->port.blocked_open); | 490 | port->blocked_open); |
487 | set_current_state (TASK_RUNNING); | 491 | set_current_state (TASK_RUNNING); |
488 | remove_wait_queue(&port->port.open_wait, &wait); | 492 | remove_wait_queue(&port->open_wait, &wait); |
493 | |||
494 | spin_lock_irqsave(&port->lock, flags); | ||
489 | if (!tty_hung_up_p(filp)) { | 495 | if (!tty_hung_up_p(filp)) { |
490 | port->port.count++; | 496 | port->count++; |
491 | } | 497 | } |
492 | port->port.blocked_open--; | 498 | port->blocked_open--; |
493 | if (retval) | 499 | if (retval == 0) |
494 | return retval; | 500 | port->flags |= ASYNC_NORMAL_ACTIVE; |
495 | 501 | spin_unlock_irqrestore(&port->lock, flags); | |
496 | port->port.flags |= ASYNC_NORMAL_ACTIVE; | ||
497 | func_exit (); | 502 | func_exit (); |
498 | return 0; | 503 | return retval; |
499 | } | 504 | } |
500 | 505 | ||
501 | 506 | ||
@@ -506,7 +511,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
506 | 511 | ||
507 | func_enter (); | 512 | func_enter (); |
508 | 513 | ||
509 | port = (struct gs_port *) tty->driver_data; | 514 | port = tty->driver_data; |
510 | 515 | ||
511 | if (!port) return; | 516 | if (!port) return; |
512 | 517 | ||
@@ -516,10 +521,10 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
516 | port->port.tty = tty; | 521 | port->port.tty = tty; |
517 | } | 522 | } |
518 | 523 | ||
519 | spin_lock_irqsave(&port->driver_lock, flags); | 524 | spin_lock_irqsave(&port->port.lock, flags); |
520 | 525 | ||
521 | if (tty_hung_up_p(filp)) { | 526 | if (tty_hung_up_p(filp)) { |
522 | spin_unlock_irqrestore(&port->driver_lock, flags); | 527 | spin_unlock_irqrestore(&port->port.lock, flags); |
523 | if (port->rd->hungup) | 528 | if (port->rd->hungup) |
524 | port->rd->hungup (port); | 529 | port->rd->hungup (port); |
525 | func_exit (); | 530 | func_exit (); |
@@ -538,7 +543,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
538 | 543 | ||
539 | if (port->port.count) { | 544 | if (port->port.count) { |
540 | gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count); | 545 | gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count); |
541 | spin_unlock_irqrestore(&port->driver_lock, flags); | 546 | spin_unlock_irqrestore(&port->port.lock, flags); |
542 | func_exit (); | 547 | func_exit (); |
543 | return; | 548 | return; |
544 | } | 549 | } |
@@ -559,8 +564,10 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
559 | * line status register. | 564 | * line status register. |
560 | */ | 565 | */ |
561 | 566 | ||
567 | spin_lock_irqsave(&port->driver_lock, flags); | ||
562 | port->rd->disable_rx_interrupts (port); | 568 | port->rd->disable_rx_interrupts (port); |
563 | spin_unlock_irqrestore(&port->driver_lock, flags); | 569 | spin_unlock_irqrestore(&port->driver_lock, flags); |
570 | spin_unlock_irqrestore(&port->port.lock, flags); | ||
564 | 571 | ||
565 | /* close has no way of returning "EINTR", so discard return value */ | 572 | /* close has no way of returning "EINTR", so discard return value */ |
566 | if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) | 573 | if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) |
@@ -573,20 +580,25 @@ void gs_close(struct tty_struct * tty, struct file * filp) | |||
573 | tty_ldisc_flush(tty); | 580 | tty_ldisc_flush(tty); |
574 | tty->closing = 0; | 581 | tty->closing = 0; |
575 | 582 | ||
583 | spin_lock_irqsave(&port->driver_lock, flags); | ||
576 | port->event = 0; | 584 | port->event = 0; |
577 | port->rd->close (port); | 585 | port->rd->close (port); |
578 | port->rd->shutdown_port (port); | 586 | port->rd->shutdown_port (port); |
587 | spin_unlock_irqrestore(&port->driver_lock, flags); | ||
588 | |||
589 | spin_lock_irqsave(&port->port.lock, flags); | ||
579 | port->port.tty = NULL; | 590 | port->port.tty = NULL; |
580 | 591 | ||
581 | if (port->port.blocked_open) { | 592 | if (port->port.blocked_open) { |
582 | if (port->close_delay) { | 593 | if (port->close_delay) { |
583 | spin_unlock_irqrestore(&port->driver_lock, flags); | 594 | spin_unlock_irqrestore(&port->port.lock, flags); |
584 | msleep_interruptible(jiffies_to_msecs(port->close_delay)); | 595 | msleep_interruptible(jiffies_to_msecs(port->close_delay)); |
585 | spin_lock_irqsave(&port->driver_lock, flags); | 596 | spin_lock_irqsave(&port->port.lock, flags); |
586 | } | 597 | } |
587 | wake_up_interruptible(&port->port.open_wait); | 598 | wake_up_interruptible(&port->port.open_wait); |
588 | } | 599 | } |
589 | port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); | 600 | port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); |
601 | spin_unlock_irqrestore(&port->port.lock, flags); | ||
590 | wake_up_interruptible(&port->port.close_wait); | 602 | wake_up_interruptible(&port->port.close_wait); |
591 | 603 | ||
592 | func_exit (); | 604 | func_exit (); |