<commit_before>/************************************************************************************************
 * Author : <NAME>
 * 
 * This file is part of 'serial communication manager' library.
 * Copyright (C) <2014-2016>  <<NAME>>
 *
 * This 'serial communication manager' is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The 'serial communication manager' is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 * A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with 'serial communication manager'.  If not, see <http://www.gnu.org/licenses/>.
 ************************************************************************************************/

/* 
 * Virtual multi-port serial adaptor :
 *
 * This driver implements a virtual multiport serial adaptor in such a way that the virtual adaptor 
 * can have from 0 to N number of virtual serial ports (tty devices). The virtual tty devices created 
 * by this adaptor are used in exactly the same way using termios and Linux/Posix APIs as the real tty 
 * devices.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/device.h>

/* Module information */
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "<NAME>"
#define DRIVER_DESC "Serial port null modem emulation driver (kernel mode)"

/* 
 * Default number of virtual tty ports this driver is going to support.
 * TTY devices are created on demand. Users can override this value at module load time for example 
 * to support 5000 virtual devices :
 * insmod ./tty2comKm.ko max_num_vtty_dev=5000
 */
#define VTTY_DEV_MAX 128

/* Experimental range (major number of devices) */
#define SCM_VTTY_MAJOR 240

/* Pin out configurations definitions */
#define SCM_CON_CTS    0x0001
#define SCM_CON_DCD    0x0002
#define SCM_CON_DSR    0x0004
#define SCM_CON_RI     0x0008

/* Modem control register definitions */
#define SCM_MCR_DTR    0x0001
#define SCM_MCR_RTS    0x0002
#define SCM_MCR_LOOP   0x0004

/* Modem status register definitions */
#define SCM_MSR_CTS    0x0008
#define SCM_MSR_DCD    0x0010
#define SCM_MSR_RI     0x0020
#define SCM_MSR_DSR    0x0040

/* UART frame structure definitions */
#define SCM_CRTSCTS       0x0001
#define SCM_XON           0x0002
#define SCM_NONE          0X0004
#define SCM_DATA_5        0X0008
#define SCM_DATA_6        0X0010
#define SCM_DATA_7        0X0020
#define SCM_DATA_8        0X0040
#define SCM_PARITY_NONE   0x0080
#define SCM_PARITY_ODD    0x0100
#define SCM_PARITY_EVEN   0x0200
#define SCM_PARITY_MARK   0x0400
#define SCM_PARITY_SPACE  0x0800
#define SCM_STOP_1        0x1000
#define SCM_STOP_2        0x2000

/* Represent a virtual tty device in this virtual adaptor. The peer_index will contain own 
 * index if this device is loop back configured device (peer == own). */
struct vtty_dev {
    int own_index;
    int peer_index;
    int msr_reg; // shadow modem status register
    int mcr_reg; // shadow modem control register
    int rts_mappings;
    int dtr_mappings;
    int set_dtr_atopen;
    struct mutex lock;
    int is_break_on;
    int baud;
    int uart_frame;
    struct tty_struct *own_tty;
    struct tty_struct *peer_tty;
    struct serial_struct serial;
    struct async_icount icount;
    struct device *device;
};

struct vtty_info {
    int index;
    struct vtty_dev *vttydev;
};

static int scmtty_open(struct tty_struct *tty, struct file *filp);
static int scmtty_write(struct tty_struct *tty, const unsigned char *buf, int count);
static int scmtty_put_char(struct tty_struct *tty, unsigned char ch);
static int scmtty_break_ctl(struct tty_struct *tty, int state);
static int scmtty_write_room(struct tty_struct *tty);
static int scmtty_chars_in_buffer(struct tty_struct *tty);
static int scmtty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
static int scmtty_tiocmget(struct tty_struct *tty);
static int scmtty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
static int scmtty_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount);

static void scmtty_set_termios(struct tty_struct *tty, struct ktermios *old);
static void scmtty_throttle(struct tty_struct *tty);
static void scmtty_unthrottle(struct tty_struct *tty);
static void scmtty_stop(struct tty_struct *tty);
static void scmtty_start(struct tty_struct *tty);
static void scmtty_hangup(struct tty_struct *tty);
static void scmtty_flush_chars(struct tty_struct *tty);
static void scmtty_flush_buffer(struct tty_struct *tty);
static void scmtty_wait_until_sent(struct tty_struct *tty, int timeout);
static void scmtty_send_xchar(struct tty_struct *tty, char ch);
static void scmtty_close(struct tty_struct *tty, struct file *filp);

static int extract_mapping(char data[], int x);
static int update_modem_lines(struct tty_struct *tty, unsigned int set, unsigned int clear);
static int get_serial_info(struct tty_struct *tty, unsigned long arg);
static int wait_msr_change(struct tty_struct *tty, unsigned long mask);
static int check_msr_delta(struct vtty_dev *local_vttydev, unsigned long mask, struct async_icount *prev);

static ssize_t evt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int scmtty_vadapt_proc_open(struct inode *inode, struct  file *file);
static int scmtty_vadapt_proc_close(struct inode *inode, struct file *file);
static ssize_t scmtty_vadapt_proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos);
static ssize_t scmtty_vadapt_proc_write(struct file *file, const char __user *buf, size_t length, loff_t * ppos);

static void scm_port_dtr_rts(struct tty_port *port, int raise);
static int scm_port_carrier_raised(struct tty_port *port);
static void scm_port_shutdown(struct tty_port *port);
static int scm_port_activate(struct tty_port *port, struct tty_struct *tty);
static void scm_port_destruct(struct tty_port *port);

/* These values may be overriden if module is loaded with parameters */
static ushort max_num_vtty_dev = VTTY_DEV_MAX;
static ushort init_num_nm_pair = 0;
static ushort init_num_lb_dev = 0;

/* Describes this driver kernel module */
static struct tty_driver *scmtty_driver;

/* Used when creating or destroying virtual tty devices */
static DEFINE_SPINLOCK(adaptlock);      // atomically create/destroy tty devices
struct vtty_info *index_manager = NULL;   //  keep track of indexes in use currently

/* Per device sysfs entries to emulate frame, parity and overrun error events during data reception */
static DEVICE_ATTR(evt, 0666, NULL, evt_store);

static struct attribute *scmvtty_error_events_attrs[] = {
        &dev_attr_evt.attr,
        NULL,
};

static const struct attribute_group scmvtty_error_events_attr_group = {
        .name = "scmvtty_errevt",
        .attrs = scmvtty_error_events_attrs,
};

static int last_lbdev_idx  = -1;
static int last_nmdev1_idx = -1;
static int last_nmdev2_idx = -1;

/*
 * Notifies tty layer that a framing/parity/overrun error has happend while receiving data on serial port. 
 * The serial port on which the given error/event is to be emulated must have been opened before causing 
 * error event. In the example given below tty2com0 port will indicate to tty layer that it received 
 * corrupted data.
 *
 * The -7 is taken as corrupted character in this driver. For emulation purpose 0 can not be taken as corrupted
 * charcter because parity and break both wil have same sequence (\377 \0 \0) and therefore application may not
 * be able to differentiate.
 * 
 * 1. Emulate framing error:
 * $echo "1" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 2. Emulate parity error:
 * $echo "2" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 3. Emulate overrun error:
 * $echo "3" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 4. Emulate ring indicator (set RI signal):
 * $echo "4" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 5. Emulate ring indicator (un-set RI signal):
 * $echo "5" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * A "framing error" occurs when the designated "start" and "stop" bits are not found. A Parity Error occurs
 * when the parity of the number of 1 bits disagrees with that specified by the parity bit. A "break condition"
 * occurs when the receiver input is at the "space" (logic low, i.e., '0') level for longer than some duration
 * of time, typically, for more than a character time. This is not necessarily an error, but appears to the
 * receiver as a character of all zero bits with a framing error.
 *
 * @dev: device associated with given sysfs entry
 * @attr: sysfs attribute corresponding to this function
 * @buf: error event passed from user space to kernel via this sysfs attribute
 * @count: number of characters in buf
 * 
 * @return number of bytes consumed from buf on success or negative error code on error
 */
static ssize_t evt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    struct vtty_dev *local_vttydev = NULL;
    struct tty_struct *tty_to_write = NULL;

    if(!buf || (count <= 0))
        return -EINVAL;

    local_vttydev = (struct vtty_dev *) dev_get_drvdata(dev);
    tty_to_write = local_vttydev->own_tty;

    /* ensure required structure has been initialized and port has been opened. */
    if((tty_to_write == NULL) || (tty_to_write->port == NULL) || (tty_to_write->port->count <= 0))
        return -EIO;

    mutex_lock(&local_vttydev->lock);

    switch(buf[0]) {
    case '1' : 
        tty_insert_flip_char(tty_to_write->port, -7, TTY_FRAME);
        local_vttydev->icount.frame++;
        break;
    case '2' :
        tty_insert_flip_char(tty_to_write->port, -7, TTY_PARITY);
        local_vttydev->icount.parity++;
        break;
    case '3' :
        tty_insert_flip_char(tty_to_write->port, -7, TTY_OVERRUN);
        local_vttydev->icount.overrun++;
        break;
    case '4' :
        local_vttydev->msr_reg |= SCM_MSR_RI;
        local_vttydev->icount.rng++;
        break;
    case '5' :
        local_vttydev->msr_reg &= ~SCM_MSR_RI;
        local_vttydev->icount.rng++;
        break;
    default :
        mutex_unlock(&local_vttydev->lock);
        return -EINVAL;
    }
    tty_flip_buffer_push(tty_to_write->port);

    mutex_unlock(&local_vttydev->lock);
    return count;
}

