c - 某种事件驱动程序

标签 c linux linux-kernel linux-device-driver raspberry-pi3

我正在尝试在 Raspberry pi 3 中制作一个 Linux 内核驱动程序,当按下操纵杆中的按钮时它会打开 LED(将 GPIO 设置为输出然后将其设置为打开状态)并读取该 GPIO 的状态端口。

我打开 LED 的驱动程序是:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<asm/uaccess.h>
#include<asm/io.h>
#define ioaddress_SIE_BASE 0x3F200000
#define ioaddress_SIZE 0x38
#define address_LED_on 0x1C
#define address_LED_off 0x28
#define address_LED_estado 0x34
MODULE_LICENSE("Dual BSD/GPL");
static char *nombre="4led";
static unsigned int PrimerMenor=0;
static unsigned int cuenta=1;
static dev_t led_dev_numero;
char *buffer;
int on_off=0;
int leido=0;
static void __iomem *ioaddress_SIE;
struct led_dev *led_dev_puntero;

struct led_dev {
    struct cdev led_cdev;
};
int led_open (struct inode *puntero_inode, struct file *puntero_file)
{
 struct led_dev *led_dev_puntero;
 printk (KERN_INFO "led_SIE: se ha abierto el dispositivo \n" );
 led_dev_puntero=container_of(puntero_inode->i_cdev, struct led_dev, led_cdev);
 puntero_file->private_data=led_dev_puntero;
 return 0;
}

int led_release (struct inode *puntero_inode , struct file *puntero_file)
{
 printk (KERN_INFO "led_SIE: se ha liberado el dispositivo \n" );
 return 0;
}

static ssize_t led_read (struct file *puntero_file , char *buffer_user, size_t tamano, loff_t *puntero_offset)
{
 unsigned int estado;
 unsigned long prueba;
 printk (KERN_INFO "led_SIE: leyendo el dispositivo \n" );
 iowrite32(0x00000000, ioaddress_SIE);
 estado=ioread32(ioaddress_SIE + address_LED_estado);

 printk("led_SIE: GPIOs 9 to 0 --> 0x%X \n", estado);

*buffer=(char ) (estado >> leido );

prueba=copy_to_user(buffer_user, buffer, 1);
printk("led_SIE: GPIOs 9 to 0 --> 0x%X \n", *buffer);

if(leido>23){
leido=0;}
else
  leido=leido+8;
return 1;
}


static ssize_t led_write (struct file *puntero_file , const char *buffer_user, size_t tamano, loff_t *puntero_offset)
{
 unsigned long prueba;
/*printk(KERN_INFO "led_SIE: escribiendo en el dispositivo \n");
if(buffer_user[0]!='1'){
if(buffer_user[0]!='0'){
printk(KERN_INFO "led_SIE: Ha ingresado una orden incorrecta! \n");
printk(KERN_INFO "led_SIE: Las ordenes son: 1 para encender, 0 para apagar \n");
return tamano;
}
}*/

prueba=copy_from_user(buffer, buffer_user, tamano);

printk(KERN_INFO "led_SIE: SE escribió %c en el dispositivo \n", buffer);
/*ibuffer_user=(int)buffer_user;*/
/*printk(ibuffer_user);
int    ibuffer = (int) buffer;*/
/*if(buffer_user=='1'){
printk(KERN_INFO "Lee maldita sea \n");
}*/
switch(buffer[0]){
case '1':
if(on_off==1){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=1;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000004, ioaddress_SIE + address_LED_on);
iowrite32(0x00000038, ioaddress_SIE + address_LED_off);
break;

case '2':
if(on_off==2){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=2;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000008, ioaddress_SIE + address_LED_on);
iowrite32(0x00000034, ioaddress_SIE + address_LED_off);
break;

case '3':
if(on_off==3){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=3;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000010, ioaddress_SIE + address_LED_on);
iowrite32(0x0000002C, ioaddress_SIE + address_LED_off);
break;

case '4':
if(on_off==4){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=4;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000020, ioaddress_SIE + address_LED_on);
iowrite32(0x0000001C, ioaddress_SIE + address_LED_off);

break;
case '0':
if(on_off==0){
printk(KERN_INFO "led_SIE: El led ya se encuentra apagado \n");
return tamano;
}
on_off=0;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x0000003C, ioaddress_SIE + address_LED_off);
break;
default:
return tamano;
}
return tamano;
}


