LCOV - code coverage report
Current view: top level - arch/um/drivers - line.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 57 348 16.4 %
Date: 2022-12-09 01:23:36 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           0 :                                line->driver->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           0 :                        line->driver->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           0 :                                line->driver->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->driver->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->driver->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(driver->read_irq, fd, IRQ_READ,
     264             :                                      line_interrupt, IRQF_SHARED,
     265             :                                      driver->read_irq_name, data);
     266           0 :                 if (err < 0)
     267             :                         return err;
     268             :         }
     269             : 
     270           0 :         if (output) {
     271           0 :                 err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
     272             :                                      line_write_interrupt, IRQF_SHARED,
     273             :                                      driver->write_irq_name, data);
     274           0 :                 if (err < 0)
     275             :                         return err;
     276             :         }
     277             : 
     278             :         return 0;
     279             : }
     280             : 
     281           0 : static int line_activate(struct tty_port *port, struct tty_struct *tty)
     282             : {
     283             :         int ret;
     284           0 :         struct line *line = tty->driver_data;
     285             : 
     286           0 :         ret = enable_chan(line);
     287           0 :         if (ret)
     288             :                 return ret;
     289             : 
     290           0 :         if (!line->sigio) {
     291           0 :                 chan_enable_winch(line->chan_out, port);
     292           0 :                 line->sigio = 1;
     293             :         }
     294             : 
     295           0 :         chan_window_size(line, &tty->winsize.ws_row,
     296             :                 &tty->winsize.ws_col);
     297             : 
     298           0 :         return 0;
     299             : }
     300             : 
     301             : static void unregister_winch(struct tty_struct *tty);
     302             : 
     303           0 : static void line_destruct(struct tty_port *port)
     304             : {
     305           0 :         struct tty_struct *tty = tty_port_tty_get(port);
     306           0 :         struct line *line = tty->driver_data;
     307             : 
     308           0 :         if (line->sigio) {
     309           0 :                 unregister_winch(tty);
     310           0 :                 line->sigio = 0;
     311             :         }
     312           0 : }
     313             : 
     314             : static const struct tty_port_operations line_port_ops = {
     315             :         .activate = line_activate,
     316             :         .destruct = line_destruct,
     317             : };
     318             : 
     319           0 : int line_open(struct tty_struct *tty, struct file *filp)
     320             : {
     321           0 :         struct line *line = tty->driver_data;
     322             : 
     323           0 :         return tty_port_open(&line->port, tty, filp);
     324             : }
     325             : 
     326           0 : int line_install(struct tty_driver *driver, struct tty_struct *tty,
     327             :                  struct line *line)
     328             : {
     329             :         int ret;
     330             : 
     331           0 :         ret = tty_standard_install(driver, tty);
     332           0 :         if (ret)
     333             :                 return ret;
     334             : 
     335           0 :         tty->driver_data = line;
     336             : 
     337           0 :         return 0;
     338             : }
     339             : 
     340           0 : void line_close(struct tty_struct *tty, struct file * filp)
     341             : {
     342           0 :         struct line *line = tty->driver_data;
     343             : 
     344           0 :         tty_port_close(&line->port, tty, filp);
     345           0 : }
     346             : 
     347           0 : void line_hangup(struct tty_struct *tty)
     348             : {
     349           0 :         struct line *line = tty->driver_data;
     350             : 
     351           0 :         tty_port_hangup(&line->port);
     352           0 : }
     353             : 
     354           1 : void close_lines(struct line *lines, int nlines)
     355             : {
     356             :         int i;
     357             : 
     358          17 :         for(i = 0; i < nlines; i++)
     359          16 :                 close_chan(&lines[i]);
     360           1 : }
     361             : 
     362          16 : int setup_one_line(struct line *lines, int n, char *init,
     363             :                    const struct chan_opts *opts, char **error_out)
     364             : {
     365          16 :         struct line *line = &lines[n];
     366          16 :         struct tty_driver *driver = line->driver->driver;
     367          16 :         int err = -EINVAL;
     368             : 
     369          16 :         if (line->port.count) {
     370           0 :                 *error_out = "Device is already open";
     371           0 :                 goto out;
     372             :         }
     373             : 
     374          16 :         if (!strcmp(init, "none")) {
     375           0 :                 if (line->valid) {
     376           0 :                         line->valid = 0;
     377           0 :                         kfree(line->init_str);
     378           0 :                         tty_unregister_device(driver, n);
     379           0 :                         parse_chan_pair(NULL, line, n, opts, error_out);
     380           0 :                         err = 0;
     381             :                 }
     382             :         } else {
     383          16 :                 char *new = kstrdup(init, GFP_KERNEL);
     384          16 :                 if (!new) {
     385           0 :                         *error_out = "Failed to allocate memory";
     386           0 :                         return -ENOMEM;
     387             :                 }
     388          16 :                 if (line->valid) {
     389           0 :                         tty_unregister_device(driver, n);
     390           0 :                         kfree(line->init_str);
     391             :                 }
     392          16 :                 line->init_str = new;
     393          16 :                 line->valid = 1;
     394          16 :                 err = parse_chan_pair(new, line, n, opts, error_out);
     395          16 :                 if (!err) {
     396           1 :                         struct device *d = tty_port_register_device(&line->port,
     397             :                                         driver, n, NULL);
     398           1 :                         if (IS_ERR(d)) {
     399           0 :                                 *error_out = "Failed to register device";
     400           0 :                                 err = PTR_ERR(d);
     401           0 :                                 parse_chan_pair(NULL, line, n, opts, error_out);
     402             :                         }
     403             :                 }
     404          16 :                 if (err) {
     405          15 :                         line->init_str = NULL;
     406          15 :                         line->valid = 0;
     407          15 :                         kfree(new);
     408             :                 }
     409             :         }
     410             : out:
     411             :         return err;
     412             : }
     413             : 
     414             : /*
     415             :  * Common setup code for both startup command line and mconsole initialization.
     416             :  * @lines contains the array (of size @num) to modify;
     417             :  * @init is the setup string;
     418             :  * @error_out is an error string in the case of failure;
     419             :  */
     420             : 
     421           0 : int line_setup(char **conf, unsigned int num, char **def,
     422             :                char *init, char *name)
     423             : {
     424             :         char *error;
     425             : 
     426           0 :         if (*init == '=') {
     427             :                 /*
     428             :                  * We said con=/ssl= instead of con#=, so we are configuring all
     429             :                  * consoles at once.
     430             :                  */
     431           0 :                 *def = init + 1;
     432             :         } else {
     433             :                 char *end;
     434           0 :                 unsigned n = simple_strtoul(init, &end, 0);
     435             : 
     436           0 :                 if (*end != '=') {
     437             :                         error = "Couldn't parse device number";
     438           0 :                         goto out;
     439             :                 }
     440           0 :                 if (n >= num) {
     441             :                         error = "Device number out of range";
     442             :                         goto out;
     443             :                 }
     444           0 :                 conf[n] = end + 1;
     445             :         }
     446             :         return 0;
     447             : 
     448             : out:
     449           0 :         printk(KERN_ERR "Failed to set up %s with "
     450             :                "configuration string \"%s\" : %s\n", name, init, error);
     451           0 :         return -EINVAL;
     452             : }
     453             : 
     454           0 : int line_config(struct line *lines, unsigned int num, char *str,
     455             :                 const struct chan_opts *opts, char **error_out)
     456             : {
     457             :         char *end;
     458             :         int n;
     459             : 
     460           0 :         if (*str == '=') {
     461           0 :                 *error_out = "Can't configure all devices from mconsole";
     462           0 :                 return -EINVAL;
     463             :         }
     464             : 
     465           0 :         n = simple_strtoul(str, &end, 0);
     466           0 :         if (*end++ != '=') {
     467           0 :                 *error_out = "Couldn't parse device number";
     468           0 :                 return -EINVAL;
     469             :         }
     470           0 :         if (n >= num) {
     471           0 :                 *error_out = "Device number out of range";
     472           0 :                 return -EINVAL;
     473             :         }
     474             : 
     475           0 :         return setup_one_line(lines, n, end, opts, error_out);
     476             : }
     477             : 
     478           0 : int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
     479             :                     int size, char **error_out)
     480             : {
     481             :         struct line *line;
     482             :         char *end;
     483           0 :         int dev, n = 0;
     484             : 
     485           0 :         dev = simple_strtoul(name, &end, 0);
     486           0 :         if ((*end != '\0') || (end == name)) {
     487           0 :                 *error_out = "line_get_config failed to parse device number";
     488           0 :                 return 0;
     489             :         }
     490             : 
     491           0 :         if ((dev < 0) || (dev >= num)) {
     492           0 :                 *error_out = "device number out of range";
     493           0 :                 return 0;
     494             :         }
     495             : 
     496           0 :         line = &lines[dev];
     497             : 
     498           0 :         if (!line->valid)
     499           0 :                 CONFIG_CHUNK(str, size, n, "none", 1);
     500             :         else {
     501           0 :                 struct tty_struct *tty = tty_port_tty_get(&line->port);
     502           0 :                 if (tty == NULL) {
     503           0 :                         CONFIG_CHUNK(str, size, n, line->init_str, 1);
     504             :                 } else {
     505           0 :                         n = chan_config_string(line, str, size, error_out);
     506           0 :                         tty_kref_put(tty);
     507             :                 }
     508             :         }
     509             : 
     510             :         return n;
     511             : }
     512             : 
     513           0 : int line_id(char **str, int *start_out, int *end_out)
     514             : {
     515             :         char *end;
     516             :         int n;
     517             : 
     518           0 :         n = simple_strtoul(*str, &end, 0);
     519           0 :         if ((*end != '\0') || (end == *str))
     520             :                 return -1;
     521             : 
     522           0 :         *str = end;
     523           0 :         *start_out = n;
     524           0 :         *end_out = n;
     525           0 :         return n;
     526             : }
     527             : 
     528           0 : int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
     529             : {
     530           0 :         if (n >= num) {
     531           0 :                 *error_out = "Device number out of range";
     532           0 :                 return -EINVAL;
     533             :         }
     534           0 :         return setup_one_line(lines, n, "none", NULL, error_out);
     535             : }
     536             : 
     537           1 : int register_lines(struct line_driver *line_driver,
     538             :                    const struct tty_operations *ops,
     539             :                    struct line *lines, int nlines)
     540             : {
     541             :         struct tty_driver *driver;
     542             :         int err;
     543             :         int i;
     544             : 
     545           1 :         driver = tty_alloc_driver(nlines, TTY_DRIVER_REAL_RAW |
     546             :                         TTY_DRIVER_DYNAMIC_DEV);
     547           1 :         if (IS_ERR(driver))
     548           0 :                 return PTR_ERR(driver);
     549             : 
     550           1 :         driver->driver_name = line_driver->name;
     551           1 :         driver->name = line_driver->device_name;
     552           1 :         driver->major = line_driver->major;
     553           1 :         driver->minor_start = line_driver->minor_start;
     554           1 :         driver->type = line_driver->type;
     555           1 :         driver->subtype = line_driver->subtype;
     556           1 :         driver->init_termios = tty_std_termios;
     557             : 
     558          17 :         for (i = 0; i < nlines; i++) {
     559          16 :                 tty_port_init(&lines[i].port);
     560          16 :                 lines[i].port.ops = &line_port_ops;
     561          16 :                 spin_lock_init(&lines[i].lock);
     562          16 :                 lines[i].driver = line_driver;
     563          32 :                 INIT_LIST_HEAD(&lines[i].chan_list);
     564             :         }
     565           2 :         tty_set_operations(driver, ops);
     566             : 
     567           1 :         err = tty_register_driver(driver);
     568           1 :         if (err) {
     569           0 :                 printk(KERN_ERR "register_lines : can't register %s driver\n",
     570             :                        line_driver->name);
     571           0 :                 tty_driver_kref_put(driver);
     572           0 :                 for (i = 0; i < nlines; i++)
     573           0 :                         tty_port_destroy(&lines[i].port);
     574             :                 return err;
     575             :         }
     576             : 
     577           1 :         line_driver->driver = driver;
     578           1 :         mconsole_register_dev(&line_driver->mc);
     579           1 :         return 0;
     580             : }
     581             : 
     582             : static DEFINE_SPINLOCK(winch_handler_lock);
     583             : static LIST_HEAD(winch_handlers);
     584             : 
     585             : struct winch {
     586             :         struct list_head list;
     587             :         int fd;
     588             :         int tty_fd;
     589             :         int pid;
     590             :         struct tty_port *port;
     591             :         unsigned long stack;
     592             :         struct work_struct work;
     593             : };
     594             : 
     595           0 : static void __free_winch(struct work_struct *work)
     596             : {
     597           0 :         struct winch *winch = container_of(work, struct winch, work);
     598           0 :         um_free_irq(WINCH_IRQ, winch);
     599             : 
     600           0 :         if (winch->pid != -1)
     601           0 :                 os_kill_process(winch->pid, 1);
     602           0 :         if (winch->stack != 0)
     603           0 :                 free_stack(winch->stack, 0);
     604           0 :         kfree(winch);
     605           0 : }
     606             : 
     607           0 : static void free_winch(struct winch *winch)
     608             : {
     609           0 :         int fd = winch->fd;
     610           0 :         winch->fd = -1;
     611           0 :         if (fd != -1)
     612           0 :                 os_close_file(fd);
     613           0 :         __free_winch(&winch->work);
     614           0 : }
     615             : 
     616           0 : static irqreturn_t winch_interrupt(int irq, void *data)
     617             : {
     618           0 :         struct winch *winch = data;
     619             :         struct tty_struct *tty;
     620             :         struct line *line;
     621           0 :         int fd = winch->fd;
     622             :         int err;
     623             :         char c;
     624             :         struct pid *pgrp;
     625             : 
     626           0 :         if (fd != -1) {
     627           0 :                 err = generic_read(fd, &c, NULL);
     628           0 :                 if (err < 0) {
     629           0 :                         if (err != -EAGAIN) {
     630           0 :                                 winch->fd = -1;
     631           0 :                                 list_del(&winch->list);
     632           0 :                                 os_close_file(fd);
     633           0 :                                 printk(KERN_ERR "winch_interrupt : "
     634             :                                        "read failed, errno = %d\n", -err);
     635           0 :                                 printk(KERN_ERR "fd %d is losing SIGWINCH "
     636             :                                        "support\n", winch->tty_fd);
     637           0 :                                 INIT_WORK(&winch->work, __free_winch);
     638           0 :                                 schedule_work(&winch->work);
     639           0 :                                 return IRQ_HANDLED;
     640             :                         }
     641             :                         goto out;
     642             :                 }
     643             :         }
     644           0 :         tty = tty_port_tty_get(winch->port);
     645           0 :         if (tty != NULL) {
     646           0 :                 line = tty->driver_data;
     647           0 :                 if (line != NULL) {
     648           0 :                         chan_window_size(line, &tty->winsize.ws_row,
     649             :                                          &tty->winsize.ws_col);
     650           0 :                         pgrp = tty_get_pgrp(tty);
     651           0 :                         if (pgrp)
     652           0 :                                 kill_pgrp(pgrp, SIGWINCH, 1);
     653           0 :                         put_pid(pgrp);
     654             :                 }
     655           0 :                 tty_kref_put(tty);
     656             :         }
     657             :  out:
     658             :         return IRQ_HANDLED;
     659             : }
     660             : 
     661           0 : void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port,
     662             :                         unsigned long stack)
     663             : {
     664             :         struct winch *winch;
     665             : 
     666           0 :         winch = kmalloc(sizeof(*winch), GFP_KERNEL);
     667           0 :         if (winch == NULL) {
     668           0 :                 printk(KERN_ERR "register_winch_irq - kmalloc failed\n");
     669           0 :                 goto cleanup;
     670             :         }
     671             : 
     672           0 :         *winch = ((struct winch) { .list        = LIST_HEAD_INIT(winch->list),
     673             :                                    .fd          = fd,
     674             :                                    .tty_fd      = tty_fd,
     675             :                                    .pid         = pid,
     676             :                                    .port        = port,
     677             :                                    .stack       = stack });
     678             : 
     679           0 :         if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
     680             :                            IRQF_SHARED, "winch", winch) < 0) {
     681           0 :                 printk(KERN_ERR "register_winch_irq - failed to register "
     682             :                        "IRQ\n");
     683             :                 goto out_free;
     684             :         }
     685             : 
     686           0 :         spin_lock(&winch_handler_lock);
     687           0 :         list_add(&winch->list, &winch_handlers);
     688             :         spin_unlock(&winch_handler_lock);
     689             : 
     690             :         return;
     691             : 
     692             :  out_free:
     693           0 :         kfree(winch);
     694             :  cleanup:
     695           0 :         os_kill_process(pid, 1);
     696           0 :         os_close_file(fd);
     697           0 :         if (stack != 0)
     698           0 :                 free_stack(stack, 0);
     699             : }
     700             : 
     701           0 : static void unregister_winch(struct tty_struct *tty)
     702             : {
     703             :         struct list_head *ele, *next;
     704             :         struct winch *winch;
     705             :         struct tty_struct *wtty;
     706             : 
     707           0 :         spin_lock(&winch_handler_lock);
     708             : 
     709           0 :         list_for_each_safe(ele, next, &winch_handlers) {
     710           0 :                 winch = list_entry(ele, struct winch, list);
     711           0 :                 wtty = tty_port_tty_get(winch->port);
     712           0 :                 if (wtty == tty) {
     713           0 :                         list_del(&winch->list);
     714           0 :                         spin_unlock(&winch_handler_lock);
     715           0 :                         free_winch(winch);
     716           0 :                         break;
     717             :                 }
     718           0 :                 tty_kref_put(wtty);
     719             :         }
     720           0 :         spin_unlock(&winch_handler_lock);
     721           0 : }
     722             : 
     723           1 : static void winch_cleanup(void)
     724             : {
     725             :         struct winch *winch;
     726             : 
     727             :         spin_lock(&winch_handler_lock);
     728           1 :         while ((winch = list_first_entry_or_null(&winch_handlers,
     729             :                                                  struct winch, list))) {
     730           0 :                 list_del(&winch->list);
     731           0 :                 spin_unlock(&winch_handler_lock);
     732             : 
     733           0 :                 free_winch(winch);
     734             : 
     735             :                 spin_lock(&winch_handler_lock);
     736             :         }
     737             : 
     738           1 :         spin_unlock(&winch_handler_lock);
     739           1 : }
     740             : __uml_exitcall(winch_cleanup);
     741             : 
     742           1 : char *add_xterm_umid(char *base)
     743             : {
     744             :         char *umid, *title;
     745             :         int len;
     746             : 
     747           1 :         umid = get_umid();
     748           1 :         if (*umid == '\0')
     749             :                 return base;
     750             : 
     751           1 :         len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
     752           2 :         title = kmalloc(len, GFP_KERNEL);
     753           1 :         if (title == NULL) {
     754           0 :                 printk(KERN_ERR "Failed to allocate buffer for xterm title\n");
     755           0 :                 return base;
     756             :         }
     757             : 
     758           1 :         snprintf(title, len, "%s (%s)", base, umid);
     759           1 :         return title;
     760             : }

Generated by: LCOV version 1.14