/* 
 * Update modem control and modem status registers according to the bit mask(s) provided. The 
 * DTR and RTS values can be set only if the current handshaking state of the tty device allows 
 * direct control of the modem control lines. Update honours pin mappings.
 *
 * Caller holds the lock associated with the given tty's virtual tty info.
 * 
 * @tty: tty device whose modem control register is to be updated with given value(s)
 * @set: bit mask of signals which should be asserted
 * @clear: bit mask of signals which should be de-asserted
 * 
 * @return 0 on success otherwise negative error code on failure
 */
static int update_modem_lines(struct tty_struct *tty, unsigned int set, unsigned int clear)
{
    int ctsint = 0;
    int dcdint = 0;
    int dsrint = 0;
    int rngint = 0;
    int rts_mappings = 0;
    int dtr_mappings = 0;
    unsigned int mcr_ctrl_reg = 0;
    unsigned int msr_state_reg = 0;
    struct async_icount *evicount;
    struct vtty_dev *local_vttydev = index_manager[tty->index].vttydev;
    struct vtty_dev *remote_vttydev = NULL;
<commit_msg>add error checking while emulating parity in tty2comKm<commit_after>/************************************************************************************************
 * Author : <NAME>
 * 
 * This file is part of 'serial communication manager' library.
 * Copyright (C) <2014-2016>  <<NAME>>
 *
 * This 'serial communication manager' is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The 'serial communication manager' is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 * A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with 'serial communication manager'.  If not, see <http://www.gnu.org/licenses/>.
 ************************************************************************************************/

/* 
 * Virtual multi-port serial adaptor :
 *
 * This driver implements a virtual multiport serial adaptor in such a way that the virtual adaptor 
 * can have from 0 to N number of virtual serial ports (tty devices). The virtual tty devices created 
 * by this adaptor are used in exactly the same way using termios and Linux/Posix APIs as the real tty 
 * devices.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/device.h>

/* Module information */
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "<NAME>"
#define DRIVER_DESC "Serial port null modem emulation driver (kernel mode)"

/* 
 * Default number of virtual tty ports this driver is going to support.
 * TTY devices are created on demand. Users can override this value at module load time for example 
 * to support 5000 virtual devices :
 * insmod ./tty2comKm.ko max_num_vtty_dev=5000
 */
#define VTTY_DEV_MAX 128

/* Experimental range (major number of devices) */
#define SCM_VTTY_MAJOR 240

/* Pin out configurations definitions */
#define SCM_CON_CTS    0x0001
#define SCM_CON_DCD    0x0002
#define SCM_CON_DSR    0x0004
#define SCM_CON_RI     0x0008

/* Modem control register definitions */
#define SCM_MCR_DTR    0x0001
#define SCM_MCR_RTS    0x0002
#define SCM_MCR_LOOP   0x0004

/* Modem status register definitions */
#define SCM_MSR_CTS    0x0008
#define SCM_MSR_DCD    0x0010
#define SCM_MSR_RI     0x0020
#define SCM_MSR_DSR    0x0040

/* UART frame structure definitions */
#define SCM_CRTSCTS       0x0001
#define SCM_XON           0x0002
#define SCM_NONE          0X0004
#define SCM_DATA_5        0X0008
#define SCM_DATA_6        0X0010
#define SCM_DATA_7        0X0020
#define SCM_DATA_8        0X0040
#define SCM_PARITY_NONE   0x0080
#define SCM_PARITY_ODD    0x0100
#define SCM_PARITY_EVEN   0x0200
#define SCM_PARITY_MARK   0x0400
#define SCM_PARITY_SPACE  0x0800
#define SCM_STOP_1        0x1000
#define SCM_STOP_2        0x2000

/* Represent a virtual tty device in this virtual adaptor. The peer_index will contain own 
 * index if this device is loop back configured device (peer == own). */
struct vtty_dev {
    int own_index;
    int peer_index;
    int msr_reg; // shadow modem status register
    int mcr_reg; // shadow modem control register
    int rts_mappings;
    int dtr_mappings;
    int set_dtr_atopen;
    struct mutex lock;
    int is_break_on;
    int baud;
    int uart_frame;
    struct tty_struct *own_tty;
    struct tty_struct *peer_tty;
    struct serial_struct serial;
    struct async_icount icount;
    struct device *device;
};

struct vtty_info {
    int index;
    struct vtty_dev *vttydev;
};

static int scmtty_open(struct tty_struct *tty, struct file *filp);
static int scmtty_write(struct tty_struct *tty, const unsigned char *buf, int count);
static int scmtty_put_char(struct tty_struct *tty, unsigned char ch);
static int scmtty_break_ctl(struct tty_struct *tty, int state);
static int scmtty_write_room(struct tty_struct *tty);
static int scmtty_chars_in_buffer(struct tty_struct *tty);
static int scmtty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
static int scmtty_tiocmget(struct tty_struct *tty);
static int scmtty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
static int scmtty_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount);