struct file_operations led_fops = {

    .owner = THIS_MODULE,
    .read = led_read,
    .write = led_write,
    .open = led_open,
    .release = led_release
};

static int hello_init(void)
{
int resultado, error;

printk(KERN_ALERT "Hola, mundo\n");
resultado=alloc_chrdev_region(&led_dev_numero, PrimerMenor, cuenta, nombre);
if (resultado ==0)
printk(KERN_INFO "Se reservaron los siguientes numeros \n Mayor:  %d\n Menor: %d\n", MAJOR(led_dev_numero), MINOR(led_dev_numero));
else
printk(KERN_INFO "Hubo un error y los numeros no se reservaron. Error:  %d\n", resultado);

led_dev_puntero = kmalloc (sizeof(struct led_dev), GFP_ATOMIC);
buffer=kmalloc(8,GFP_ATOMIC);//GFP_KERNEL---Difícil
cdev_init(&led_dev_puntero->led_cdev, &led_fops);
led_dev_puntero->led_cdev.owner=THIS_MODULE;
led_dev_puntero->led_cdev.ops=&led_fops;
error=cdev_add(&led_dev_puntero->led_cdev, led_dev_numero, cuenta);
if(error)
printk (KERN_INFO "error $d al anadir led_dev");
ioaddress_SIE=ioremap(ioaddress_SIE_BASE, ioaddress_SIZE);
printk(KERN_ALERT "ioadress_SIE_BASE fue mapeado a: %p \n", ioaddress_SIE);
return 0;
}
module_init(hello_init);

static void hello_exit(void)
{
 printk(KERN_ALERT "Adios, mundo cruel\n");
 unregister_chrdev_region(led_dev_numero,cuenta);
 cdev_del(&led_dev_puntero->led_cdev);
 kfree(led_dev_puntero);
 kfree(buffer);
if(on_off==1){
 iowrite32(0xFFFFFFFF, ioaddress_SIE + address_LED_off);
}
iounmap(ioaddress_SIE);
}

module_exit(hello_exit);

与驱动器和操纵杆交互的应用程序是:

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

struct js_event {
        unsigned int time;      /* event timestamp in milliseconds */
        short value;   /* value */
        unsigned char type;     /* event type */
        unsigned char number;   /* axis/button number */
};

#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
#define JS_EVENT_AXIS           0x02    /* joystick moved */
#define JS_EVENT_INIT           0x80    /* initial state of device */

