diff options
Diffstat (limited to 'arch')
| -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; |