static void scmtty_set_termios(struct tty_struct *tty, struct ktermios *old);
static void scmtty_throttle(struct tty_struct *tty);
static void scmtty_unthrottle(struct tty_struct *tty);
static void scmtty_stop(struct tty_struct *tty);
static void scmtty_start(struct tty_struct *tty);
static void scmtty_hangup(struct tty_struct *tty);
static void scmtty_flush_chars(struct tty_struct *tty);
static void scmtty_flush_buffer(struct tty_struct *tty);
static void scmtty_wait_until_sent(struct tty_struct *tty, int timeout);
static void scmtty_send_xchar(struct tty_struct *tty, char ch);
static void scmtty_close(struct tty_struct *tty, struct file *filp);

static int extract_mapping(char data[], int x);
static int update_modem_lines(struct tty_struct *tty, unsigned int set, unsigned int clear);
static int get_serial_info(struct tty_struct *tty, unsigned long arg);
static int wait_msr_change(struct tty_struct *tty, unsigned long mask);
static int check_msr_delta(struct vtty_dev *local_vttydev, unsigned long mask, struct async_icount *prev);

static ssize_t evt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static int scmtty_vadapt_proc_open(struct inode *inode, struct  file *file);
static int scmtty_vadapt_proc_close(struct inode *inode, struct file *file);
static ssize_t scmtty_vadapt_proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos);
static ssize_t scmtty_vadapt_proc_write(struct file *file, const char __user *buf, size_t length, loff_t * ppos);

static void scm_port_dtr_rts(struct tty_port *port, int raise);
static int scm_port_carrier_raised(struct tty_port *port);
static void scm_port_shutdown(struct tty_port *port);
static int scm_port_activate(struct tty_port *port, struct tty_struct *tty);
static void scm_port_destruct(struct tty_port *port);

/* These values may be overriden if module is loaded with parameters */
static ushort max_num_vtty_dev = VTTY_DEV_MAX;
static ushort init_num_nm_pair = 0;
static ushort init_num_lb_dev = 0;

/* Describes this driver kernel module */
static struct tty_driver *scmtty_driver;

/* Used when creating or destroying virtual tty devices */
static DEFINE_SPINLOCK(adaptlock);      // atomically create/destroy tty devices
struct vtty_info *index_manager = NULL;   //  keep track of indexes in use currently

/* Per device sysfs entries to emulate frame, parity and overrun error events during data reception */
static DEVICE_ATTR(evt, 0666, NULL, evt_store);

static struct attribute *scmvtty_error_events_attrs[] = {
        &dev_attr_evt.attr,
        NULL,
};

static const struct attribute_group scmvtty_error_events_attr_group = {
        .name = "scmvtty_errevt",
        .attrs = scmvtty_error_events_attrs,
};

static int last_lbdev_idx  = -1;
static int last_nmdev1_idx = -1;
static int last_nmdev2_idx = -1;

