diff --git a/module/tty0tty.c b/module/tty0tty.c index 841e860..e33d599 100644 --- a/module/tty0tty.c +++ b/module/tty0tty.c @@ -5,7 +5,7 @@ ######################################################################## Copyright (c) : 2013-2019 Luis Claudio GambĂ´a Lopes - + Based in Tiny TTY driver - Copyright (C) 2002-2004 Greg Kroah-Hartman (greg@kroah.com) This program is free software; you can redistribute it and/or modify @@ -69,7 +69,7 @@ MODULE_LICENSE("GPL"); #define MSR_CD 0x20 #define MSR_DSR 0x40 #define MSR_RI 0x80 - + static struct tty_port tport[TTY0TTY_MINORS]; @@ -86,23 +86,65 @@ struct tty0tty_serial { struct serial_struct serial; wait_queue_head_t wait; struct async_icount icount; - }; static struct tty0tty_serial *tty0tty_table[TTY0TTY_MINORS]; /* initially all NULL */ +static struct tty0tty_serial *get_shadow_tty(int index) +{ + struct tty0tty_serial *shadow = NULL; + int shadow_idx = index ^ 1; + + if ((index < TTY0TTY_MINORS) && + (tty0tty_table[shadow_idx] != NULL) && + (tty0tty_table[shadow_idx]->open_count > 0)) { + shadow = tty0tty_table[shadow_idx]; +#ifdef SCULL_DEBUG + printk(KERN_DEBUG "%s - shadow idx: %d\n", __FUNCTION__, shadow_idx); +#endif + } + + return shadow; +} + +static void update_shadow_msr(int index, int msr) +{ + struct tty0tty_serial *shadow; + +#ifdef SCULL_DEBUG + printk(KERN_DEBUG "%s - 0x%02x\n", __FUNCTION__, msr); +#endif + + if ((shadow = get_shadow_tty(index)) != NULL) { + if((shadow->msr & MSR_CTS) != (msr & MSR_CTS)) + shadow->icount.cts++; + + if((shadow->msr & MSR_DSR) != (msr & MSR_DSR)) + shadow->icount.dsr++; + + if((shadow->msr & MSR_CD) != (msr & MSR_CD)) + shadow->icount.dcd++; + + if (msr != shadow->msr) { + shadow->msr = msr; + wake_up_interruptible(&shadow->wait); + } + } +} + static int tty0tty_open(struct tty_struct *tty, struct file *file) { struct tty0tty_serial *tty0tty; - int index; - int msr=0; + struct tty0tty_serial *shadow; + int index; + int msr=0; int mcr=0; #ifdef SCULL_DEBUG printk(KERN_DEBUG "%s - tnt%i \n", __FUNCTION__,tty->index); -#endif - /* initialize the pointer in case something fails */ +#endif + /* initialize the pointer in case something fails */ tty->driver_data = NULL; /* get the serial object associated with this tty pointer */ @@ -118,44 +160,36 @@ static int tty0tty_open(struct tty_struct *tty, struct file *file) tty0tty->open_count = 0; tty0tty_table[index] = tty0tty; - - } - - tport[index].tty=tty; - tty->port = &tport[index]; - - if( (index % 2) == 0) - { - if(tty0tty_table[index+1] != NULL) - if (tty0tty_table[index+1]->open_count > 0) - mcr=tty0tty_table[index+1]->mcr; - } - else - { - if(tty0tty_table[index-1] != NULL) - if (tty0tty_table[index-1]->open_count > 0) - mcr=tty0tty_table[index-1]->mcr; - } - + + } + + tport[index].tty=tty; + tty->port = &tport[index]; + + if ((shadow = get_shadow_tty(index)) != NULL) + mcr = shadow->mcr; + //null modem connection - if( (mcr & MCR_RTS) == MCR_RTS ) - { - msr |= MSR_CTS; - } - - if( (mcr & MCR_DTR) == MCR_DTR ) - { - msr |= MSR_DSR; - msr |= MSR_CD; - } - + if( (mcr & MCR_RTS) == MCR_RTS ) + { + msr |= MSR_CTS; + } + + if( (mcr & MCR_DTR) == MCR_DTR ) + { + msr |= MSR_DSR; + msr |= MSR_CD; + } + tty0tty->msr = msr; tty0tty->mcr = 0; - + memset(&tty0tty->icount, 0, sizeof(tty0tty->icount)); + + init_waitqueue_head(&tty0tty->wait); /* register the tty driver */ - + down(&tty0tty->sem); /* save our structure within the tty structure */ @@ -169,25 +203,14 @@ static int tty0tty_open(struct tty_struct *tty, struct file *file) } static void do_close(struct tty0tty_serial *tty0tty) -{ +{ unsigned int msr=0; - + #ifdef SCULL_DEBUG printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__,tty0tty->tty->index); #endif - if( (tty0tty->tty->index % 2) == 0) - { - if(tty0tty_table[tty0tty->tty->index+1] != NULL) - if (tty0tty_table[tty0tty->tty->index+1]->open_count > 0) - tty0tty_table[tty0tty->tty->index+1]->msr=msr; - } - else - { - if(tty0tty_table[tty0tty->tty->index-1] != NULL) - if (tty0tty_table[tty0tty->tty->index-1]->open_count > 0) - tty0tty_table[tty0tty->tty->index-1]->msr=msr; - } - + update_shadow_msr(tty0tty->tty->index, msr); + down(&tty0tty->sem); if (!tty0tty->open_count) { /* port was never opened */ @@ -197,36 +220,37 @@ static void do_close(struct tty0tty_serial *tty0tty) --tty0tty->open_count; exit: up(&tty0tty->sem); - - - return; + + + return; } static void tty0tty_close(struct tty_struct *tty, struct file *file) { struct tty0tty_serial *tty0tty = tty->driver_data; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif if (tty0tty) do_close(tty0tty); -} +} static int tty0tty_write(struct tty_struct *tty, const unsigned char *buffer, int count) { struct tty0tty_serial *tty0tty = tty->driver_data; + struct tty0tty_serial *shadow; int retval = -EINVAL; - struct tty_struct *ttyx = NULL; + struct tty_struct *ttyx = NULL; #ifdef SCULL_DEBUG int i; printk(KERN_DEBUG "%s -tnt%i [%02i] \n", __FUNCTION__,tty->index, count); for(i=0;isem); @@ -235,47 +259,37 @@ static int tty0tty_write(struct tty_struct *tty, const unsigned char *buffer, in /* port was not opened */ goto exit; - if( (tty0tty->tty->index % 2) == 0) - { - if(tty0tty_table[tty0tty->tty->index+1] != NULL) - if (tty0tty_table[tty0tty->tty->index+1]->open_count > 0) - ttyx=tty0tty_table[tty0tty->tty->index+1]->tty; - } - else - { - if(tty0tty_table[tty0tty->tty->index-1] != NULL) - if (tty0tty_table[tty0tty->tty->index-1]->open_count > 0) - ttyx=tty0tty_table[tty0tty->tty->index-1]->tty; - } + if ((shadow = get_shadow_tty(tty0tty->tty->index)) != NULL) + ttyx = shadow->tty; // tty->low_latency=1; - if(ttyx != NULL) - { - tty_insert_flip_string(ttyx->port, buffer, count); - tty_flip_buffer_push(ttyx->port); - retval=count; - } - + if(ttyx != NULL) + { + tty_insert_flip_string(ttyx->port, buffer, count); + tty_flip_buffer_push(ttyx->port); + retval=count; + } + exit: up(&tty0tty->sem); return retval; } -static int tty0tty_write_room(struct tty_struct *tty) +static int tty0tty_write_room(struct tty_struct *tty) { struct tty0tty_serial *tty0tty = tty->driver_data; int room = -EINVAL; #ifdef SCULL_DEBUG printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__,tty->index); -#endif - +#endif + if (!tty0tty) return -ENODEV; down(&tty0tty->sem); - + if (!tty0tty->open_count) { /* port was not opened */ goto exit; @@ -296,9 +310,9 @@ static int tty0tty_write_room(struct tty_struct *tty) static void tty0tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { unsigned int cflag; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s -tnt%i \n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s -tnt%i \n", __FUNCTION__, tty->index); #endif cflag = tty->termios.c_cflag; @@ -306,7 +320,7 @@ static void tty0tty_set_termios(struct tty_struct *tty, struct ktermios *old_ter /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios.c_iflag) == + (RELEVANT_IFLAG(tty->termios.c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { #ifdef SCULL_DEBUG printk(KERN_DEBUG " - nothing to change...\n"); @@ -332,7 +346,7 @@ static void tty0tty_set_termios(struct tty_struct *tty, struct ktermios *old_ter printk(KERN_DEBUG " - data bits = 8\n"); break; } - + /* determine the parity */ if (cflag & PARENB) if (cflag & PARODD) @@ -353,9 +367,9 @@ static void tty0tty_set_termios(struct tty_struct *tty, struct ktermios *old_ter printk(KERN_DEBUG " - RTS/CTS is enabled\n"); else printk(KERN_DEBUG " - RTS/CTS is disabled\n"); - + /* determine software flow control */ - /* if we are implementing XON/XOFF, set the start and + /* if we are implementing XON/XOFF, set the start and * stop character in the device */ if (I_IXOFF(tty) || I_IXON(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -389,18 +403,18 @@ static int tty0tty_tiocmget(struct tty_struct *tty) unsigned int result = 0; unsigned int msr = tty0tty->msr; unsigned int mcr = tty0tty->mcr; - + result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | /* DTR is set */ - ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | /* RTS is set */ - ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) | /* LOOP is set */ - ((msr & MSR_CTS) ? TIOCM_CTS : 0) | /* CTS is set */ - ((msr & MSR_CD) ? TIOCM_CAR : 0) | /* Carrier detect is set*/ - ((msr & MSR_RI) ? TIOCM_RI : 0) | /* Ring Indicator is set */ - ((msr & MSR_DSR) ? TIOCM_DSR : 0); /* DSR is set */ + ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | /* RTS is set */ + ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) | /* LOOP is set */ + ((msr & MSR_CTS) ? TIOCM_CTS : 0) | /* CTS is set */ + ((msr & MSR_CD) ? TIOCM_CAR : 0) | /* Carrier detect is set*/ + ((msr & MSR_RI) ? TIOCM_RI : 0) | /* Ring Indicator is set */ + ((msr & MSR_DSR) ? TIOCM_DSR : 0); /* DSR is set */ #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i 0x%08X \n", __FUNCTION__, tty->index, result); + printk(KERN_DEBUG "%s - tnt%i 0x%08X \n", __FUNCTION__, tty->index, result); #endif return result; @@ -410,86 +424,66 @@ static int tty0tty_tiocmget(struct tty_struct *tty) -static int tty0tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) +static int tty0tty_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) { struct tty0tty_serial *tty0tty = tty->driver_data; + struct tty0tty_serial *shadow; unsigned int mcr = tty0tty->mcr; unsigned int msr=0; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i set=0x%08X clear=0x%08X \n", __FUNCTION__,tty->index, set ,clear); + printk(KERN_DEBUG "%s - tnt%i set=0x%08X clear=0x%08X \n", __FUNCTION__,tty->index, set ,clear); #endif + if ((shadow = get_shadow_tty(tty0tty->tty->index)) != NULL) + msr = shadow->msr; - if( (tty0tty->tty->index % 2) == 0) - { - if(tty0tty_table[tty0tty->tty->index+1] != NULL) - if (tty0tty_table[tty0tty->tty->index+1]->open_count > 0) - msr=tty0tty_table[tty0tty->tty->index+1]->msr; - } - else - { - if(tty0tty_table[tty0tty->tty->index-1] != NULL) - if (tty0tty_table[tty0tty->tty->index-1]->open_count > 0) - msr=tty0tty_table[tty0tty->tty->index-1]->msr; - } - //null modem connection if (set & TIOCM_RTS) - { - mcr |= MCR_RTS; - msr |= MSR_CTS; - } - + { + mcr |= MCR_RTS; + msr |= MSR_CTS; + } + if (set & TIOCM_DTR) - { - mcr |= MCR_DTR; - msr |= MSR_DSR; - msr |= MSR_CD; - } + { + mcr |= MCR_DTR; + msr |= MSR_DSR; + msr |= MSR_CD; + } if (clear & TIOCM_RTS) - { - mcr &= ~MCR_RTS; - msr &= ~MSR_CTS; - } - + { + mcr &= ~MCR_RTS; + msr &= ~MSR_CTS; + } + if (clear & TIOCM_DTR) - { - mcr &= ~MCR_DTR; - msr &= ~MSR_DSR; - msr &= ~MSR_CD; - } - + { + mcr &= ~MCR_DTR; + msr &= ~MSR_DSR; + msr &= ~MSR_CD; + } + /* set the new MCR value in the device */ tty0tty->mcr = mcr; - - if( (tty0tty->tty->index % 2) == 0) - { - if(tty0tty_table[tty0tty->tty->index+1] != NULL) - if (tty0tty_table[tty0tty->tty->index+1]->open_count > 0) - tty0tty_table[tty0tty->tty->index+1]->msr=msr; - } - else - { - if(tty0tty_table[tty0tty->tty->index-1] != NULL) - if (tty0tty_table[tty0tty->tty->index-1]->open_count > 0) - tty0tty_table[tty0tty->tty->index-1]->msr=msr; - } + + update_shadow_msr(tty0tty->tty->index, msr); + return 0; } -static int tty0tty_ioctl_tiocgserial(struct tty_struct *tty, - unsigned long arg) +static int tty0tty_ioctl_tiocgserial(struct tty_struct *tty, + unsigned long arg) { struct tty0tty_serial *tty0tty = tty->driver_data; struct serial_struct tmp; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i \n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i \n", __FUNCTION__, tty->index); #endif if (!arg) @@ -515,15 +509,15 @@ static int tty0tty_ioctl_tiocgserial(struct tty_struct *tty, return 0; } -static int tty0tty_ioctl_tiocsserial(struct tty_struct *tty, - unsigned long arg) +static int tty0tty_ioctl_tiocsserial(struct tty_struct *tty, + unsigned long arg) { /* struct tty0tty_serial *tty0tty = tty->driver_data; struct serial_struct tmp; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif if (!arg) @@ -547,12 +541,12 @@ static int tty0tty_ioctl_tiocsserial(struct tty_struct *tty, if (copy_to_user((void __user *)arg, &tmp, sizeof(struct serial_struct))) return -EFAULT; return 0; -*/ +*/ return -EFAULT;//TODO } static int tty0tty_ioctl_tiocmiwait(struct tty_struct *tty, - unsigned long arg) + unsigned long arg) { struct tty0tty_serial *tty0tty = tty->driver_data; DECLARE_WAITQUEUE(wait, current); @@ -560,7 +554,7 @@ static int tty0tty_ioctl_tiocmiwait(struct tty_struct *tty, struct async_icount cprev; #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif cprev = tty0tty->icount; while (1) { @@ -588,14 +582,14 @@ static int tty0tty_ioctl_tiocmiwait(struct tty_struct *tty, } static int tty0tty_ioctl_tiocgicount(struct tty_struct *tty, - unsigned long arg) + unsigned long arg) { struct tty0tty_serial *tty0tty = tty->driver_data; struct async_icount cnow = tty0tty->icount; struct serial_icounter_struct icount; - + #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif icount.cts = cnow.cts; @@ -616,21 +610,21 @@ static int tty0tty_ioctl_tiocgicount(struct tty_struct *tty, } static int tty0tty_ioctl_tcgets(struct tty_struct *tty, - unsigned long arg, unsigned int opt) + unsigned long arg, unsigned int opt) { - struct ktermios kterm; + struct ktermios kterm; #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif down_read(&tty->termios_rwsem); kterm = tty->termios; up_read(&tty->termios_rwsem); if(opt){ - if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) + if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) return -EFAULT; } - else{ + else{ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) return -EFAULT; } @@ -640,13 +634,13 @@ static int tty0tty_ioctl_tcgets(struct tty_struct *tty, } static int tty0tty_ioctl_tcsets(struct tty_struct *tty, - unsigned long arg, unsigned int opt) + unsigned long arg, unsigned int opt) { struct ktermios tmp_termios; int retval = tty_check_change(tty); #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); + printk(KERN_DEBUG "%s - tnt%i\n", __FUNCTION__, tty->index); #endif @@ -673,18 +667,17 @@ static int tty0tty_ioctl_tcsets(struct tty_struct *tty, tty_set_termios(tty, &tmp_termios); -return 0; - + return 0; } static int tty0tty_ioctl_tcflsh(struct tty_struct *tty, - unsigned long arg) + unsigned long arg) { struct tty_ldisc *ld = tty->ldisc; int retval = tty_check_change(tty); #ifdef SCULL_DEBUG - printk(KERN_DEBUG "%s - tnt%i 0x%08lX\n", __FUNCTION__,tty->index, arg); + printk(KERN_DEBUG "%s - tnt%i 0x%08lX\n", __FUNCTION__,tty->index, arg); #endif if (retval) @@ -713,7 +706,7 @@ static int tty0tty_ioctl_tcflsh(struct tty_struct *tty, } static int tty0tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { #ifdef SCULL_DEBUG printk(KERN_DEBUG "%s - tnt%i cmd=0x%04X\n", __FUNCTION__, tty->index, cmd); @@ -738,8 +731,8 @@ static int tty0tty_ioctl(struct tty_struct *tty, case TCSETS2: return tty0tty_ioctl_tcsets(tty, arg ,1); #ifdef SCULL_DEBUG - default: - printk(KERN_DEBUG "ioctl 0x%04X Not Implemented!\n",cmd); + default: + printk(KERN_DEBUG "ioctl 0x%04X Not Implemented!\n",cmd); break; #endif } @@ -771,15 +764,13 @@ static struct tty_operations serial_ops = { }; - - static struct tty_driver *tty0tty_tty_driver; static int __init tty0tty_init(void) { int retval; - int i; - + int i; + #ifdef SCULL_DEBUG printk(KERN_DEBUG "%s - \n", __FUNCTION__); #endif @@ -792,30 +783,29 @@ static int __init tty0tty_init(void) tty0tty_tty_driver->owner = THIS_MODULE; tty0tty_tty_driver->driver_name = "tty0tty"; tty0tty_tty_driver->name = "tnt"; - /* no more devfs subsystem */ + /* no more devfs subsystem */ tty0tty_tty_driver->major = TTY0TTY_MAJOR; tty0tty_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; tty0tty_tty_driver->subtype = SERIAL_TYPE_NORMAL; - tty0tty_tty_driver->flags = /*TTY_DRIVER_RESET_TERMIOS |*/ TTY_DRIVER_REAL_RAW ; - /* no more devfs subsystem */ + tty0tty_tty_driver->flags = /*TTY_DRIVER_RESET_TERMIOS |*/ TTY_DRIVER_REAL_RAW ; + /* no more devfs subsystem */ tty0tty_tty_driver->init_termios = tty_std_termios; - tty0tty_tty_driver->init_termios.c_iflag = 0; - tty0tty_tty_driver->init_termios.c_oflag = 0; - tty0tty_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - tty0tty_tty_driver->init_termios.c_lflag = 0; - tty0tty_tty_driver->init_termios.c_ispeed = 38400; - tty0tty_tty_driver->init_termios.c_ospeed = 38400; - + tty0tty_tty_driver->init_termios.c_iflag = 0; + tty0tty_tty_driver->init_termios.c_oflag = 0; + tty0tty_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; + tty0tty_tty_driver->init_termios.c_lflag = 0; + tty0tty_tty_driver->init_termios.c_ispeed = 38400; + tty0tty_tty_driver->init_termios.c_ospeed = 38400; tty_set_operations(tty0tty_tty_driver, &serial_ops); - - for(i=0;i