linux/arch/um/drivers/line.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   6#include <linux/irqreturn.h>
   7#include <linux/kd.h>
   8#include <linux/sched.h>
   9#include <linux/slab.h>
  10#include "chan.h"
  11#include <irq_kern.h>
  12#include <irq_user.h>
  13#include <kern_util.h>
  14#include <os.h>
  15
  16#define LINE_BUFSIZE 4096
  17
  18static irqreturn_t line_interrupt(int irq, void *data)
  19{
  20        struct chan *chan = data;
  21        struct line *line = chan->line;
  22
  23        if (line)
  24                chan_interrupt(line, irq);
  25
  26        return IRQ_HANDLED;
  27}
  28
  29/*
  30 * Returns the free space inside the ring buffer of this line.
  31 *
  32 * Should be called while holding line->lock (this does not modify data).
  33 */
  34static int write_room(struct line *line)
  35{
  36        int n;
  37
  38        if (line->buffer == NULL)
  39                return LINE_BUFSIZE - 1;
  40
  41        /* This is for the case where the buffer is wrapped! */
  42        n = line->head - line->tail;
  43
  44        if (n <= 0)
  45                n += LINE_BUFSIZE; /* The other case */
  46        return n - 1;
  47}
  48
  49int line_write_room(struct tty_struct *tty)
  50{
  51        struct line *line = tty->driver_data;
  52        unsigned long flags;
  53        int room;
  54
  55        spin_lock_irqsave(&line->lock, flags);
  56        room = write_room(line);
  57        spin_unlock_irqrestore(&line->lock, flags);
  58
  59        return room;
  60}
  61
  62int line_chars_in_buffer(struct tty_struct *tty)
  63{
  64        struct line *line = tty->driver_data;
  65        unsigned long flags;
  66        int ret;
  67
  68        spin_lock_irqsave(&line->lock, flags);
  69        /* write_room subtracts 1 for the needed NULL, so we readd it.*/
  70        ret = LINE_BUFSIZE - (write_room(line) + 1);
  71        spin_unlock_irqrestore(&line->lock, flags);
  72
  73        return ret;
  74}
  75
  76/*
  77 * This copies the content of buf into the circular buffer associated with
  78 * this line.
  79 * The return value is the number of characters actually copied, i.e. the ones
  80 * for which there was space: this function is not supposed to ever flush out
  81 * the circular buffer.
  82 *
  83 * Must be called while holding line->lock!
  84 */
  85static int buffer_data(struct line *line, const char *buf, int len)
  86{
  87        int end, room;
  88
  89        if (line->buffer == NULL) {
  90                line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
  91                if (line->buffer == NULL) {
  92                        printk(KERN_ERR "buffer_data - atomic allocation "
  93                               "failed\n");
  94                        return 0;
  95                }
  96                line->head = line->buffer;
  97                line->tail = line->buffer;
  98        }
  99
 100        room = write_room(line);
 101        len = (len > room) ? room : len;
 102
 103        end = line->buffer + LINE_BUFSIZE - line->tail;
 104
 105        if (len < end) {
 106                memcpy(line->tail, buf, len);
 107                line->tail += len;
 108        }
 109        else {
 110                /* The circular buffer is wrapping */
 111                memcpy(line->tail, buf, end);
 112                buf += end;
 113                memcpy(line->buffer, buf, len - end);
 114                line->tail = line->buffer + len - end;
 115        }
 116
 117        return len;
 118}
 119
 120/*
 121 * Flushes the ring buffer to the output channels. That is, write_chan is
 122 * called, passing it line->head as buffer, and an appropriate count.
 123 *
 124 * On exit, returns 1 when the buffer is empty,
 125 * 0 when the buffer is not empty on exit,
 126 * and -errno when an error occurred.
 127 *
 128 * Must be called while holding line->lock!*/
 129static int flush_buffer(struct line *line)
 130{
 131        int n, count;
 132
 133        if ((line->buffer == NULL) || (line->head == line->tail))
 134                return 1;
 135
 136        if (line->tail < line->head) {
 137                /* line->buffer + LINE_BUFSIZE is the end of the buffer! */
 138                count = line->buffer + LINE_BUFSIZE - line->head;
 139
 140                n = write_chan(line->chan_out, line->head, count,
 141                               line->driver->write_irq);
 142                if (n < 0)
 143                        return n;
 144                if (n == count) {
 145                        /*
 146                         * We have flushed from ->head to buffer end, now we
 147                         * must flush only from the beginning to ->tail.
 148                         */
 149                        line->head = line->buffer;
 150                } else {
 151                        line->head += n;
 152                        return 0;
 153                }
 154        }
 155
 156        count = line->tail - line->head;
 157        n = write_chan(line->chan_out, line->head, count,
 158                       line->driver->write_irq);
 159
 160        if (n < 0)
 161                return n;
 162
 163        line->head += n;
 164        return line->head == line->tail;
 165}
 166
 167void line_flush_buffer(struct tty_struct *tty)
 168{
 169        struct line *line = tty->driver_data;
 170        unsigned long flags;
 171
 172        spin_lock_irqsave(&line->lock, flags);
 173        flush_buffer(line);
 174        spin_unlock_irqrestore(&line->lock, flags);
 175}
 176
 177/*
 178 * We map both ->flush_chars and ->put_char (which go in pair) onto
 179 * ->flush_buffer and ->write. Hope it's not that bad.
 180 */
 181void line_flush_chars(struct tty_struct *tty)
 182{
 183        line_flush_buffer(tty);
 184}
 185
 186int line_put_char(struct tty_struct *tty, unsigned char ch)
 187{
 188        return line_write(tty, &ch, sizeof(ch));
 189}
 190
 191int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
 192{
 193        struct line *line = tty->driver_data;
 194        unsigned long flags;
 195        int n, ret = 0;
 196
 197        spin_lock_irqsave(&line->lock, flags);
 198        if (line->head != line->tail)
 199                ret = buffer_data(line, buf, len);
 200        else {
 201                n = write_chan(line->chan_out, buf, len,
 202                               line->driver->write_irq);
 203                if (n < 0) {
 204                        ret = n;
 205                        goto out_up;
 206                }
 207
 208                len -= n;
 209                ret += n;
 210                if (len > 0)
 211                        ret += buffer_data(line, buf + n, len);
 212        }
 213out_up:
 214        spin_unlock_irqrestore(&line->lock, flags);
 215        return ret;
 216}
 217
 218void line_set_termios(struct tty_struct *tty, struct ktermios * old)
 219{
 220        /* nothing */
 221}
 222
 223void line_throttle(struct tty_struct *tty)
 224{
 225        struct line *line = tty->driver_data;
 226
 227        deactivate_chan(line->chan_in, line->driver->read_irq);
 228        line->throttled = 1;
 229}
 230
 231void line_unthrottle(struct tty_struct *tty)
 232{
 233        struct line *line = tty->driver_data;
 234
 235        line->throttled = 0;
 236        chan_interrupt(line, line->driver->read_irq);
 237
 238        /*
 239         * Maybe there is enough stuff pending that calling the interrupt
 240         * throttles us again.  In this case, line->throttled will be 1
 241         * again and we shouldn't turn the interrupt back on.
 242         */
 243        if (!line->throttled)
 244                reactivate_chan(line->chan_in, line->driver->read_irq);
 245}
 246
 247static irqreturn_t line_write_interrupt(int irq, void *data)
 248{
 249        struct chan *chan = data;
 250        struct line *line = chan->line;
 251        int err;
 252
 253        /*
 254         * Interrupts are disabled here because genirq keep irqs disabled when
 255         * calling the action handler.
 256         */
 257
 258        spin_lock(&line->lock);
 259        err = flush_buffer(line);
 260        if (err == 0) {
 261                spin_unlock(&line->lock);
 262                return IRQ_NONE;
 263        } else if (err < 0) {
 264                line->head = line->buffer;
 265                line->tail = line->buffer;
 266        }
 267        spin_unlock(&line->lock);
 268
 269        tty_port_tty_wakeup(&line->port);
 270
 271        return IRQ_HANDLED;
 272}
 273
 274int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
 275{
 276        const struct line_driver *driver = line->driver;
 277        int err = 0;
 278
 279        if (input)
 280                err = um_request_irq(driver->read_irq, fd, IRQ_READ,
 281                                     line_interrupt, IRQF_SHARED,
 282                                     driver->read_irq_name, data);
 283        if (err)
 284                return err;
 285        if (output)
 286                err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
 287                                     line_write_interrupt, IRQF_SHARED,
 288                                     driver->write_irq_name, data);
 289        return err;
 290}
 291
 292static int line_activate(struct tty_port *port, struct tty_struct *tty)
 293{
 294        int ret;
 295        struct line *line = tty->driver_data;
 296
 297        ret = enable_chan(line);
 298        if (ret)
 299                return ret;
 300
 301        if (!line->sigio) {
 302                chan_enable_winch(line->chan_out, port);
 303                line->sigio = 1;
 304        }
 305
 306        chan_window_size(line, &tty->winsize.ws_row,
 307                &tty->winsize.ws_col);
 308
 309        return 0;
 310}
 311
 312static void unregister_winch(struct tty_struct *tty);
 313
 314static void line_destruct(struct tty_port *port)
 315{
 316        struct tty_struct *tty = tty_port_tty_get(port);
 317        struct line *line = tty->driver_data;
 318
 319        if (line->sigio) {
 320                unregister_winch(tty);
 321                line->sigio = 0;
 322        }
 323}
 324
 325static const struct tty_port_operations line_port_ops = {
 326        .activate = line_activate,
 327        .destruct = line_destruct,
 328};
 329
 330int line_open(struct tty_struct *tty, struct file *filp)
 331{
 332        struct line *line = tty->driver_data;
 333
 334        return tty_port_open(&line->port, tty, filp);
 335}
 336
 337int line_install(struct tty_driver *driver, struct tty_struct *tty,
 338                 struct line *line)
 339{
 340        int ret;
 341
 342        ret = tty_standard_install(driver, tty);
 343        if (ret)
 344                return ret;
 345
 346        tty->driver_data = line;
 347
 348        return 0;
 349}
 350
 351void line_close(struct tty_struct *tty, struct file * filp)
 352{
 353        struct line *line = tty->driver_data;
 354
 355        tty_port_close(&line->port, tty, filp);
 356}
 357
 358void line_hangup(struct tty_struct *tty)
 359{
 360        struct line *line = tty->driver_data;
 361
 362        tty_port_hangup(&line->port);
 363}
 364
 365void close_lines(struct line *lines, int nlines)
 366{
 367        int i;
 368
 369        for(i = 0; i < nlines; i++)
 370                close_chan(&lines[i]);
 371}
 372
 373int setup_one_line(struct line *lines, int n, char *init,
 374                   const struct chan_opts *opts, char **error_out)
 375{
 376        struct line *line = &lines[n];
 377        struct tty_driver *driver = line->driver->driver;
 378        int err = -EINVAL;
 379
 380        if (line->port.count) {
 381                *error_out = "Device is already open";
 382                goto out;
 383        }
 384
 385        if (!strcmp(init, "none")) {
 386                if (line->valid) {
 387                        line->valid = 0;
 388                        kfree(line->init_str);
 389                        tty_unregister_device(driver, n);
 390                        parse_chan_pair(NULL, line, n, opts, error_out);
 391                        err = 0;
 392                }
 393        } else {
 394                char *new = kstrdup(init, GFP_KERNEL);
 395                if (!new) {
 396                        *error_out = "Failed to allocate memory";
 397                        return -ENOMEM;
 398                }
 399                if (line->valid) {
 400                        tty_unregister_device(driver, n);
 401                        kfree(line->init_str);
 402                }
 403                line->init_str = new;
 404                line->valid = 1;
 405                err = parse_chan_pair(new, line, n, opts, error_out);
 406                if (!err) {
 407                        struct device *d = tty_port_register_device(&line->port,
 408                                        driver, n, NULL);
 409                        if (IS_ERR(d)) {
 410                                *error_out = "Failed to register device";
 411                                err = PTR_ERR(d);
 412                                parse_chan_pair(NULL, line, n, opts, error_out);
 413                        }
 414                }
 415                if (err) {
 416                        line->init_str = NULL;
 417                        line->valid = 0;
 418                        kfree(new);
 419                }
 420        }
 421out:
 422        return err;
 423}
 424
 425/*
 426 * Common setup code for both startup command line and mconsole initialization.
 427 * @lines contains the array (of size @num) to modify;
 428 * @init is the setup string;
 429 * @error_out is an error string in the case of failure;
 430 */
 431
 432int line_setup(char **conf, unsigned int num, char **def,
 433               char *init, char *name)
 434{
 435        char *error;
 436
 437        if (*init == '=') {
 438                /*
 439                 * We said con=/ssl= instead of con#=, so we are configuring all
 440                 * consoles at once.
 441                 */
 442                *def = init + 1;
 443        } else {
 444                char *end;
 445                unsigned n = simple_strtoul(init, &end, 0);
 446
 447                if (*end != '=') {
 448                        error = "Couldn't parse device number";
 449                        goto out;
 450                }
 451                if (n >= num) {
 452                        error = "Device number out of range";
 453                        goto out;
 454                }
 455                conf[n] = end + 1;
 456        }
 457        return 0;
 458
 459out:
 460        printk(KERN_ERR "Failed to set up %s with "
 461               "configuration string \"%s\" : %s\n", name, init, error);
 462        return -EINVAL;
 463}
 464
 465int line_config(struct line *lines, unsigned int num, char *str,
 466                const struct chan_opts *opts, char **error_out)
 467{
 468        char *end;
 469        int n;
 470
 471        if (*str == '=') {
 472                *error_out = "Can't configure all devices from mconsole";
 473                return -EINVAL;
 474        }
 475
 476        n = simple_strtoul(str, &end, 0);
 477        if (*end++ != '=') {
 478                *error_out = "Couldn't parse device number";
 479                return -EINVAL;
 480        }
 481        if (n >= num) {
 482                *error_out = "Device number out of range";
 483                return -EINVAL;
 484        }
 485
 486        return setup_one_line(lines, n, end, opts, error_out);
 487}
 488
 489int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
 490                    int size, char **error_out)
 491{
 492        struct line *line;
 493        char *end;
 494        int dev, n = 0;
 495
 496        dev = simple_strtoul(name, &end, 0);
 497        if ((*end != '\0') || (end == name)) {
 498                *error_out = "line_get_config failed to parse device number";
 499                return 0;
 500        }
 501
 502        if ((dev < 0) || (dev >= num)) {
 503                *error_out = "device number out of range";
 504                return 0;
 505        }
 506
 507        line = &lines[dev];
 508
 509        if (!line->valid)
 510                CONFIG_CHUNK(str, size, n, "none", 1);
 511        else {
 512                struct tty_struct *tty = tty_port_tty_get(&line->port);
 513                if (tty == NULL) {
 514                        CONFIG_CHUNK(str, size, n, line->init_str, 1);
 515                } else {
 516                        n = chan_config_string(line, str, size, error_out);
 517                        tty_kref_put(tty);
 518                }
 519        }
 520
 521        return n;
 522}
 523
 524int line_id(char **str, int *start_out, int *end_out)
 525{
 526        char *end;
 527        int n;
 528
 529        n = simple_strtoul(*str, &end, 0);
 530        if ((*end != '\0') || (end == *str))
 531                return -1;
 532
 533        *str = end;
 534        *start_out = n;
 535        *end_out = n;
 536        return n;
 537}
 538
 539int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
 540{
 541        if (n >= num) {
 542                *error_out = "Device number out of range";
 543                return -EINVAL;
 544        }
 545        return setup_one_line(lines, n, "none", NULL, error_out);
 546}
 547
 548int register_lines(struct line_driver *line_driver,
 549                   const struct tty_operations *ops,
 550                   struct line *lines, int nlines)
 551{
 552        struct tty_driver *driver = alloc_tty_driver(nlines);
 553        int err;
 554        int i;
 555
 556        if (!driver)
 557                return -ENOMEM;
 558
 559        driver->driver_name = line_driver->name;
 560        driver->name = line_driver->device_name;
 561        driver->major = line_driver->major;
 562        driver->minor_start = line_driver->minor_start;
 563        driver->type = line_driver->type;
 564        driver->subtype = line_driver->subtype;
 565        driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 566        driver->init_termios = tty_std_termios;
 567        
 568        for (i = 0; i < nlines; i++) {
 569                tty_port_init(&lines[i].port);
 570                lines[i].port.ops = &line_port_ops;
 571                spin_lock_init(&lines[i].lock);
 572                lines[i].driver = line_driver;
 573                INIT_LIST_HEAD(&lines[i].chan_list);
 574        }
 575        tty_set_operations(driver, ops);
 576
 577        err = tty_register_driver(driver);
 578        if (err) {
 579                printk(KERN_ERR "register_lines : can't register %s driver\n",
 580                       line_driver->name);
 581                put_tty_driver(driver);
 582                for (i = 0; i < nlines; i++)
 583                        tty_port_destroy(&lines[i].port);
 584                return err;
 585        }
 586
 587        line_driver->driver = driver;
 588        mconsole_register_dev(&line_driver->mc);
 589        return 0;
 590}
 591
 592static DEFINE_SPINLOCK(winch_handler_lock);
 593static LIST_HEAD(winch_handlers);
 594
 595struct winch {
 596        struct list_head list;
 597        int fd;
 598        int tty_fd;
 599        int pid;
 600        struct tty_port *port;
 601        unsigned long stack;
 602        struct work_struct work;
 603};
 604
 605static void __free_winch(struct work_struct *work)
 606{
 607        struct winch *winch = container_of(work, struct winch, work);
 608        um_free_irq(WINCH_IRQ, winch);
 609
 610        if (winch->pid != -1)
 611                os_kill_process(winch->pid, 1);
 612        if (winch->stack != 0)
 613                free_stack(winch->stack, 0);
 614        kfree(winch);
 615}
 616
 617static void free_winch(struct winch *winch)
 618{
 619        int fd = winch->fd;
 620        winch->fd = -1;
 621        if (fd != -1)
 622                os_close_file(fd);
 623        list_del(&winch->list);
 624        __free_winch(&winch->work);
 625}
 626
 627static irqreturn_t winch_interrupt(int irq, void *data)
 628{
 629        struct winch *winch = data;
 630        struct tty_struct *tty;
 631        struct line *line;
 632        int fd = winch->fd;
 633        int err;
 634        char c;
 635        struct pid *pgrp;
 636
 637        if (fd != -1) {
 638                err = generic_read(fd, &c, NULL);
 639                if (err < 0) {
 640                        if (err != -EAGAIN) {
 641                                winch->fd = -1;
 642                                list_del(&winch->list);
 643                                os_close_file(fd);
 644                                printk(KERN_ERR "winch_interrupt : "
 645                                       "read failed, errno = %d\n", -err);
 646                                printk(KERN_ERR "fd %d is losing SIGWINCH "
 647                                       "support\n", winch->tty_fd);
 648                                INIT_WORK(&winch->work, __free_winch);
 649                                schedule_work(&winch->work);
 650                                return IRQ_HANDLED;
 651                        }
 652                        goto out;
 653                }
 654        }
 655        tty = tty_port_tty_get(winch->port);
 656        if (tty != NULL) {
 657                line = tty->driver_data;
 658                if (line != NULL) {
 659                        chan_window_size(line, &tty->winsize.ws_row,
 660                                         &tty->winsize.ws_col);
 661                        pgrp = tty_get_pgrp(tty);
 662                        if (pgrp)
 663                                kill_pgrp(pgrp, SIGWINCH, 1);
 664                        put_pid(pgrp);
 665                }
 666                tty_kref_put(tty);
 667        }
 668 out:
 669        if (winch->fd != -1)
 670                reactivate_fd(winch->fd, WINCH_IRQ);
 671        return IRQ_HANDLED;
 672}
 673
 674void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port,
 675                        unsigned long stack)
 676{
 677        struct winch *winch;
 678
 679        winch = kmalloc(sizeof(*winch), GFP_KERNEL);
 680        if (winch == NULL) {
 681                printk(KERN_ERR "register_winch_irq - kmalloc failed\n");
 682                goto cleanup;
 683        }
 684
 685        *winch = ((struct winch) { .list        = LIST_HEAD_INIT(winch->list),
 686                                   .fd          = fd,
 687                                   .tty_fd      = tty_fd,
 688                                   .pid         = pid,
 689                                   .port        = port,
 690                                   .stack       = stack });
 691
 692        if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
 693                           IRQF_SHARED, "winch", winch) < 0) {
 694                printk(KERN_ERR "register_winch_irq - failed to register "
 695                       "IRQ\n");
 696                goto out_free;
 697        }
 698
 699        spin_lock(&winch_handler_lock);
 700        list_add(&winch->list, &winch_handlers);
 701        spin_unlock(&winch_handler_lock);
 702
 703        return;
 704
 705 out_free:
 706        kfree(winch);
 707 cleanup:
 708        os_kill_process(pid, 1);
 709        os_close_file(fd);
 710        if (stack != 0)
 711                free_stack(stack, 0);
 712}
 713
 714static void unregister_winch(struct tty_struct *tty)
 715{
 716        struct list_head *ele, *next;
 717        struct winch *winch;
 718        struct tty_struct *wtty;
 719
 720        spin_lock(&winch_handler_lock);
 721
 722        list_for_each_safe(ele, next, &winch_handlers) {
 723                winch = list_entry(ele, struct winch, list);
 724                wtty = tty_port_tty_get(winch->port);
 725                if (wtty == tty) {
 726                        free_winch(winch);
 727                        break;
 728                }
 729                tty_kref_put(wtty);
 730        }
 731        spin_unlock(&winch_handler_lock);
 732}
 733
 734static void winch_cleanup(void)
 735{
 736        struct list_head *ele, *next;
 737        struct winch *winch;
 738
 739        spin_lock(&winch_handler_lock);
 740
 741        list_for_each_safe(ele, next, &winch_handlers) {
 742                winch = list_entry(ele, struct winch, list);
 743                free_winch(winch);
 744        }
 745
 746        spin_unlock(&winch_handler_lock);
 747}
 748__uml_exitcall(winch_cleanup);
 749
 750char *add_xterm_umid(char *base)
 751{
 752        char *umid, *title;
 753        int len;
 754
 755        umid = get_umid();
 756        if (*umid == '\0')
 757                return base;
 758
 759        len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
 760        title = kmalloc(len, GFP_KERNEL);
 761        if (title == NULL) {
 762                printk(KERN_ERR "Failed to allocate buffer for xterm title\n");
 763                return base;
 764        }
 765
 766        snprintf(title, len, "%s (%s)", base, umid);
 767        return title;
 768}
 769