diff options
author | Jeff Dike <jdike@addtoit.com> | 2006-01-06 03:18:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:46 -0500 |
commit | 165dc5911627a9c4752e909a0da661b96b6fd269 (patch) | |
tree | 7e8eb47b7e766a5296b9e15ef177f958dec16d93 /arch/um/drivers/line.c | |
parent | 1f80171e81ed0d08dcdb6efe239d7b929aef498f (diff) |
[PATCH] uml: Simplify console opening/closing and irq registration
This patch simplifies the opening and closing of host console devices and the
registration and deregistration of IRQs. The intent is to make it obvious
that an IRQ can't exist without an open file descriptor.
chan_enable will now open the channel, and when both opening and IRQ
registration are desired, this should be used. Opening only is done for the
initial console, so that interface still needs to exist.
The free_irqs_later interface is now gone. It was intended to avoid freeing
an IRQ while it was being processed. It did this, but it didn't eliminate the
possiblity of free_irq being called from an interrupt, which is bad. In its
place is a list of irqs to be freed, which is processed by the signal handler
just before exiting. close_one_chan now disables irqs.
When a host device disappears, it is just closed, and that disables IRQs.
The device id registered with the IRQ is now the chan structure, not the tty.
This is because the interrupt arrives on a descriptor associated with the
channel. This caused equivalent changes in the arguments to line_timer_cb.
line_disable is gone since it is not used any more.
The count field in the line structure is gone. tty->count is used instead.
The complicated logic in sigio_handler with freeing IRQs when necessary and
making sure its idea of the next irq is correct is now much simpler. The irq
list can't be rearranged underneath it, so it is now a simple list walk.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/drivers/line.c')
-rw-r--r-- | arch/um/drivers/line.c | 116 |
1 files changed, 47 insertions, 69 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index da81d22ec04a..851a7c8caae5 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -23,8 +23,9 @@ | |||
23 | 23 | ||
24 | static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) | 24 | static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) |
25 | { | 25 | { |
26 | struct tty_struct *tty = data; | 26 | struct chan *chan = data; |
27 | struct line *line = tty->driver_data; | 27 | struct line *line = chan->line; |
28 | struct tty_struct *tty = line->tty; | ||
28 | 29 | ||
29 | if (line) | 30 | if (line) |
30 | chan_interrupt(&line->chan_list, &line->task, tty, irq); | 31 | chan_interrupt(&line->chan_list, &line->task, tty, irq); |
@@ -33,10 +34,10 @@ static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) | |||
33 | 34 | ||
34 | static void line_timer_cb(void *arg) | 35 | static void line_timer_cb(void *arg) |
35 | { | 36 | { |
36 | struct tty_struct *tty = arg; | 37 | struct line *line = arg; |
37 | struct line *line = tty->driver_data; | ||
38 | 38 | ||
39 | line_interrupt(line->driver->read_irq, arg, NULL); | 39 | chan_interrupt(&line->chan_list, &line->task, line->tty, |
40 | line->driver->read_irq); | ||
40 | } | 41 | } |
41 | 42 | ||
42 | /* Returns the free space inside the ring buffer of this line. | 43 | /* Returns the free space inside the ring buffer of this line. |
@@ -342,8 +343,9 @@ int line_ioctl(struct tty_struct *tty, struct file * file, | |||
342 | static irqreturn_t line_write_interrupt(int irq, void *data, | 343 | static irqreturn_t line_write_interrupt(int irq, void *data, |
343 | struct pt_regs *unused) | 344 | struct pt_regs *unused) |
344 | { | 345 | { |
345 | struct tty_struct *tty = data; | 346 | struct chan *chan = data; |
346 | struct line *line = tty->driver_data; | 347 | struct line *line = chan->line; |
348 | struct tty_struct *tty = line->tty; | ||
347 | int err; | 349 | int err; |
348 | 350 | ||
349 | /* Interrupts are enabled here because we registered the interrupt with | 351 | /* Interrupts are enabled here because we registered the interrupt with |
@@ -365,7 +367,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data, | |||
365 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && | 367 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && |
366 | (tty->ldisc.write_wakeup != NULL)) | 368 | (tty->ldisc.write_wakeup != NULL)) |
367 | (tty->ldisc.write_wakeup)(tty); | 369 | (tty->ldisc.write_wakeup)(tty); |
368 | 370 | ||
369 | /* BLOCKING mode | 371 | /* BLOCKING mode |
370 | * In blocking mode, everything sleeps on tty->write_wait. | 372 | * In blocking mode, everything sleeps on tty->write_wait. |
371 | * Sleeping in the console driver would break non-blocking | 373 | * Sleeping in the console driver would break non-blocking |
@@ -377,52 +379,29 @@ static irqreturn_t line_write_interrupt(int irq, void *data, | |||
377 | return IRQ_HANDLED; | 379 | return IRQ_HANDLED; |
378 | } | 380 | } |
379 | 381 | ||
380 | int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) | 382 | int line_setup_irq(int fd, int input, int output, struct line *line, void *data) |
381 | { | 383 | { |
382 | struct line *line = tty->driver_data; | ||
383 | struct line_driver *driver = line->driver; | 384 | struct line_driver *driver = line->driver; |
384 | int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; | 385 | int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; |
385 | 386 | ||
386 | if (input) | 387 | if (input) |
387 | err = um_request_irq(driver->read_irq, fd, IRQ_READ, | 388 | err = um_request_irq(driver->read_irq, fd, IRQ_READ, |
388 | line_interrupt, flags, | 389 | line_interrupt, flags, |
389 | driver->read_irq_name, tty); | 390 | driver->read_irq_name, data); |
390 | if (err) | 391 | if (err) |
391 | return err; | 392 | return err; |
392 | if (output) | 393 | if (output) |
393 | err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, | 394 | err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, |
394 | line_write_interrupt, flags, | 395 | line_write_interrupt, flags, |
395 | driver->write_irq_name, tty); | 396 | driver->write_irq_name, data); |
396 | line->have_irq = 1; | 397 | line->have_irq = 1; |
397 | return err; | 398 | return err; |
398 | } | 399 | } |
399 | 400 | ||
400 | void line_disable(struct tty_struct *tty, int current_irq) | ||
401 | { | ||
402 | struct line *line = tty->driver_data; | ||
403 | |||
404 | if(!line->have_irq) | ||
405 | return; | ||
406 | |||
407 | if(line->driver->read_irq == current_irq) | ||
408 | free_irq_later(line->driver->read_irq, tty); | ||
409 | else { | ||
410 | free_irq(line->driver->read_irq, tty); | ||
411 | } | ||
412 | |||
413 | if(line->driver->write_irq == current_irq) | ||
414 | free_irq_later(line->driver->write_irq, tty); | ||
415 | else { | ||
416 | free_irq(line->driver->write_irq, tty); | ||
417 | } | ||
418 | |||
419 | line->have_irq = 0; | ||
420 | } | ||
421 | |||
422 | int line_open(struct line *lines, struct tty_struct *tty) | 401 | int line_open(struct line *lines, struct tty_struct *tty) |
423 | { | 402 | { |
424 | struct line *line; | 403 | struct line *line; |
425 | int err = 0; | 404 | int err = -ENODEV; |
426 | 405 | ||
427 | line = &lines[tty->index]; | 406 | line = &lines[tty->index]; |
428 | tty->driver_data = line; | 407 | tty->driver_data = line; |
@@ -430,29 +409,29 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
430 | /* The IRQ which takes this lock is not yet enabled and won't be run | 409 | /* The IRQ which takes this lock is not yet enabled and won't be run |
431 | * before the end, so we don't need to use spin_lock_irq.*/ | 410 | * before the end, so we don't need to use spin_lock_irq.*/ |
432 | spin_lock(&line->lock); | 411 | spin_lock(&line->lock); |
433 | if (tty->count == 1) { | ||
434 | if (!line->valid) { | ||
435 | err = -ENODEV; | ||
436 | goto out; | ||
437 | } | ||
438 | 412 | ||
439 | err = open_chan(&line->chan_list); | 413 | tty->driver_data = line; |
440 | if(err) | 414 | line->tty = tty; |
441 | goto out; | 415 | if(!line->valid) |
442 | 416 | goto out; | |
443 | /* Here the interrupt is registered.*/ | 417 | |
444 | enable_chan(&line->chan_list, tty); | 418 | if(tty->count == 1){ |
445 | INIT_WORK(&line->task, line_timer_cb, tty); | 419 | /* Here the device is opened, if necessary, and interrupt |
446 | } | 420 | * is registered. |
421 | */ | ||
422 | enable_chan(line); | ||
423 | INIT_WORK(&line->task, line_timer_cb, line); | ||
424 | |||
425 | if(!line->sigio){ | ||
426 | chan_enable_winch(&line->chan_list, tty); | ||
427 | line->sigio = 1; | ||
428 | } | ||
447 | 429 | ||
448 | if(!line->sigio){ | 430 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
449 | chan_enable_winch(&line->chan_list, tty); | 431 | &tty->winsize.ws_col); |
450 | line->sigio = 1; | ||
451 | } | 432 | } |
452 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | ||
453 | &tty->winsize.ws_col); | ||
454 | line->count++; | ||
455 | 433 | ||
434 | err = 0; | ||
456 | out: | 435 | out: |
457 | spin_unlock(&line->lock); | 436 | spin_unlock(&line->lock); |
458 | return err; | 437 | return err; |
@@ -472,15 +451,14 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
472 | /* We ignore the error anyway! */ | 451 | /* We ignore the error anyway! */ |
473 | flush_buffer(line); | 452 | flush_buffer(line); |
474 | 453 | ||
475 | line->count--; | 454 | if(tty->count == 1){ |
476 | if (tty->count == 1) { | 455 | line->tty = NULL; |
477 | line_disable(tty, -1); | ||
478 | tty->driver_data = NULL; | 456 | tty->driver_data = NULL; |
479 | } | ||
480 | 457 | ||
481 | if((line->count == 0) && line->sigio){ | 458 | if(line->sigio){ |
482 | unregister_winch(tty); | 459 | unregister_winch(tty); |
483 | line->sigio = 0; | 460 | line->sigio = 0; |
461 | } | ||
484 | } | 462 | } |
485 | 463 | ||
486 | spin_unlock_irq(&line->lock); | 464 | spin_unlock_irq(&line->lock); |
@@ -491,7 +469,7 @@ void close_lines(struct line *lines, int nlines) | |||
491 | int i; | 469 | int i; |
492 | 470 | ||
493 | for(i = 0; i < nlines; i++) | 471 | for(i = 0; i < nlines; i++) |
494 | close_chan(&lines[i].chan_list); | 472 | close_chan(&lines[i].chan_list, 0); |
495 | } | 473 | } |
496 | 474 | ||
497 | /* Common setup code for both startup command line and mconsole initialization. | 475 | /* Common setup code for both startup command line and mconsole initialization. |
@@ -526,7 +504,7 @@ int line_setup(struct line *lines, unsigned int num, char *init) | |||
526 | return 0; | 504 | return 0; |
527 | } | 505 | } |
528 | else if (n >= 0){ | 506 | else if (n >= 0){ |
529 | if (lines[n].count > 0) { | 507 | if (lines[n].tty != NULL) { |
530 | printk("line_setup - device %d is open\n", n); | 508 | printk("line_setup - device %d is open\n", n); |
531 | return 0; | 509 | return 0; |
532 | } | 510 | } |
@@ -537,7 +515,7 @@ int line_setup(struct line *lines, unsigned int num, char *init) | |||
537 | else { | 515 | else { |
538 | lines[n].init_str = init; | 516 | lines[n].init_str = init; |
539 | lines[n].valid = 1; | 517 | lines[n].valid = 1; |
540 | } | 518 | } |
541 | } | 519 | } |
542 | } | 520 | } |
543 | else { | 521 | else { |
@@ -578,7 +556,7 @@ int line_config(struct line *lines, unsigned int num, char *str, | |||
578 | return 1; | 556 | return 1; |
579 | 557 | ||
580 | line = &lines[n]; | 558 | line = &lines[n]; |
581 | return parse_chan_pair(line->init_str, &line->chan_list, n, opts); | 559 | return parse_chan_pair(line->init_str, line, n, opts); |
582 | } | 560 | } |
583 | 561 | ||
584 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | 562 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, |
@@ -604,7 +582,7 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | |||
604 | spin_lock(&line->lock); | 582 | spin_lock(&line->lock); |
605 | if(!line->valid) | 583 | if(!line->valid) |
606 | CONFIG_CHUNK(str, size, n, "none", 1); | 584 | CONFIG_CHUNK(str, size, n, "none", 1); |
607 | else if(line->count == 0) | 585 | else if(line->tty == NULL) |
608 | CONFIG_CHUNK(str, size, n, line->init_str, 1); | 586 | CONFIG_CHUNK(str, size, n, line->init_str, 1); |
609 | else n = chan_config_string(&line->chan_list, str, size, error_out); | 587 | else n = chan_config_string(&line->chan_list, str, size, error_out); |
610 | spin_unlock(&line->lock); | 588 | spin_unlock(&line->lock); |
@@ -696,7 +674,7 @@ void lines_init(struct line *lines, int nlines, struct chan_opts *opts) | |||
696 | if(line->init_str == NULL) | 674 | if(line->init_str == NULL) |
697 | printk("lines_init - kstrdup returned NULL\n"); | 675 | printk("lines_init - kstrdup returned NULL\n"); |
698 | 676 | ||
699 | if(parse_chan_pair(line->init_str, &line->chan_list, i, opts)){ | 677 | if(parse_chan_pair(line->init_str, line, i, opts)){ |
700 | printk("parse_chan_pair failed for device %d\n", i); | 678 | printk("parse_chan_pair failed for device %d\n", i); |
701 | line->valid = 0; | 679 | line->valid = 0; |
702 | } | 680 | } |
@@ -831,7 +809,7 @@ char *add_xterm_umid(char *base) | |||
831 | umid = get_umid(1); | 809 | umid = get_umid(1); |
832 | if(umid == NULL) | 810 | if(umid == NULL) |
833 | return base; | 811 | return base; |
834 | 812 | ||
835 | len = strlen(base) + strlen(" ()") + strlen(umid) + 1; | 813 | len = strlen(base) + strlen(" ()") + strlen(umid) + 1; |
836 | title = kmalloc(len, GFP_KERNEL); | 814 | title = kmalloc(len, GFP_KERNEL); |
837 | if(title == NULL){ | 815 | if(title == NULL){ |