aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers')
-rw-r--r--arch/um/drivers/chan_kern.c111
-rw-r--r--arch/um/drivers/line.c116
2 files changed, 120 insertions, 107 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 */
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
24static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) 24static 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
34static void line_timer_cb(void *arg) 35static 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,
342static irqreturn_t line_write_interrupt(int irq, void *data, 343static 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
380int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) 382int 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
400void 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
422int line_open(struct line *lines, struct tty_struct *tty) 401int 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;
456out: 435out:
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
584int line_get_config(char *name, struct line *lines, unsigned int num, char *str, 562int 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){