/*
 * Notifies tty layer that a framing/parity/overrun error has happend while receiving data on serial port. 
 * The serial port on which the given error/event is to be emulated must have been opened before causing 
 * error event. In the example given below tty2com0 port will indicate to tty layer that it received 
 * corrupted data.
 *
 * The -7 is taken as corrupted character in this driver. For emulation purpose 0 can not be taken as corrupted
 * charcter because parity and break both wil have same sequence (\377 \0 \0) and therefore application may not
 * be able to differentiate.
 * 
 * 1. Emulate framing error:
 * $echo "1" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 2. Emulate parity error:
 * $echo "2" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 3. Emulate overrun error:
 * $echo "3" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 4. Emulate ring indicator (set RI signal):
 * $echo "4" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * 5. Emulate ring indicator (un-set RI signal):
 * $echo "5" > /sys/devices/virtual/tty/tty2com0/scmvtty_errevt/evt
 * 
 * A "framing error" occurs when the designated "start" and "stop" bits are not found. A Parity Error occurs
 * when the parity of the number of 1 bits disagrees with that specified by the parity bit. A "break condition"
 * occurs when the receiver input is at the "space" (logic low, i.e., '0') level for longer than some duration
 * of time, typically, for more than a character time. This is not necessarily an error, but appears to the
 * receiver as a character of all zero bits with a framing error.
 *
 * @dev: device associated with given sysfs entry
 * @attr: sysfs attribute corresponding to this function
 * @buf: error event passed from user space to kernel via this sysfs attribute
 * @count: number of characters in buf
 * 
 * @return number of bytes consumed from buf on success or negative error code on error
 */
static ssize_t evt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    int ret = 0;
    struct vtty_dev *local_vttydev = NULL;
    struct tty_struct *tty_to_write = NULL;

    if(!buf || (count <= 0))
        return -EINVAL;

    local_vttydev = (struct vtty_dev *) dev_get_drvdata(dev);
    tty_to_write = local_vttydev->own_tty;

    /* ensure required structure has been initialized and port has been opened. */
    if((tty_to_write == NULL) || (tty_to_write->port == NULL) || (tty_to_write->port->count <= 0))
        return -EIO;

    mutex_lock(&local_vttydev->lock);

    switch(buf[0]) {
    case '1' : 
        ret = tty_insert_flip_char(tty_to_write->port, -7, TTY_FRAME);
        if(ret < 0)
            goto fail;
        local_vttydev->icount.frame++;
        break;
    case '2' :
        ret = tty_insert_flip_char(tty_to_write->port, -7, TTY_PARITY);
        if(ret < 0)
            goto fail;
        local_vttydev->icount.parity++;
        break;
    case '3' :
        ret = tty_insert_flip_char(tty_to_write->port, 0, TTY_OVERRUN);
        if(ret < 0)
            goto fail;
        local_vttydev->icount.overrun++;
        break;
    case '4' :
        local_vttydev->msr_reg |= SCM_MSR_RI;
        local_vttydev->icount.rng++;
        break;
    case '5' :
        local_vttydev->msr_reg &= ~SCM_MSR_RI;
        local_vttydev->icount.rng++;
        break;
    default :
        mutex_unlock(&local_vttydev->lock);
        return -EINVAL;
    }
    tty_flip_buffer_push(tty_to_write->port);

    mutex_unlock(&local_vttydev->lock);
    return count;

    fail:
    mutex_unlock(&local_vttydev->lock);
    return ret;
}

/* 
 * Update modem control and modem status registers according to the bit mask(s) provided. The 
 * DTR and RTS values can be set only if the current handshaking state of the tty device allows 
 * direct control of the modem control lines. Update honours pin mappings.
 *
 * Caller holds the lock associated with the given tty's virtual tty info.
 * 
 * @tty: tty device whose modem control register is to be updated with given value(s)
 * @set: bit mask of signals which should be asserted
 * @clear: bit mask of signals which should be de-asserted
 * 
 * @return 0 on success otherwise negative error code on failure
 */
static int update_modem_lines(struct tty_struct *tty, unsigned int set, unsigned int clear)
{
    int ctsint = 0;
    int dcdint = 0;
    int dsrint = 0;
    int rngint = 0;
    int rts_mappings = 0;
    int dtr_mappings = 0;
    unsigned int mcr_ctrl_reg = 0;
    unsigned int msr_state_reg = 0;
    struct async_icount *evicount;
    struct vtty_dev *local_vttydev = index_manager[tty->index].vttydev;
    struct vtty_dev *remote_vttydev = NULL;

{'fraction_non_alphanumeric': 0.09585313350391941, 'fraction_numerical': 0.018074001868323787, 'mean_word_length': 4.09983429991715, 'pattern_counts': {'":': 0, '<': 58, '<?xml version=': 0, '>': 100, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3205080', 'n_tokens_mistral': 8228, 'n_tokens_neox': 7838, 'n_words': 2711}