summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 2bb4c4f..e0fdffa 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,
return driver;
}
+static spinlock_t winch_handler_lock;
+LIST_HEAD(winch_handlers);
+
void lines_init(struct line *lines, int nlines)
{
struct line *line;
int i;
+ spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
return IRQ_HANDLED;
}
-DECLARE_MUTEX(winch_handler_sem);
-LIST_HEAD(winch_handlers);
-
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
{
struct winch *winch;
- down(&winch_handler_sem);
winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n");
- goto out;
+ return;
}
+
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
.tty = tty });
+
+ spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
+ spin_unlock(&winch_handler_lock);
+
if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
"winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n");
- out:
- up(&winch_handler_sem);
}
static void unregister_winch(struct tty_struct *tty)
@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
struct list_head *ele;
struct winch *winch, *found = NULL;
- down(&winch_handler_sem);
+ spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
break;
}
}
-
if(found == NULL)
- goto out;
+ goto err;
+
+ list_del(&winch->list);
+ spin_unlock(&winch_handler_lock);
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
free_irq(WINCH_IRQ, winch);
- list_del(&winch->list);
kfree(winch);
- out:
- up(&winch_handler_sem);
+
+ return;
+err:
+ spin_unlock(&winch_handler_lock);
}
+/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
+ * order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void)
{
struct list_head *ele;
@@ -786,6 +794,9 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->fd != -1){
+ /* Why is this different from the above free_irq(),
+ * which deactivates SIGIO? This searches the FD
+ * somewhere else and removes it from the list... */
deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd);
}