aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/line.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2006-01-06 03:18:57 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:46 -0500
commit165dc5911627a9c4752e909a0da661b96b6fd269 (patch)
tree7e8eb47b7e766a5296b9e15ef177f958dec16d93 /arch/um/drivers/line.c
parent1f80171e81ed0d08dcdb6efe239d7b929aef498f (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.c116
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
24static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) 24static 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
34static void line_timer_cb(void *arg) 35static 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,
342static irqreturn_t line_write_interrupt(int irq, void *data, 343static 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
380int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) 382int 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
400void 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
422int line_open(struct line *lines, struct tty_struct *tty) 401int 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;
456out: 435out:
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
584int line_get_config(char *name, struct line *lines, unsigned int num, char *str, 562int 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){