aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/chan_kern.c
diff options
context:
space:
mode:
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 */