aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/line.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers/line.c')
-rw-r--r--arch/um/drivers/line.c64
1 files changed, 37 insertions, 27 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 35dd0b86401..364c8a15c4c 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -176,10 +176,9 @@ void line_flush_buffer(struct tty_struct *tty)
176{ 176{
177 struct line *line = tty->driver_data; 177 struct line *line = tty->driver_data;
178 unsigned long flags; 178 unsigned long flags;
179 int err;
180 179
181 spin_lock_irqsave(&line->lock, flags); 180 spin_lock_irqsave(&line->lock, flags);
182 err = flush_buffer(line); 181 flush_buffer(line);
183 spin_unlock_irqrestore(&line->lock, flags); 182 spin_unlock_irqrestore(&line->lock, flags);
184} 183}
185 184
@@ -400,8 +399,8 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
400 * is done under a spinlock. Checking whether the device is in use is 399 * is done under a spinlock. Checking whether the device is in use is
401 * line->tty->count > 1, also under the spinlock. 400 * line->tty->count > 1, also under the spinlock.
402 * 401 *
403 * tty->count serves to decide whether the device should be enabled or 402 * line->count serves to decide whether the device should be enabled or
404 * disabled on the host. If it's equal to 1, then we are doing the 403 * disabled on the host. If it's equal to 0, then we are doing the
405 * first open or last close. Otherwise, open and close just return. 404 * first open or last close. Otherwise, open and close just return.
406 */ 405 */
407 406
@@ -415,16 +414,16 @@ int line_open(struct line *lines, struct tty_struct *tty)
415 goto out_unlock; 414 goto out_unlock;
416 415
417 err = 0; 416 err = 0;
418 if (tty->count > 1) 417 if (line->count++)
419 goto out_unlock; 418 goto out_unlock;
420 419
421 spin_unlock(&line->count_lock); 420 BUG_ON(tty->driver_data);
422
423 tty->driver_data = line; 421 tty->driver_data = line;
424 line->tty = tty; 422 line->tty = tty;
425 423
424 spin_unlock(&line->count_lock);
426 err = enable_chan(line); 425 err = enable_chan(line);
427 if (err) 426 if (err) /* line_close() will be called by our caller */
428 return err; 427 return err;
429 428
430 INIT_DELAYED_WORK(&line->task, line_timer_cb); 429 INIT_DELAYED_WORK(&line->task, line_timer_cb);
@@ -437,7 +436,7 @@ int line_open(struct line *lines, struct tty_struct *tty)
437 chan_window_size(&line->chan_list, &tty->winsize.ws_row, 436 chan_window_size(&line->chan_list, &tty->winsize.ws_row,
438 &tty->winsize.ws_col); 437 &tty->winsize.ws_col);
439 438
440 return err; 439 return 0;
441 440
442out_unlock: 441out_unlock:
443 spin_unlock(&line->count_lock); 442 spin_unlock(&line->count_lock);
@@ -461,17 +460,16 @@ void line_close(struct tty_struct *tty, struct file * filp)
461 flush_buffer(line); 460 flush_buffer(line);
462 461
463 spin_lock(&line->count_lock); 462 spin_lock(&line->count_lock);
464 if (!line->valid) 463 BUG_ON(!line->valid);
465 goto out_unlock;
466 464
467 if (tty->count > 1) 465 if (--line->count)
468 goto out_unlock; 466 goto out_unlock;
469 467
470 spin_unlock(&line->count_lock);
471
472 line->tty = NULL; 468 line->tty = NULL;
473 tty->driver_data = NULL; 469 tty->driver_data = NULL;
474 470
471 spin_unlock(&line->count_lock);
472
475 if (line->sigio) { 473 if (line->sigio) {
476 unregister_winch(tty); 474 unregister_winch(tty);
477 line->sigio = 0; 475 line->sigio = 0;
@@ -499,7 +497,7 @@ static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
499 497
500 spin_lock(&line->count_lock); 498 spin_lock(&line->count_lock);
501 499
502 if (line->tty != NULL) { 500 if (line->count) {
503 *error_out = "Device is already open"; 501 *error_out = "Device is already open";
504 goto out; 502 goto out;
505 } 503 }
@@ -723,41 +721,53 @@ struct winch {
723 int pid; 721 int pid;
724 struct tty_struct *tty; 722 struct tty_struct *tty;
725 unsigned long stack; 723 unsigned long stack;
724 struct work_struct work;
726}; 725};
727 726
728static void free_winch(struct winch *winch, int free_irq_ok) 727static void __free_winch(struct work_struct *work)
729{ 728{
730 if (free_irq_ok) 729 struct winch *winch = container_of(work, struct winch, work);
731 free_irq(WINCH_IRQ, winch); 730 free_irq(WINCH_IRQ, winch);
732
733 list_del(&winch->list);
734 731
735 if (winch->pid != -1) 732 if (winch->pid != -1)
736 os_kill_process(winch->pid, 1); 733 os_kill_process(winch->pid, 1);
737 if (winch->fd != -1)
738 os_close_file(winch->fd);
739 if (winch->stack != 0) 734 if (winch->stack != 0)
740 free_stack(winch->stack, 0); 735 free_stack(winch->stack, 0);
741 kfree(winch); 736 kfree(winch);
742} 737}
743 738
739static void free_winch(struct winch *winch)
740{
741 int fd = winch->fd;
742 winch->fd = -1;
743 if (fd != -1)
744 os_close_file(fd);
745 list_del(&winch->list);
746 __free_winch(&winch->work);
747}
748
744static irqreturn_t winch_interrupt(int irq, void *data) 749static irqreturn_t winch_interrupt(int irq, void *data)
745{ 750{
746 struct winch *winch = data; 751 struct winch *winch = data;
747 struct tty_struct *tty; 752 struct tty_struct *tty;
748 struct line *line; 753 struct line *line;
754 int fd = winch->fd;
749 int err; 755 int err;
750 char c; 756 char c;
751 757
752 if (winch->fd != -1) { 758 if (fd != -1) {
753 err = generic_read(winch->fd, &c, NULL); 759 err = generic_read(fd, &c, NULL);
754 if (err < 0) { 760 if (err < 0) {
755 if (err != -EAGAIN) { 761 if (err != -EAGAIN) {
762 winch->fd = -1;
763 list_del(&winch->list);
764 os_close_file(fd);
756 printk(KERN_ERR "winch_interrupt : " 765 printk(KERN_ERR "winch_interrupt : "
757 "read failed, errno = %d\n", -err); 766 "read failed, errno = %d\n", -err);
758 printk(KERN_ERR "fd %d is losing SIGWINCH " 767 printk(KERN_ERR "fd %d is losing SIGWINCH "
759 "support\n", winch->tty_fd); 768 "support\n", winch->tty_fd);
760 free_winch(winch, 0); 769 INIT_WORK(&winch->work, __free_winch);
770 schedule_work(&winch->work);
761 return IRQ_HANDLED; 771 return IRQ_HANDLED;
762 } 772 }
763 goto out; 773 goto out;
@@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty)
829 list_for_each_safe(ele, next, &winch_handlers) { 839 list_for_each_safe(ele, next, &winch_handlers) {
830 winch = list_entry(ele, struct winch, list); 840 winch = list_entry(ele, struct winch, list);
831 if (winch->tty == tty) { 841 if (winch->tty == tty) {
832 free_winch(winch, 1); 842 free_winch(winch);
833 break; 843 break;
834 } 844 }
835 } 845 }
@@ -845,7 +855,7 @@ static void winch_cleanup(void)
845 855
846 list_for_each_safe(ele, next, &winch_handlers) { 856 list_for_each_safe(ele, next, &winch_handlers) {
847 winch = list_entry(ele, struct winch, list); 857 winch = list_entry(ele, struct winch, list);
848 free_winch(winch, 1); 858 free_winch(winch);
849 } 859 }
850 860
851 spin_unlock(&winch_handler_lock); 861 spin_unlock(&winch_handler_lock);