diff options
-rw-r--r-- | arch/um/drivers/chan_kern.c | 111 | ||||
-rw-r--r-- | arch/um/drivers/line.c | 116 | ||||
-rw-r--r-- | arch/um/include/chan_kern.h | 9 | ||||
-rw-r--r-- | arch/um/include/irq_user.h | 13 | ||||
-rw-r--r-- | arch/um/include/line.h | 6 | ||||
-rw-r--r-- | arch/um/kernel/irq_user.c | 48 |
6 files changed, 137 insertions, 166 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 | */ | ||
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){ |
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 22bf3a73437c..84d1f64f9795 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h | |||
@@ -14,11 +14,14 @@ | |||
14 | 14 | ||
15 | struct chan { | 15 | struct chan { |
16 | struct list_head list; | 16 | struct list_head list; |
17 | struct list_head free_list; | ||
18 | struct line *line; | ||
17 | char *dev; | 19 | char *dev; |
18 | unsigned int primary:1; | 20 | unsigned int primary:1; |
19 | unsigned int input:1; | 21 | unsigned int input:1; |
20 | unsigned int output:1; | 22 | unsigned int output:1; |
21 | unsigned int opened:1; | 23 | unsigned int opened:1; |
24 | unsigned int enabled:1; | ||
22 | int fd; | 25 | int fd; |
23 | struct chan_ops *ops; | 26 | struct chan_ops *ops; |
24 | void *data; | 27 | void *data; |
@@ -26,7 +29,7 @@ struct chan { | |||
26 | 29 | ||
27 | extern void chan_interrupt(struct list_head *chans, struct work_struct *task, | 30 | extern void chan_interrupt(struct list_head *chans, struct work_struct *task, |
28 | struct tty_struct *tty, int irq); | 31 | struct tty_struct *tty, int irq); |
29 | extern int parse_chan_pair(char *str, struct list_head *chans, int device, | 32 | extern int parse_chan_pair(char *str, struct line *line, int device, |
30 | struct chan_opts *opts); | 33 | struct chan_opts *opts); |
31 | extern int open_chan(struct list_head *chans); | 34 | extern int open_chan(struct list_head *chans); |
32 | extern int write_chan(struct list_head *chans, const char *buf, int len, | 35 | extern int write_chan(struct list_head *chans, const char *buf, int len, |
@@ -35,9 +38,9 @@ extern int console_write_chan(struct list_head *chans, const char *buf, | |||
35 | int len); | 38 | int len); |
36 | extern int console_open_chan(struct line *line, struct console *co, | 39 | extern int console_open_chan(struct line *line, struct console *co, |
37 | struct chan_opts *opts); | 40 | struct chan_opts *opts); |
38 | extern void close_chan(struct list_head *chans); | ||
39 | extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); | 41 | extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); |
40 | extern void enable_chan(struct list_head *chans, struct tty_struct *tty); | 42 | extern void enable_chan(struct line *line); |
43 | extern void close_chan(struct list_head *chans, int delay_free_irq); | ||
41 | extern int chan_window_size(struct list_head *chans, | 44 | extern int chan_window_size(struct list_head *chans, |
42 | unsigned short *rows_out, | 45 | unsigned short *rows_out, |
43 | unsigned short *cols_out); | 46 | unsigned short *cols_out); |
diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index f724b717213f..b61deb8b362a 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h | |||
@@ -18,19 +18,8 @@ extern int deactivate_all_fds(void); | |||
18 | extern void forward_interrupts(int pid); | 18 | extern void forward_interrupts(int pid); |
19 | extern void init_irq_signals(int on_sigstack); | 19 | extern void init_irq_signals(int on_sigstack); |
20 | extern void forward_ipi(int fd, int pid); | 20 | extern void forward_ipi(int fd, int pid); |
21 | extern void free_irq_later(int irq, void *dev_id); | ||
22 | extern int activate_ipi(int fd, int pid); | 21 | extern int activate_ipi(int fd, int pid); |
23 | extern unsigned long irq_lock(void); | 22 | extern unsigned long irq_lock(void); |
24 | extern void irq_unlock(unsigned long flags); | 23 | extern void irq_unlock(unsigned long flags); |
25 | #endif | ||
26 | 24 | ||
27 | /* | 25 | #endif |
28 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
29 | * Emacs will notice this stuff at the end of the file and automatically | ||
30 | * adjust the settings for this buffer only. This must remain at the end | ||
31 | * of the file. | ||
32 | * --------------------------------------------------------------------------- | ||
33 | * Local variables: | ||
34 | * c-file-style: "linux" | ||
35 | * End: | ||
36 | */ | ||
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 474398ba1207..e6cc3abfd4db 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h | |||
@@ -32,6 +32,7 @@ struct line_driver { | |||
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct line { | 34 | struct line { |
35 | struct tty_struct *tty; | ||
35 | char *init_str; | 36 | char *init_str; |
36 | int init_pri; | 37 | int init_pri; |
37 | struct list_head chan_list; | 38 | struct list_head chan_list; |
@@ -89,10 +90,9 @@ extern int line_ioctl(struct tty_struct *tty, struct file * file, | |||
89 | unsigned int cmd, unsigned long arg); | 90 | unsigned int cmd, unsigned long arg); |
90 | 91 | ||
91 | extern char *add_xterm_umid(char *base); | 92 | extern char *add_xterm_umid(char *base); |
92 | extern int line_setup_irq(int fd, int input, int output, | 93 | extern int line_setup_irq(int fd, int input, int output, struct line *line, |
93 | struct tty_struct *tty); | 94 | void *data); |
94 | extern void line_close_chan(struct line *line); | 95 | extern void line_close_chan(struct line *line); |
95 | extern void line_disable(struct tty_struct *tty, int current_irq); | ||
96 | extern struct tty_driver * line_register_devfs(struct lines *set, | 96 | extern struct tty_driver * line_register_devfs(struct lines *set, |
97 | struct line_driver *line_driver, | 97 | struct line_driver *line_driver, |
98 | struct tty_operations *driver, | 98 | struct tty_operations *driver, |
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index c3ccaf24f3e0..50a2aa35cda9 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c | |||
@@ -29,7 +29,6 @@ struct irq_fd { | |||
29 | int pid; | 29 | int pid; |
30 | int events; | 30 | int events; |
31 | int current_events; | 31 | int current_events; |
32 | int freed; | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | static struct irq_fd *active_fds = NULL; | 34 | static struct irq_fd *active_fds = NULL; |
@@ -41,9 +40,11 @@ static int pollfds_size = 0; | |||
41 | 40 | ||
42 | extern int io_count, intr_count; | 41 | extern int io_count, intr_count; |
43 | 42 | ||
43 | extern void free_irqs(void); | ||
44 | |||
44 | void sigio_handler(int sig, union uml_pt_regs *regs) | 45 | void sigio_handler(int sig, union uml_pt_regs *regs) |
45 | { | 46 | { |
46 | struct irq_fd *irq_fd, *next; | 47 | struct irq_fd *irq_fd; |
47 | int i, n; | 48 | int i, n; |
48 | 49 | ||
49 | if(smp_sigio_handler()) return; | 50 | if(smp_sigio_handler()) return; |
@@ -66,29 +67,15 @@ void sigio_handler(int sig, union uml_pt_regs *regs) | |||
66 | irq_fd = irq_fd->next; | 67 | irq_fd = irq_fd->next; |
67 | } | 68 | } |
68 | 69 | ||
69 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){ | 70 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ |
70 | next = irq_fd->next; | ||
71 | if(irq_fd->current_events != 0){ | 71 | if(irq_fd->current_events != 0){ |
72 | irq_fd->current_events = 0; | 72 | irq_fd->current_events = 0; |
73 | do_IRQ(irq_fd->irq, regs); | 73 | do_IRQ(irq_fd->irq, regs); |
74 | |||
75 | /* This is here because the next irq may be | ||
76 | * freed in the handler. If a console goes | ||
77 | * away, both the read and write irqs will be | ||
78 | * freed. After do_IRQ, ->next will point to | ||
79 | * a good IRQ. | ||
80 | * Irqs can't be freed inside their handlers, | ||
81 | * so the next best thing is to have them | ||
82 | * marked as needing freeing, so that they | ||
83 | * can be freed here. | ||
84 | */ | ||
85 | next = irq_fd->next; | ||
86 | if(irq_fd->freed){ | ||
87 | free_irq(irq_fd->irq, irq_fd->id); | ||
88 | } | ||
89 | } | 74 | } |
90 | } | 75 | } |
91 | } | 76 | } |
77 | |||
78 | free_irqs(); | ||
92 | } | 79 | } |
93 | 80 | ||
94 | int activate_ipi(int fd, int pid) | 81 | int activate_ipi(int fd, int pid) |
@@ -136,8 +123,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) | |||
136 | .irq = irq, | 123 | .irq = irq, |
137 | .pid = pid, | 124 | .pid = pid, |
138 | .events = events, | 125 | .events = events, |
139 | .current_events = 0, | 126 | .current_events = 0 } ); |
140 | .freed = 0 } ); | ||
141 | 127 | ||
142 | /* Critical section - locked by a spinlock because this stuff can | 128 | /* Critical section - locked by a spinlock because this stuff can |
143 | * be changed from interrupt handlers. The stuff above is done | 129 | * be changed from interrupt handlers. The stuff above is done |
@@ -313,26 +299,6 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) | |||
313 | return(irq); | 299 | return(irq); |
314 | } | 300 | } |
315 | 301 | ||
316 | void free_irq_later(int irq, void *dev_id) | ||
317 | { | ||
318 | struct irq_fd *irq_fd; | ||
319 | unsigned long flags; | ||
320 | |||
321 | flags = irq_lock(); | ||
322 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ | ||
323 | if((irq_fd->irq == irq) && (irq_fd->id == dev_id)) | ||
324 | break; | ||
325 | } | ||
326 | if(irq_fd == NULL){ | ||
327 | printk("free_irq_later found no irq, irq = %d, " | ||
328 | "dev_id = 0x%p\n", irq, dev_id); | ||
329 | goto out; | ||
330 | } | ||
331 | irq_fd->freed = 1; | ||
332 | out: | ||
333 | irq_unlock(flags); | ||
334 | } | ||
335 | |||
336 | void reactivate_fd(int fd, int irqnum) | 302 | void reactivate_fd(int fd, int irqnum) |
337 | { | 303 | { |
338 | struct irq_fd *irq; | 304 | struct irq_fd *irq; |