简体   繁体   English

在Linux内核中的UART轮询期间处理CTRL-C

[英]Handling CTRL-C during UART polling in Linux Kernel

I have a syscall read, like so: 我有一个系统调用读取,像这样:

ssize_t serp_read(struct file *filep, char __user *buf, size_t count, loff_t *offp){
        ssize_t cnt;
        char *buffer;
        int i;

        buffer = kmalloc(count * sizeof(char), GFP_KERNEL);

        for (i = 0; i != count; ++i) {
            buffer[i] = UART_read();
            if(buffer[i] == '\n')
                break;
        }

        cnt = copy_to_user(buf, buffer, i);
        kfree(buffer);
        if(cnt) {
        printk("Error in copy_to_user() cnt is %d\n", cnt);
        i -= cnt; /* bytes successfully copied */
        }

        return i; 
}

And the UART_read() is UART_read()是

unsigned char UART_read(void){
     unsigned int buf;
     if( ( inb(UART + UART_LSR) & UART_LSR_FE ) == 1){
       printk("KERNEL - Framing error"); return -1;}
     else if( ( inb(UART + UART_LSR) & UART_LSR_PE ) == 1){
       printk("KERNEL - Parity error"); return -1;}
     else if( ( inb(UART + UART_LSR) & UART_LSR_OE ) == 1){
       printk("KERNEL - Overrun error"); return -1;}

     while( ( ( inb(UART_LSR + UART) ) & UART_LSR_DR ) == 0 ){
             schedule();
     }
     buf = inb(UART);
     return (char)buf;
}

And in my test program I invoke it 然后在我的测试程序中调用它

    rb = read(fd, buffer, sizeof(buffer));
    if ( rb < 0){
        perror("Error");
    }
    else {
        buffer[rb] = '\0';
    }

So, from the moment I invoke it in the test program, I can't get out unless the UART gets some characters. 因此,从我在测试程序中调用它的那一刻起,除非UART获得一些字符,否则我无法离开。 But I want to be able to interrupt the process. 但我希望能够中断该过程。 Can I do a normal handler to handle a CTRL-C? 我可以做一个普通的处理程序来处理CTRL-C吗? Or do I have to do something different for the same effect? 还是我必须做一些不同的事情才能达到相同的效果? And if the handler is called, where is the kernel program going to go afterwards? 如果调用了处理程序,内核程序将在哪里去? Or what would happen in the kernel if I just had a normal handler in the test program? 还是如果我在测试程序中只有一个普通的处理程序,在内核中会发生什么? Would it work at all? 会起作用吗?

Also, kernel code is one program and the test program is another program altogether. 同样,内核代码是一个程序,而测试程序则是另一个程序。

EDIT2: ctrl+c issues a signal(SIGINT) that can be treated with sigaction() EDIT2:ctrl + c发出一个信号(SIGINT)可以用sigaction()处理

-----------IGNORE MODE ON (according to @undefined-behaviour)------------- ----------- IGNORE MODE ON(根据@ undefined-behaviour)-------------

this code handles a ctrl+c 此代码处理ctrl + c

EDIT: while ((a!='A')&&(a!= 'ctrl+c' )); 编辑: while ((a!='A')&&(a!= 'ctrl+c' )); this was supposed to have the 'ctrl+c' char but stackoverflow doesnt show it (its the decimal/octal/hex: 0003) 这应该具有'ctrl + c'字符,但是stackoverflow不会显示它(其十进制/八进制/十六进制:0003)

#include <stdio.h>
#include <unistd.h> /*_getch*/
#include <termios.h>    /*_getch*/


char getch() {
    /*#include <unistd.h>   //_getch*/
    /*#include <termios.h>  //_getch*/
    char buf=0;
    struct termios old = {0};
    fflush(stdout);
    if(tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag&=~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN]=1;
    old.c_cc[VTIME]=0;
    if(tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
    if(read(0,&buf,1)<0)
        perror("read()");
    old.c_lflag=ICANON;
    old.c_lflag=ECHO;
    if(tcsetattr(0, TCSADRAIN, &old) < 0)
        perror ("tcsetattr ~ICANON");
    printf("%c\n",buf);
    return buf;
}

int main(int argc, char *argv[]){
    char a;
    do{
        a=getch();
        printf("%d-%c \n",a,a);
    }while ((a!='A')&&(a!='ctrl+c'));   /* ctrl+c ;  backspace ;� multi-char cte ; ç 135*/
    printf("\n");
    return 0;
}

I believe what you can do is write a signal handler at your application level which catches SIGINT (ctrl+c) or whatever signal of your choice (provided we can handle those) 我相信您可以做的是在您的应用程序级别编写一个信号处理程序,以捕获SIGINT(ctrl + c)或您选择的任何信号(前提是我们能够处理这些信号)

and from the signal handle call an IOCTL call to your driver inside kernel which inturn should reschedule your kernel read may be a change in logic like below 并从信号句柄中调用IOCTL调用内核中的驱动程序,从而应重新安排内核读取的时间,这可能是如下所示的逻辑更改

you need to implement an IOCTL call at kernel along with this 您需要与此同时在内核上实现IOCTL调用

 /** This NO_SIGNAL_FROM_USER is a GLOBAL variable at kernel 
             which should be set based on your IOCTL**/

 while( (( ( inb(UART_LSR + UART) ) & UART_LSR_DR ) == 0 ) && (NO_SIGNAL_FROM_USER)){
             schedule();
     }

and a little change at your read 在阅读时有一点变化

for (i = 0; i != count && NO_SIGNAL_FROM_USER ; ++i) {
            buffer[i] = UART_read();
            if(buffer[i] == '\n')
                break;
        }
/*** RESET THE SIGNAL HERE AGAIN ***/

PS - oops forgot may be you need to do some more handling at signal handler also in your user application, but again that depends i guess. PS-哎呀,忘记了您可能还需要在用户应用程序中的信号处理程序上做一些处理,但这又取决于我的猜测。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM