Последовательный порт зависает при закрытии()

Я разработал этот простой модуль ядра, который эмулирует последовательный порт с использованием очереди FIFO и таймера (чтение из аппаратного обеспечения: из очереди, запись в аппаратное обеспечение: вставка в очередь).
Далее показан исходный код.

  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/tty.h>
  #include <linux/tty_flip.h>
  #include <linux/serial.h>
  #include <linux/serial_core.h>
  #include <linux/module.h>


  #define TINY_SERIAL_DEBUG
  #define pr_fmt(fmt) "tiny_serial: " fmt

  #if defined(TINY_SERIAL_DEBUG)
  #define DBG(fmt, ...)  printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
  #else 
  #define DBG(fmt, ...)  no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)   
  #endif

  #define DRIVER_AUTHOR "Me Me <[email protected]>"
  #define DRIVER_DESC "Tiny serial driver"

  /* Module information */
  MODULE_AUTHOR( DRIVER_AUTHOR );
  MODULE_DESCRIPTION( DRIVER_DESC );
  MODULE_LICENSE("GPL");

  #define DELAY_TIME        100// HZ * 2    /* 2 seconds per character */
  #define TINY_DATA_CHARACTER    't'

  #define TINY_SERIAL_MAJOR    240 //240    /* experimental range */
  #define TINY_SERIAL_MINORS    1 //1    /* only have one minor */
  #define UART_NR            1    /* only use one port */

  #define TINY_SERIAL_NAME    "ttytiny"

  #define MY_NAME            TINY_SERIAL_NAME

  #define BUF_SIZE 4096

  static char buf[BUF_SIZE];
  static char *read_ptr;
  static char *write_ptr;

  static struct timer_list *timer;


  static void serial_out(char data) 
  {
      *write_ptr = data;
      write_ptr++;
      if (write_ptr >= buf + BUF_SIZE)
          write_ptr = buf;
  }

  static void serial_in(char *data)
  {
      if (read_ptr == NULL) {
          DBG("pointer is null !\n");
      }

      if (read_ptr && (read_ptr != write_ptr)) {
          *data = *read_ptr;
            read_ptr++;
         if(read_ptr >= buf + BUF_SIZE)
              read_ptr = buf;
      }
  }


  static void tiny_stop_tx(struct uart_port *port)
  {
      DBG("tiny_stop_tx()\n");
  }

  static void tiny_stop_rx(struct uart_port *port)
  {
      DBG("tiny_stop_rx()\n");
  }

  static void tiny_enable_ms(struct uart_port *port)
  {
      DBG("tiny_enable_ms()\n");
  }

  static void tiny_rx_chars(struct uart_port *port, int size)
  {
      int i = 0;
      char byte;
      char flag;
      struct tty_port *tty = &port->state->port;

      if (size <= 0) {
          return;
      }

      while (size--) {
         serial_in(&byte);
         DBG("read: 0x%2x\n", byte);
         flag = TTY_NORMAL;
         port->icount.rx++;

         if (uart_handle_sysrq_char(port, byte)) {
             DBG("found ignore char !\n");
             goto ignore_char;
         }

         uart_insert_char(port, 0, 0, byte, flag);

 ignore_char:
         i ++;
     }

     tty_flip_buffer_push(tty);
     DBG("push to user space !\n");
 }

 static int tiny_tx_chars(struct uart_port *port)
 {
     struct circ_buf *xmit = &port->state->xmit;
     int count;

     DBG("tiny_tx_chars()\n"); 

     if (port->x_char) {
         DBG("wrote 0x%2x\r\n", port->x_char);
         port->icount.tx++;
         port->x_char = 0;
         return 0;
     }
     if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
         tiny_stop_tx(port);
         return 0;
     }

     count = port->fifosize >> 1;

     do {
         DBG("wrote 0x%2x\r\n", xmit->buf[xmit->tail]);
         serial_out(xmit->buf[xmit->tail]);
         xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
         port->icount.tx++;
         if (uart_circ_empty(xmit))
             break;
     } while (--count > 0);

     if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
         uart_write_wakeup(port);

     if (uart_circ_empty(xmit))
         tiny_stop_tx(port);

     return ((port->fifosize >> 1) - count + 1);
 }

 static void tiny_start_tx(struct uart_port *port)
{
     DBG("tiny_start_tx()\n");
 }

 static void tiny_timer(unsigned long data)
 {
     struct uart_port *port;
     struct tty_port *tport;
     int ret = 0;

     DBG("tiny_timer()\n"); 
     port = (struct uart_port *)data;
     if (!port)
         return;
     if (!port->state)
         return;
     tport = &port->state->port;

     /* resubmit the timer again */
     timer->expires = jiffies + DELAY_TIME;
     add_timer(timer);

     /* see if we have any data to transmit */
     ret = tiny_tx_chars(port);
     tiny_rx_chars(port, ret);
}

 static unsigned int tiny_tx_empty(struct uart_port *port)
 {
     DBG("tiny_tx_empty()\n");
     return 0;
 }

 static unsigned int tiny_get_mctrl(struct uart_port *port)
 {
    DBG("tiny_get_mctrl()\n");
     return 0;
 }

 static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
     DBG("tiny_set_mctrl()\n"); 
 }

 static void tiny_break_ctl(struct uart_port *port, int break_state)
 {
     DBG("tiny_set_mctrl()\n"); 
 }

 static void tiny_set_termios(struct uart_port *port,
                  struct ktermios *new, struct ktermios *old)
 {
     int baud, quot, cflag = new->c_cflag;

     DBG("tiny_set_termios()\n"); 

     /* get the byte size */
     switch (cflag & CSIZE) {
     case CS5:
         DBG(" - data bits = 5\n");
         break;
     case CS6:
         DBG(" - data bits = 6\n");
         break;
     case CS7:
         DBG(" - data bits = 7\n");
         break;
     default: // CS8
         DBG(" - data bits = 8\n");
         break;
     }

     /* determine the parity */
     if (cflag & PARENB)
         if (cflag & PARODD)
             DBG(" - parity = odd\n");
         else
             DBG(" - parity = even\n");
     else
         DBG(" - parity = none\n");

     /* figure out the stop bits requested */
     if (cflag & CSTOPB)
         DBG(" - stop bits = 2\n");
     else
         DBG(" - stop bits = 1\n");

     /* figure out the flow control settings */
     if (cflag & CRTSCTS)
         DBG(" - RTS/CTS is enabled\n");
     else
         DBG(" - RTS/CTS is disabled\n");

     /* Set baud rate */
     baud = uart_get_baud_rate(port, new, old, 9600, 115200);
     quot = uart_get_divisor(port, baud);


 }

 static int tiny_startup(struct uart_port *port)
 {
     /* this is the first time this port is opened */
     /* do any hardware initialization needed here */

     DBG("tiny_startup()\n");

     /* create our timer and submit it */
     if (!timer) {
         timer = kmalloc(sizeof(*timer), GFP_KERNEL);
         if (!timer)
             return -ENOMEM;
         init_timer(timer);
     }
     timer->data = (unsigned long)port;
     timer->expires = jiffies + DELAY_TIME;
     timer->function = tiny_timer;
     add_timer(timer);
     return 0;
 }

 static void tiny_shutdown(struct uart_port *port)
 {
     /* The port is being closed by the last user. */
     /* Do any hardware specific stuff here */

     DBG("tiny_shutdown()\n");

     /* shut down our timer */
     del_timer(timer);
 }

 static const char *tiny_type(struct uart_port *port)
 {
     DBG("tiny_type()\n");
     return "tinytty";
 }

 static void tiny_release_port(struct uart_port *port)
 {
     DBG("tiny_release_port()\n");
 }

 static int tiny_request_port(struct uart_port *port)
 {
     DBG("tiny_request_port()\n");
    return 0;
 }

 static void tiny_config_port(struct uart_port *port, int flags)
 {
     DBG("tiny_config_port()\n");
 }

 static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
     DBG("tiny_verify_port()\n");
     return 0;
 }

 static struct uart_ops tiny_ops = {
     .tx_empty    = tiny_tx_empty,
     .set_mctrl    = tiny_set_mctrl,
     .get_mctrl    = tiny_get_mctrl,
     .stop_tx    = tiny_stop_tx,
     .start_tx    = tiny_start_tx,
     .stop_rx    = tiny_stop_rx,
     .enable_ms    = tiny_enable_ms,
     .break_ctl    = tiny_break_ctl,
     .startup    = tiny_startup,
     .shutdown    = tiny_shutdown,
     .set_termios    = tiny_set_termios,
     .type        = tiny_type,
     .release_port    = tiny_release_port,
     .request_port    = tiny_request_port,
     .config_port    = tiny_config_port,
     .verify_port    = tiny_verify_port,
 };

 static struct uart_port tiny_port = {
     .ops        = &tiny_ops,
     .line       = 0,
     .type       = 104,
     .iotype     = SERIAL_IO_PORT,
     .fifosize   = 128,
     .flags      = ASYNC_BOOT_AUTOCONF,
     .irq        = 0,
 };

 static struct uart_driver tiny_reg = {
     .owner        = THIS_MODULE,
     .driver_name    = TINY_SERIAL_NAME,
     .dev_name    = TINY_SERIAL_NAME,
     .major        = TINY_SERIAL_MAJOR,
     .minor        = TINY_SERIAL_MINORS,
     .nr        = UART_NR,
 };

 static int __init tiny_init(void)
 {
     int result;

     DBG(KERN_INFO "Tiny serial driver loaded\n");

     result = uart_register_driver(&tiny_reg);
     if (result) {
         DBG("tiny_init() error!\n");
         return result;
     }

     result = uart_add_one_port(&tiny_reg, &tiny_port);
     if (result) {
         DBG("uart_add_one_port() error!\n");
         uart_unregister_driver(&tiny_reg);
     }

     read_ptr = buf;
     write_ptr = buf;

     return result;
 }

 module_init(tiny_init);

