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.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 2bb4c4f5dec..e0fdffa2d54 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set,
663 return driver; 663 return driver;
664} 664}
665 665
666static spinlock_t winch_handler_lock;
667LIST_HEAD(winch_handlers);
668
666void lines_init(struct line *lines, int nlines) 669void lines_init(struct line *lines, int nlines)
667{ 670{
668 struct line *line; 671 struct line *line;
669 int i; 672 int i;
670 673
674 spin_lock_init(&winch_handler_lock);
671 for(i = 0; i < nlines; i++){ 675 for(i = 0; i < nlines; i++){
672 line = &lines[i]; 676 line = &lines[i];
673 INIT_LIST_HEAD(&line->chan_list); 677 INIT_LIST_HEAD(&line->chan_list);
@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
724 return IRQ_HANDLED; 728 return IRQ_HANDLED;
725} 729}
726 730
727DECLARE_MUTEX(winch_handler_sem);
728LIST_HEAD(winch_handlers);
729
730void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) 731void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
731{ 732{
732 struct winch *winch; 733 struct winch *winch;
733 734
734 down(&winch_handler_sem);
735 winch = kmalloc(sizeof(*winch), GFP_KERNEL); 735 winch = kmalloc(sizeof(*winch), GFP_KERNEL);
736 if (winch == NULL) { 736 if (winch == NULL) {
737 printk("register_winch_irq - kmalloc failed\n"); 737 printk("register_winch_irq - kmalloc failed\n");
738 goto out; 738 return;
739 } 739 }
740
740 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), 741 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
741 .fd = fd, 742 .fd = fd,
742 .tty_fd = tty_fd, 743 .tty_fd = tty_fd,
743 .pid = pid, 744 .pid = pid,
744 .tty = tty }); 745 .tty = tty });
746
747 spin_lock(&winch_handler_lock);
745 list_add(&winch->list, &winch_handlers); 748 list_add(&winch->list, &winch_handlers);
749 spin_unlock(&winch_handler_lock);
750
746 if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 751 if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
747 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 752 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
748 "winch", winch) < 0) 753 "winch", winch) < 0)
749 printk("register_winch_irq - failed to register IRQ\n"); 754 printk("register_winch_irq - failed to register IRQ\n");
750 out:
751 up(&winch_handler_sem);
752} 755}
753 756
754static void unregister_winch(struct tty_struct *tty) 757static void unregister_winch(struct tty_struct *tty)
@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
756 struct list_head *ele; 759 struct list_head *ele;
757 struct winch *winch, *found = NULL; 760 struct winch *winch, *found = NULL;
758 761
759 down(&winch_handler_sem); 762 spin_lock(&winch_handler_lock);
760 list_for_each(ele, &winch_handlers){ 763 list_for_each(ele, &winch_handlers){
761 winch = list_entry(ele, struct winch, list); 764 winch = list_entry(ele, struct winch, list);
762 if(winch->tty == tty){ 765 if(winch->tty == tty){
@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
764 break; 767 break;
765 } 768 }
766 } 769 }
767
768 if(found == NULL) 770 if(found == NULL)
769 goto out; 771 goto err;
772
773 list_del(&winch->list);
774 spin_unlock(&winch_handler_lock);
770 775
771 if(winch->pid != -1) 776 if(winch->pid != -1)
772 os_kill_process(winch->pid, 1); 777 os_kill_process(winch->pid, 1);
773 778
774 free_irq(WINCH_IRQ, winch); 779 free_irq(WINCH_IRQ, winch);
775 list_del(&winch->list);
776 kfree(winch); 780 kfree(winch);
777 out: 781
778 up(&winch_handler_sem); 782 return;
783err:
784 spin_unlock(&winch_handler_lock);
779} 785}
780 786
787/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
788 * order... are we sure that nothing else is done on the list? */
781static void winch_cleanup(void) 789static void winch_cleanup(void)
782{ 790{
783 struct list_head *ele; 791 struct list_head *ele;
@@ -786,6 +794,9 @@ static void winch_cleanup(void)
786 list_for_each(ele, &winch_handlers){ 794 list_for_each(ele, &winch_handlers){
787 winch = list_entry(ele, struct winch, list); 795 winch = list_entry(ele, struct winch, list);
788 if(winch->fd != -1){ 796 if(winch->fd != -1){
797 /* Why is this different from the above free_irq(),
798 * which deactivates SIGIO? This searches the FD
799 * somewhere else and removes it from the list... */
789 deactivate_fd(winch->fd, WINCH_IRQ); 800 deactivate_fd(winch->fd, WINCH_IRQ);
790 os_close_file(winch->fd); 801 os_close_file(winch->fd);
791 } 802 }