4040#include <asm/termbits.h>
4141#include <asm/termios.h>
4242#include <asm/ioctls.h>
43+ #include <linux/serial.h>
4344#include <linux/version.h>
4445
4546#include "stack_protector.include"
7071 #define _access_ok (__type , __addr , __size ) access_ok(__type, __addr, __size)
7172#endif
7273
73- #if (LINUX_VERSION_CODE >= KERNEL_VERSION (6 ,4 ,0 ))
74- #define class_create (__owner , __class ) class_create(__class)
75- #endif
76-
7774struct eq3loop_channel_data
7875{
7976 struct circ_buf master2slave_buf ;
@@ -365,7 +362,7 @@ static ssize_t eq3loop_write_master(struct eq3loop_channel_data* channel, struct
365362 {
366363 ret = - EFAULT ;
367364 count_to_end = CIRC_SPACE ( head , channel -> master2slave_buf .tail , BUFSIZE );
368- printk ( KERN_ERR EQ3LOOP_DRIVER_NAME ": eq3loop_write_master() %s: not enought space in the buffers. free space = %zu, required space = %zu" , channel -> name ,count_to_end ,count );
365+ printk ( KERN_ERR EQ3LOOP_DRIVER_NAME ": eq3loop_write_master() %s: not enough space in buffers. free space = %zu, required space = %zu" , channel -> name ,count_to_end ,count );
369366 goto out ;
370367 }
371368 /* ok, space is free, write something */
@@ -401,7 +398,7 @@ static ssize_t eq3loop_write_master(struct eq3loop_channel_data* channel, struct
401398 up (& channel -> sem );
402399 if (ret < 0 )
403400 {
404- printk ( KERN_INFO EQ3LOOP_DRIVER_NAME ": eq3loop_write_master() retrun error:" );
401+ printk ( KERN_INFO EQ3LOOP_DRIVER_NAME ": eq3loop_write_master() return error: %zd" , ret );
405402 }
406403 if ( ret > 0 || CIRC_CNT (channel -> master2slave_buf .head ,channel -> master2slave_buf .tail ,BUFSIZE ) )
407404 {
@@ -512,21 +509,76 @@ static long eq3loop_ioctl_slave(struct eq3loop_channel_data* channel, struct fil
512509 switch (cmd ) {
513510
514511 case TCGETS :
515- if ( _access_ok (VERIFY_READ , (void * )arg , sizeof (struct termios ) ) )
512+ if ( _access_ok (VERIFY_WRITE , (void * )arg , sizeof (struct termios ) ) )
516513 {
517514 ret = copy_to_user ( (void * )arg , & channel -> termios , sizeof (struct termios ) );
518515 } else {
519516 ret = - EFAULT ;
520517 }
521518 break ;
522519 case TCSETS :
523- if ( _access_ok (VERIFY_WRITE , (void * )arg , sizeof (struct termios ) ) )
520+ case TCSETSW :
521+ case TCSETSF :
522+ if ( _access_ok (VERIFY_READ , (void * )arg , sizeof (struct termios ) ) )
524523 {
525524 ret = copy_from_user ( & channel -> termios , (void * )arg , sizeof (struct termios ) );
526525 } else {
527526 ret = - EFAULT ;
528527 }
529528 break ;
529+ #ifdef TCGETS2
530+ case TCGETS2 :
531+ {
532+ struct termios2 t2 ;
533+
534+ memset (& t2 , 0 , sizeof (t2 ));
535+ t2 .c_iflag = channel -> termios .c_iflag ;
536+ t2 .c_oflag = channel -> termios .c_oflag ;
537+ t2 .c_cflag = channel -> termios .c_cflag ;
538+ t2 .c_lflag = channel -> termios .c_lflag ;
539+ t2 .c_line = channel -> termios .c_line ;
540+ memcpy (t2 .c_cc , channel -> termios .c_cc , NCCS );
541+ t2 .c_ispeed = 0 ;
542+ t2 .c_ospeed = 0 ;
543+
544+ if ( _access_ok (VERIFY_WRITE , (void * )arg , sizeof (struct termios2 ) ) )
545+ {
546+ ret = copy_to_user ( (void * )arg , & t2 , sizeof (struct termios2 ) );
547+ } else {
548+ ret = - EFAULT ;
549+ }
550+ break ;
551+ }
552+ #endif
553+ #ifdef TCSETS2
554+ case TCSETS2 :
555+ #ifdef TCSETSW2
556+ case TCSETSW2 :
557+ #endif
558+ #ifdef TCSETSF2
559+ case TCSETSF2 :
560+ #endif
561+ {
562+ struct termios2 t2 ;
563+
564+ if ( _access_ok (VERIFY_READ , (void * )arg , sizeof (struct termios2 ) ) )
565+ {
566+ ret = copy_from_user ( & t2 , (void * )arg , sizeof (struct termios2 ) );
567+ if ( !ret )
568+ {
569+ channel -> termios .c_iflag = t2 .c_iflag ;
570+ channel -> termios .c_oflag = t2 .c_oflag ;
571+ channel -> termios .c_cflag = t2 .c_cflag ;
572+ channel -> termios .c_lflag = t2 .c_lflag ;
573+ channel -> termios .c_line = t2 .c_line ;
574+ memcpy (channel -> termios .c_cc , t2 .c_cc , NCCS );
575+ }
576+ } else {
577+ ret = - EFAULT ;
578+ }
579+ break ;
580+ }
581+ #endif
530582 case TIOCINQ :
531583 temp = CIRC_CNT ( channel -> master2slave_buf .head , channel -> master2slave_buf .tail , BUFSIZE );
532584 ret = __put_user ( temp , (int * )arg );
@@ -546,10 +598,20 @@ static long eq3loop_ioctl_slave(struct eq3loop_channel_data* channel, struct fil
546598 case TIOCMSET :
547599 break ;
548600 case TIOCSERGETLSR :
549- ret = - ENOIOCTLCMD ;
601+ temp = TIOCSER_TEMT ;
602+ ret = __put_user ( temp , (int * )arg );
550603 break ;
551604 case TIOCGICOUNT :
552- ret = - ENOIOCTLCMD ;
605+ {
606+ struct serial_icounter_struct icount ;
607+ memset (& icount , 0 , sizeof (icount ));
608+ if ( _access_ok (VERIFY_WRITE , (void * )arg , sizeof (struct serial_icounter_struct ) ) )
609+ {
610+ ret = copy_to_user ( (void * )arg , & icount , sizeof (struct serial_icounter_struct ) );
611+ } else {
612+ ret = - EFAULT ;
613+ }
614+ }
553615 break ;
554616 default :
555617 ret = - ENOTTY ;
@@ -559,7 +621,6 @@ static long eq3loop_ioctl_slave(struct eq3loop_channel_data* channel, struct fil
559621 if ( ret == - ENOTTY )
560622 {
561623 printk ( KERN_NOTICE EQ3LOOP_DRIVER_NAME ": eq3loop_ioctl_slave() %s: unhandled ioctl 0x%04X\n" , channel -> name , cmd );
562- ret = - ENOIOCTLCMD ;
563624 }
564625 return ret ;
565626}
@@ -960,7 +1021,14 @@ static int __init eq3loop_init(void)
9601021 printk (KERN_ERR EQ3LOOP_DRIVER_NAME ": Unable to add driver\n" );
9611022 goto out_unregister_chrdev_region ;
9621023 }
1024+ /* Linux changed signature of class_create in 6.4+
1025+ * see: https://lore.kernel.org/all/20230324100132.1633647-1-gregkh@linuxfoundation.org/
1026+ */
1027+ #if LINUX_VERSION_CODE < KERNEL_VERSION (6 , 4 , 0 )
9631028 control_data -> class = class_create (THIS_MODULE , EQ3LOOP_DRIVER_NAME );
1029+ #else
1030+ control_data -> class = class_create (EQ3LOOP_DRIVER_NAME );
1031+ #endif
9641032 if (IS_ERR (control_data -> class )){
9651033 ret = - EIO ;
9661034 printk (KERN_ERR EQ3LOOP_DRIVER_NAME ": Unable to register driver class\n" );
@@ -1003,3 +1071,4 @@ module_init(eq3loop_init);
10031071module_exit (eq3loop_exit );
10041072MODULE_DESCRIPTION ("eQ-3 IPC loopback char driver" );
10051073MODULE_LICENSE ("GPL" );
1074+ MODULE_VERSION ("1.3" );
0 commit comments