Затем я написал простое тестовое приложение, которое настраивает параметры порта (скорость передачи, четность, стоповые биты и т. д.) и запускает транзакцию записи + чтения, читая ранее записанную строку.
Далее показан исходный код.

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h> 
  #include <strings.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <termios.h>
  #include <sys/stat.h>

  #include <sys/select.h>
  #include <sys/time.h>

  #define PAR_NONE   0
  #define PAR_EVEN   1
  #define PAR_ODD    2

  #define DATA_8BIT  1
  #define DATA_7BIT  2

  #define STOP_1BIT  1
  #define STOP_2BIT  2


  struct tiny_op {
      int max_fd;
      int fd;
      fd_set rfds;
      fd_set wfds;
      fd_set efds;
      struct timeval r_timeout;
      struct timeval w_timeout; 
  };

  static struct tiny_op tops;


  static void set_termios(struct termios *termios, int baudrate, int parity, int bits, int stop) 
  {
      termios->c_cflag |= CLOCAL | CREAD;

      termios->c_cflag &= ~CSIZE;
      switch (bits) {
          case DATA_7BIT:
              termios->c_cflag |= CS7;
              break;

          case DATA_8BIT:
              termios->c_cflag |= CS8; 
              break;

          default:

              termios->c_cflag |= CS8;
              break;
      }

      switch (parity) {
          case PAR_NONE:
              termios->c_cflag &= ~PARENB;
              termios->c_cflag &= ~PARODD;
              break;

          case PAR_EVEN:
              termios->c_cflag |= PARENB;
              termios->c_cflag &= ~PARODD;
              break;

          case PAR_ODD:
              termios->c_cflag |= PARENB;
              termios->c_cflag |= PARODD;
              break;

          default:
              termios->c_cflag &= ~PARENB;
              termios->c_cflag &= ~PARODD;
              break;
      }

      switch (stop) {
          case STOP_1BIT:
              termios->c_cflag &= ~CSTOPB;
              break;

          case STOP_2BIT:
              termios->c_cflag |= CSTOPB;
              break;

          default:
              termios->c_cflag &= ~CSTOPB;
              break;
      }

      termios->c_iflag |= INPCK | ISTRIP;
      termios->c_lflag = 0;
      termios->c_oflag = 0;

      termios->c_cc[VTIME] = 5;
      termios->c_cc[VMIN]  = 0;

      cfsetspeed(termios, baudrate);
 }


 static int tiny_write(struct tiny_op *op, char *buff, int size)
 {
     int ret = -1;
     int len = 0;

     op->w_timeout.tv_sec  = 5;
     op->w_timeout.tv_usec = 0;

     ret = select(op->max_fd, NULL, &op->wfds, &op->efds, &op->w_timeout);
     if (ret < 0) {
         printf("[TINY SERIAL] Select fallita (write) !\n");
         return -1;
     } if (0 == ret) {
         printf("[TINY SERIAL] Select time-out (write) !\n");
     } else {
             if (FD_ISSET(op->fd, &op->efds)) {
             printf("[TINY SERIAL] Attenzione: errore in scrittura!\n");
             return -1;
         }

         if (FD_ISSET(op->fd, &op->wfds)) {
             printf("[TINY SERIAL] Scrittura pronta, procedo !\n");
             len = write(op->fd, (const void *)buff, size);

             if (len == size) {
                 printf("[TINY SERIAL] Scrittura completata!\n");
             } else {
                 printf("[TINY SERIAL] Scrittura parzialmente completata, scritti : = %d\n", len);
             }
        }
     }

     return 0;
 }


 static int tiny_read(struct tiny_op *op, char *buff, int size)
 {
     int ret = -1;
     int len = 0;

     op->r_timeout.tv_sec = 5;
     op->r_timeout.tv_usec = 0;

     ret = select(op->max_fd, &op->rfds, NULL, &op->efds, &op->r_timeout);
     if (ret < 0) {
         printf("[TINY SERIAL] Select fallita (read) !\n");
         return -1;
     } if (0 == ret) {
         printf("[TINY SERIAL] Select time-out (read)!\n");
     } else {
         if (FD_ISSET(op->fd, &op->efds)) {
             printf("[TINY SERIAL] Attenzione: errore in lettura!\n");
             return -1;
         }

         if (FD_ISSET(op->fd, &op->rfds)) {
             printf("[TINY SERIAL] Dati da leggere disponibili!\n");

             len = read(op->fd, (void *)buff, size);
             printf("[TINY SERIAL] Lettura da seriale: %s, len: %d\n", buff, len);
         }
     }

     return 0;
 }


 int main(int argc, char **argv)
 {
     int fd = -1, ret = -1;
     struct termios oldtio, newtio;

     char *str = {"Hello world!!\0"};
     char buff[strlen(str)];

     if(argc == 1){

       printf("[TINY DRIVER] Inserisci il device seriale da testare.\n");
       return -1;
     }

     char * device = argv[1];
     struct stat file_infos;

     if(strlen(device) == 0){
        printf("[TINY DRIVER] Seleziona un device corretto.\n");
        return -1;
     }

     printf("[TINY DRIVER] Hai selezionato il device: %s\n", device);

     if(stat(device, &file_infos) < 0){
        printf("[TINY DRIVER] Attenzione: errore nell'accesso al device selezionato: %s, riprova con un altro dispositivo.\n", device);
        return -1;
     }

     bzero((void *)&oldtio, sizeof(oldtio));
     bzero((void *)&newtio, sizeof(newtio)); 

     fd = open(device, O_RDWR | O_NONBLOCK | O_SYNC);
     if (fd == -1) {
         printf("[TINY SERIAL] failed to open /dev/ttytiny0 !\n");
         return -1;
     }

     printf("[TINY SERIAL] succeed to open /dev/ttytiny0 !\n");

     ret = tcgetattr(fd, &oldtio);
     if (ret != 0) {
         printf("[TINY SERIAL] failed to get attr !\n");
         close(fd);
         return -1;
     }

     set_termios(&newtio, B38400, PAR_EVEN, DATA_8BIT, STOP_2BIT);

     tcflush(fd, TCIOFLUSH);

     ret = tcsetattr(fd, TCSANOW, &newtio);
     if (ret != 0) {
         printf("[TINY SERIAL] failed to set termios !\n");
         close(fd);
         return -1;
     }

     tops.fd = fd;

     tops.max_fd = tops.fd + 1;

     FD_ZERO(&tops.rfds);
     FD_ZERO(&tops.wfds);
     FD_ZERO(&tops.efds);

     FD_SET(tops.fd, &tops.rfds);
     FD_SET(tops.fd, &tops.wfds);
     FD_SET(tops.fd, &tops.efds);

     if (tiny_write(&tops, str, strlen(str)) != 0) {
         close(fd);
         return -1;
     }

     if (tiny_read(&tops, buff, sizeof(buff)) != 0) {
         close(fd);
         return -1;
     }

     ret = tcsetattr(fd, TCSANOW, &oldtio);
     if (ret != 0) {
         printf("[TINY SERIAL] Errore nel reset delle impostazioni.\n");
     }else{
         printf("[TINY SERIAL] Impostazioni resettate correttamente.\n");
     }

     ret = tcflush(fd, TCIOFLUSH);

     if(ret != 0){
        printf("[TINY SERIAL] Errore nel flushing dei dati (finale) !\n");
     }else{
        printf("[TINY SERIAL] Dati flushati correttamente!\n");
     }

     //Program hangs on this call
     ret = close(fd);

     if (ret != 0) {   
         printf("[TINY SERIAL] Errore nella Chiusura del file !\n");
         return -1;
     }else{
         printf("[TINY SERIAL] Chiusura del file avvenuta correttamente !\n");
     }

     return 0;
 }

