diff options
Diffstat (limited to 'arch/um/drivers/chan_kern.c')
-rw-r--r-- | arch/um/drivers/chan_kern.c | 111 |
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 | ||
243 | void enable_chan(struct list_head *chans, struct tty_struct *tty) | 243 | void 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 | |||
261 | static LIST_HEAD(irqs_to_free); | ||
262 | |||
263 | void 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 | |||
279 | static 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 | ||
256 | void close_chan(struct list_head *chans) | 301 | void 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 | ||
342 | void free_one_chan(struct chan *chan) | 383 | void 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 | ||
352 | void free_chan(struct list_head *chans) | 396 | void 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 | ||
469 | static struct chan *parse_chan(char *str, int device, struct chan_opts *opts) | 513 | static 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 | ||
512 | int parse_chan_pair(char *str, struct list_head *chans, int device, | 561 | int 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 | */ | ||