int main(int argc, char **argv)
{   //Acceso al driver Xdriv
    int fd = open ("/dev/input/js0", O_RDONLY);
    FILE *archivo;
    int  tamano;
    int a;int b;

    /*Acceso al driver 4_leds

    system("sudo chmod 777 /dev/4leds");
    archivo=fopen("/dev/4leds" ,"w");
    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
    */

    if( fd < 0 )
        printf( "cannot open dev\n" );
    else
        printf( "opened success...:)\n" );

    struct js_event e;
    while( 1 ) //event loop
    {
        read( fd, &e, sizeof(e) );
        //printf( "%d %d %d %d\n", e.time, e.value, e.type, e.number );

        if( e.type == JS_EVENT_BUTTON || e.type == JS_EVENT_AXIS )
        {
            if( e.type == JS_EVENT_BUTTON ){
                printf( "button#%d value:%d\n", (int) e.number, e.value );

        switch((int) e.number) {
                case 0  ://Btn A, Motor 1---Atrás
                if ((int) e.value == 1){
                printf("Hola esto es 0\n Btn A, Motor 1---Atrás");
                char escribe[1] = "1";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 1 en driver
                fclose(archivo);
                    sleep(3);               
                printf("Este es escribe :%c ",*escribe);}
                else{
                printf("Hola esto es 0 pero no presionado\n");
                }

                break; 

                case 1  ://Btn B, Motor 1---Adelante
                    if ((int) e.value == 1){
                printf("Hola esto es 1\n Btn B, Motor 1---Adelante");
                char escribe[1] = "2";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 2 en driver
                fclose(archivo);
                    sleep(3);               
                printf("Este es escribe :%c \n",*escribe);}
                else{
                printf("Hola esto es 1 pero no presionado\n");
                }
                    break; 

                case 2  ://Btn X, Motor 2---Abajo
                if ((int) e.value == 1){
                printf("Hola esto es 2 \n Btn X, Motor 2---Abajo");
                char escribe[1] = "3";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 3 en driver
                fclose(archivo);
                    sleep(3);               
                printf("Este es escribe :%c \n",*escribe);}
                else{
                printf("Hola esto es 2 pero no presionado\n");
                }
                break; 

                case 3  ://Btn Y, Motor 2---Arriba
                if ((int) e.value == 1){
                printf("Hola esto es 3 \n Btn Y, Motor 2---Arriba");
                char escribe[1] = "4";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 4 en driver
                    fclose(archivo);
                    sleep(3);               
                printf("Este es escribe :%c \n",*escribe);}
                else{
                printf("Hola esto es 3 pero no presionado\n");
                }
                break; 

                case 7  ://Detener
                if ((int) e.value == 1){
                printf("Hola esto es Start/Stop \n");
                char escribe[1] = "0";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 0 en driver
                fclose(archivo);
                    sleep(3);
                printf("Este es escribe :%c \n",*escribe);}
                else{
                printf("Hola esto es 7 pero no presionado\n");
                }
                break; 

                default : /* Optional */
                printf("Hola esto es default también sirve como stop\n");
                char escribe[1] = "0";
                    //Acceso al driver 4_leds

                    system("sudo chmod 777 /dev/4leds");
                    archivo=fopen("/dev/4leds" ,"w");
                    if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
                    //
                fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 0 en driver
                    fclose(archivo);
                        sleep(3);               
                printf("Este es escribe :%c \n",*escribe);
                     }
        printf("El último presionado fue: %X \n",(char) e.number);}
            else{
                printf( "axis#%d value:%d \n", (int) e.number, e.value );}
        }
        else
        {
            printf( "Init Events\n" );
        }

    }
    return 0;
}

我遇到段错误,所以我认为这可能是 copy_from_user 缓冲区中的内存分配问题...但我现在不知道如何解决它。

我之前试过打开文件,然后在每个 switch case 中写入,还打开文件并在 switch case 中写入...等等。

驱动程序与另一个非事件应用程序一起工作正常。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char **argv){

FILE *archivo;
char escribe[1];
char lee[1];
int  tamano, i;
int registro=0;
int registro2=0;

tamano=1;

printf("introduzca el numero que quiere escribir: ");
scanf("%c" ,escribe);
printf("%c ",*escribe);
system("sudo chmod 777 /dev/4leds");

archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}

fwrite(escribe ,sizeof(char) ,tamano , archivo);

printf("El valor escrito fue: %c \n" , *escribe);

fclose(archivo);

sleep(3);

/*archivo=fopen("/dev/4leds", "r");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}

for (i=0;i<4;i++)
    {
    registro=registro << 8;
    fread(lee ,tamano*sizeof(char),1,archivo);
    registro=registro | *lee;
    }

registro2=registro2 | (registro << 24 & 0xFF000000);
registro2=registro2 | (registro << 8  & 0x00FF0000);
registro2=registro2 | (registro >> 8  & 0x0000FF00);
registro2=registro2 | (registro >> 24 & 0x000000FF);

printf("El valor leido es: 0x%X \n" , registro2);

fclose(archivo);*/

return 0;
}

感谢您的帮助和建议。对注释代码感到抱歉,但我正在测试驱动程序的所有部分。

最佳答案

tamano 或元素数量已声明但从未在 main() 中定义。

fwrite(escribe ,sizeof(char) ,tamano , archivo);

关于c - 某种事件驱动程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45154115/

相关文章:

c++ - #define 和 const 的分配

c - 传递数组名称时 sizeof 如何工作

linux - 是否有 Linux 控制台命令行 MVC 框架?

linux - 在管道 awk 语句之间传递变量

c - Linux 中的 DMA 如何处理 memcpy

linux - 检查页面是否在任务的VMA中

在 yacc/lex 中调用 YYACCEPT 之前清除缓冲区

c - C声明意味着什么?

linux - 在 Linux 下通过软件强制自动调整显示器

c - printk loff_t 类型的格式说明符?