Моя проблема: тестовое приложение работает нормально (я могу писать и читать свою собственную строку), пока не достигнет close(2): там он зависает навсегда, не доходя до конца программы (я должен закрыть его с помощью CTRL+C, а затем он закрывается должным образом, так как модуль ядра вызывает tiny_shutdown()).
Я также пытался написать простую программу для открытия и закрытия устройства /dev/ttytiny0, но результат тот же (хотя я заметил, что если я удалю close(2) программа по-прежнему зависает без завершения, но на этот раз я не мог не выключайте его с помощью CTRL+C).
Любая ссылка/ссылка на книги или материалы по этому вопросу будет высоко оценена.
Заранее спасибо!

Редактировать : здесь отображаются сообщения журнала ядра (во время работы тестового приложения).

[  446.862221] tiny_ser: module verification failed: signature and/or required key missing - tainting kernel
[  446.864143] tiny_serial: 6Tiny serial driver loaded
[  486.715801] tiny_serial: tiny_startup()
[  486.715812] tiny_serial: tiny_set_termios()
[  486.715814] tiny_serial:  - data bits = 8
[  486.715816] tiny_serial:  - parity = none
[  486.715818] tiny_serial:  - stop bits = 1
[  486.715820] tiny_serial:  - RTS/CTS is disabled
[  486.715824] tiny_serial: tiny_set_mctrl()
[  486.715853] tiny_serial: tiny_set_termios()
[  486.715856] tiny_serial:  - data bits = 8
[  486.715857] tiny_serial:  - parity = even
[  486.715859] tiny_serial:  - stop bits = 2
[  486.715861] tiny_serial:  - RTS/CTS is disabled
[  486.715943] tiny_serial: tiny_start_tx()
[  487.116105] tiny_serial: tiny_timer()
[  487.116171] tiny_serial: tiny_tx_chars()
[  487.116183] tiny_serial: wrote 0x42
[  487.116189] tiny_serial: wrote 0x75
[  487.116196] tiny_serial: wrote 0x6f
[  487.116202] tiny_serial: wrote 0x6e
[  487.116208] tiny_serial: wrote 0x61
[  487.116214] tiny_serial: wrote 0x73
[  487.116220] tiny_serial: wrote 0x65
[  487.116226] tiny_serial: wrote 0x72
[  487.116232] tiny_serial: wrote 0x61
[  487.116238] tiny_serial: wrote 0x20
[  487.116245] tiny_serial: wrote 0x64
[  487.116251] tiny_serial: wrote 0x72
[  487.116257] tiny_serial: wrote 0x69
[  487.116263] tiny_serial: wrote 0x76
[  487.116269] tiny_serial: wrote 0x65
[  487.116275] tiny_serial: wrote 0x72
[  487.116281] tiny_serial: wrote 0x21
[  487.116287] tiny_serial: wrote 0x21
[  487.116295] tiny_serial: tiny_stop_tx()
[  487.116303] tiny_serial: read: 0x42
[  487.116312] tiny_serial: read: 0x75
[  487.116318] tiny_serial: read: 0x6f
[  487.116324] tiny_serial: read: 0x6e
[  487.116330] tiny_serial: read: 0x61
[  487.116337] tiny_serial: read: 0x73
[  487.116343] tiny_serial: read: 0x65
[  487.116349] tiny_serial: read: 0x72
[  487.116355] tiny_serial: read: 0x61
[  487.116361] tiny_serial: read: 0x20
[  487.116367] tiny_serial: read: 0x64
[  487.116373] tiny_serial: read: 0x72
[  487.116379] tiny_serial: read: 0x69
[  487.116385] tiny_serial: read: 0x76
[  487.116391] tiny_serial: read: 0x65
[  487.116397] tiny_serial: read: 0x72
[  487.116403] tiny_serial: read: 0x21
[  487.116409] tiny_serial: read: 0x21
[  487.116444] tiny_serial: push to user space !
[  487.116565] tiny_serial: tiny_start_tx()
[  487.116709] tiny_serial: tiny_set_termios()
[  487.116713] tiny_serial:  - data bits = 8
[  487.116715] tiny_serial:  - parity = none
[  487.116717] tiny_serial:  - stop bits = 1
[  487.116719] tiny_serial:  - RTS/CTS is disabled
[  487.116746] tiny_serial: tiny_tx_empty()
[  487.516021] tiny_serial: tiny_timer()
[  487.516094] tiny_serial: tiny_tx_chars()
[  487.516104] tiny_serial: tiny_stop_tx()
[  487.915917] tiny_serial: tiny_timer()
[  487.915960] tiny_serial: tiny_tx_chars()
[  487.915971] tiny_serial: tiny_stop_tx()
[  505.910955] tiny_serial: tiny_timer()
[  505.910968] tiny_serial: tiny_tx_chars()
[  505.910971] tiny_serial: tiny_stop_tx()
[  506.455320] tiny_serial: tiny_timer()
[  506.455332] tiny_serial: tiny_tx_chars()
[  506.455335] tiny_serial: tiny_stop_tx()
[  506.855344] tiny_serial: tiny_timer()
[  506.855428] tiny_serial: tiny_tx_chars()
[  506.855437] tiny_serial: tiny_stop_tx()
[  507.255499] tiny_serial: tiny_timer()
[  507.255563] tiny_serial: tiny_tx_chars()
[  507.255572] tiny_serial: tiny_stop_tx()
[  507.655342] tiny_serial: tiny_timer()
[  507.655401] tiny_serial: tiny_tx_chars()
[  507.655411] tiny_serial: tiny_stop_tx()
[  507.755090] tiny_serial: tiny_stop_rx()
[  507.755100] tiny_serial: tiny_tx_empty()
[  507.755103] tiny_serial: tiny_set_mctrl()
[  507.755105] tiny_serial: tiny_shutdown()
[  507.755108] tiny_serial: tiny_shutdown() - after del_timer()

