LCOV - code coverage report
Current view: top level - arch/um/drivers - line.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 57 347 16.4 %
Date: 2023-08-24 13:40:31 Functions: 5 33 15.2 %

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

Generated by: LCOV version 1.14