aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/chan_kern.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/chan_kern.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/chan_kern.c')
-rw-r--r--arch/um/drivers/chan_kern.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 31b69c4ea800..1bb920c0d77a 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
@@ -240,20 +240,65 @@ void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
240 } 240 }
241} 241}
242 242
243void enable_chan(struct list_head *chans, struct tty_struct *tty) 243void enable_chan(struct line *line)
244{ 244{
245 struct list_head *ele; 245 struct list_head *ele;
246 struct chan *chan; 246 struct chan *chan;
247 247
248 list_for_each(ele, chans){ 248 list_for_each(ele, &line->chan_list){
249 chan = list_entry(ele, struct chan, list); 249 chan = list_entry(ele, struct chan, list);
250 if(!chan->opened) continue; 250 if(open_one_chan(chan))
251 continue;
252
253 if(chan->enabled)
254 continue;
255 line_setup_irq(chan->fd, chan->input, chan->output, line,
256 chan);
257 chan->enabled = 1;
258 }
259}
260
261static LIST_HEAD(irqs_to_free);
262
263void free_irqs(void)
264{
265 struct chan *chan;
266
267 while(!list_empty(&irqs_to_free)){
268 chan = list_entry(irqs_to_free.next, struct chan, free_list);
269 list_del(&chan->free_list);
270
271 if(chan->input)
272 free_irq(chan->line->driver->read_irq, chan);
273 if(chan->output)
274 free_irq(chan->line->driver->write_irq, chan);
275 chan->enabled = 0;
276 }
277}
278
279static void close_one_chan(struct chan *chan, int delay_free_irq)
280{
281 if(!chan->opened)
282 return;
251 283
252 line_setup_irq(chan->fd, chan->input, chan->output, tty); 284 if(delay_free_irq){
285 list_add(&chan->free_list, &irqs_to_free);
286 }
287 else {
288 if(chan->input)
289 free_irq(chan->line->driver->read_irq, chan);
290 if(chan->output)
291 free_irq(chan->line->driver->write_irq, chan);
292 chan->enabled = 0;
253 } 293 }
294 if(chan->ops->close != NULL)
295 (*chan->ops->close)(chan->fd, chan->data);
296
297 chan->opened = 0;
298 chan->fd = -1;
254} 299}
255 300
256void close_chan(struct list_head *chans) 301void close_chan(struct list_head *chans, int delay_free_irq)
257{ 302{
258 struct chan *chan; 303 struct chan *chan;
259 304
@@ -263,11 +308,7 @@ void close_chan(struct list_head *chans)
263 * so it must be the last closed. 308 * so it must be the last closed.
264 */ 309 */
265 list_for_each_entry_reverse(chan, chans, list) { 310 list_for_each_entry_reverse(chan, chans, list) {
266 if(!chan->opened) continue; 311 close_one_chan(chan, delay_free_irq);
267 if(chan->ops->close != NULL)
268 (*chan->ops->close)(chan->fd, chan->data);
269 chan->opened = 0;
270 chan->fd = -1;
271 } 312 }
272} 313}
273 314
@@ -339,24 +380,27 @@ int chan_window_size(struct list_head *chans, unsigned short *rows_out,
339 return 0; 380 return 0;
340} 381}
341 382
342void free_one_chan(struct chan *chan) 383void free_one_chan(struct chan *chan, int delay_free_irq)
343{ 384{
344 list_del(&chan->list); 385 list_del(&chan->list);
386
387 close_one_chan(chan, delay_free_irq);
388
345 if(chan->ops->free != NULL) 389 if(chan->ops->free != NULL)
346 (*chan->ops->free)(chan->data); 390 (*chan->ops->free)(chan->data);
347 free_irq_by_fd(chan->fd); 391
348 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); 392 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
349 kfree(chan); 393 kfree(chan);
350} 394}
351 395
352void free_chan(struct list_head *chans) 396void free_chan(struct list_head *chans, int delay_free_irq)
353{ 397{
354 struct list_head *ele, *next; 398 struct list_head *ele, *next;
355 struct chan *chan; 399 struct chan *chan;
356 400
357 list_for_each_safe(ele, next, chans){ 401 list_for_each_safe(ele, next, chans){
358 chan = list_entry(ele, struct chan, list); 402 chan = list_entry(ele, struct chan, list);
359 free_one_chan(chan); 403 free_one_chan(chan, delay_free_irq);
360 } 404 }
361} 405}
362 406
@@ -466,7 +510,8 @@ struct chan_type chan_table[] = {
466#endif 510#endif
467}; 511};
468 512
469static struct chan *parse_chan(char *str, int device, struct chan_opts *opts) 513static struct chan *parse_chan(struct line *line, char *str, int device,
514 struct chan_opts *opts)
470{ 515{
471 struct chan_type *entry; 516 struct chan_type *entry;
472 struct chan_ops *ops; 517 struct chan_ops *ops;
@@ -499,25 +544,30 @@ static struct chan *parse_chan(char *str, int device, struct chan_opts *opts)
499 if(chan == NULL) 544 if(chan == NULL)
500 return NULL; 545 return NULL;
501 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), 546 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
547 .free_list =
548 LIST_HEAD_INIT(chan->free_list),
549 .line = line,
502 .primary = 1, 550 .primary = 1,
503 .input = 0, 551 .input = 0,
504 .output = 0, 552 .output = 0,
505 .opened = 0, 553 .opened = 0,
554 .enabled = 0,
506 .fd = -1, 555 .fd = -1,
507 .ops = ops, 556 .ops = ops,
508 .data = data }); 557 .data = data });
509 return chan; 558 return chan;
510} 559}
511 560
512int parse_chan_pair(char *str, struct list_head *chans, int device, 561int parse_chan_pair(char *str, struct line *line, int device,
513 struct chan_opts *opts) 562 struct chan_opts *opts)
514{ 563{
564 struct list_head *chans = &line->chan_list;
515 struct chan *new, *chan; 565 struct chan *new, *chan;
516 char *in, *out; 566 char *in, *out;
517 567
518 if(!list_empty(chans)){ 568 if(!list_empty(chans)){
519 chan = list_entry(chans->next, struct chan, list); 569 chan = list_entry(chans->next, struct chan, list);
520 free_chan(chans); 570 free_chan(chans, 0);
521 INIT_LIST_HEAD(chans); 571 INIT_LIST_HEAD(chans);
522 } 572 }
523 573
@@ -526,14 +576,14 @@ int parse_chan_pair(char *str, struct list_head *chans, int device,
526 in = str; 576 in = str;
527 *out = '\0'; 577 *out = '\0';
528 out++; 578 out++;
529 new = parse_chan(in, device, opts); 579 new = parse_chan(line, in, device, opts);
530 if(new == NULL) 580 if(new == NULL)
531 return -1; 581 return -1;
532 582
533 new->input = 1; 583 new->input = 1;
534 list_add(&new->list, chans); 584 list_add(&new->list, chans);
535 585
536 new = parse_chan(out, device, opts); 586 new = parse_chan(line, out, device, opts);
537 if(new == NULL) 587 if(new == NULL)
538 return -1; 588 return -1;
539 589
@@ -541,7 +591,7 @@ int parse_chan_pair(char *str, struct list_head *chans, int device,
541 new->output = 1; 591 new->output = 1;
542 } 592 }
543 else { 593 else {
544 new = parse_chan(str, device, opts); 594 new = parse_chan(line, str, device, opts);
545 if(new == NULL) 595 if(new == NULL)
546 return -1; 596 return -1;
547 597
@@ -592,27 +642,12 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
592 if(chan->primary){ 642 if(chan->primary){
593 if(tty != NULL) 643 if(tty != NULL)
594 tty_hangup(tty); 644 tty_hangup(tty);
595 line_disable(tty, irq); 645 close_chan(chans, 1);
596 close_chan(chans);
597 return; 646 return;
598 } 647 }
599 else { 648 else close_one_chan(chan, 1);
600 if(chan->ops->close != NULL)
601 chan->ops->close(chan->fd, chan->data);
602 }
603 } 649 }
604 } 650 }
605 out: 651 out:
606 if(tty) tty_flip_buffer_push(tty); 652 if(tty) tty_flip_buffer_push(tty);
607} 653}
608
609/*
610 * Overrides for Emacs so that we follow Linus's tabbing style.
611 * Emacs will notice this stuff at the end of the file and automatically
612 * adjust the settings for this buffer only. This must remain at the end
613 * of the file.
614 * ---------------------------------------------------------------------------
615 * Local variables:
616 * c-file-style: "linux"
617 * End:
618 */