Обратите внимание, что последовательность tiny_stop_rx() - tiny_tx_empty() - tiny_set_mctrl() - tiny_shutdown() вызывается, когда я завершаю выполнение тестового приложения с помощью CTRL+C.
Другие повторяющиеся сообщения (последовательность tiny_timer() - tiny_tx_chars() - tiny_stop_tx()) генерируются таймером, который проверяет, нужно ли что-то передать (но очередь пуста, поэтому он снова спит).
Конечно, журналы тестового приложения показывают правильное поведение, пока не будет достигнуто функция закрыть().


person aldoalpha    schedule 01.07.2018    source источник
comment
Не могли бы вы показать журналы, записанные драйвером при использовании тестовой программы?   -  person alk    schedule 01.07.2018
comment
Конечно, я добавил их к вопросу.   -  person aldoalpha    schedule 01.07.2018
comment
Итак, перестает ли драйвер вести журнал после того, как close() начал блокировать? Если да, то какая последняя запись?   -  person alk    schedule 01.07.2018
comment
Также не могли бы вы поместить еще один оператор журнала сразу после del_timer() и повторить проверку?   -  person alk    schedule 01.07.2018
comment
Драйвер продолжает вести журнал даже после того, как тестовое приложение вызывает функцию закрытия. Он продолжает регистрировать последовательность tiny_timer() - tiny_tx_chars() - tiny_stop_tx(), пока я не закрою ее с помощью CTRL+C. В этот момент, как вы можете видеть из журналов, я думаю, что вызывается последовательность tiny_stop_rx() - tiny_tx_empty() - tiny_set_mctrl() - tiny_shutdown(). Также обратите внимание, что я добавил точку журнала сразу после вызова del_timer(), и она отображается правильно.   -  person aldoalpha    schedule 01.07.2018
comment
PS: вы заметите некоторые «дыры» в сообщениях журнала, взглянув на числовые значения слева: они были просто повторением последовательности tiny_timer() - tiny_tx_chars() - tiny_stop_tx(), я удалил некоторые сообщения журнала из-за лимит символов SO.   -  person aldoalpha    schedule 01.07.2018
comment
Также: я использую dmesg | grep tiny › log.txt для сбора журналов ядра, связанных с модулем ядра.   -  person aldoalpha    schedule 01.07.2018
comment
Не уверен, поможет ли это, но с kernel.org/doc/Documentation/serial/driver узнаем: tx_empty(port) Эта функция проверяет, пусты ли fifo передатчика и шифтер для порта, описываемого 'port'. [..] Если порт не поддерживает эту операцию, то он должен вернуть TIOCSER_TEMT.   -  person alk    schedule 01.07.2018
comment
Я чувствую, что вышеизложенное может быть важным, так как мне кажется, что ядро ​​​​отчаянно пытается rx, чего нет вокруг, и только сигнал, поднятый вами, дающий Ctrl-C, облегчает это.   -  person alk    schedule 01.07.2018
comment
Ваша реализация возвращает 0 из tx_empty(), что означает непустое значение.   -  person alk    schedule 01.07.2018
comment
Понял суть. Я попытаюсь изменить это поведение, я сообщу о любых изменениях: спасибо!   -  person aldoalpha    schedule 01.07.2018
comment
Решил это. Я добавил несколько строк, которые проверяют, пуст ли буфер или нет, а затем возвращают соответствующее значение на основе этого. Усвоенный урок: всегда сначала проверяйте документацию! В любом случае, большое спасибо.   -  person aldoalpha    schedule 01.07.2018
comment
Пожалуйста. И действительно интересный случай. Блокировка close() встречается редко...   -  person alk    schedule 01.07.2018


Ответы (1)


Ваша реализация возвращает 0 из tx_empty(), что означает "не пустой".

Из kernel.org/doc/Documentation/serial/driver:

tx_empty(port)

Эта функция проверяет, пусты ли fifo передатчика и устройство сдвига для порта, описываемого как «порт». Если он пуст, эта функция должна вернуть TIOCSER_TEMT, иначе вернуть 0. Если порт не поддерживает эту операцию, то она должна вернуть TIOCSER_TEMT.

person alk    schedule 01.07.2018