Aprendizaje de controladores LINUX integrado 6. Equipo mixto (1): Uso de estructura y función


Aprendizaje de controladores LINUX integrado 6. Equipo diverso (1): uso de estructura y función)
El número de dispositivo principal del dispositivo híbrido es 10, generalmente solo es necesario asignar el número de dispositivo menor, que puede especificar usted mismo (si se repite, se informará un error), o puede ser asignado por el kernel
Utilice el método de dispositivo promiscuo para programar. Cuando se registra el dispositivo promiscuo, se crea automáticamente un dispositivo de caracteres sin ejecutar el comando mknod. Consulte la función misc_register para una implementación específica

1. La ubicación del archivo de encabezado y la descripción de las principales variables miembro de la estructura principal

头文件位置:include/linux/miscdevice.h"
struct miscdevice  {
    
    
        int minor;  //保存次设备号,一般使用宏MISC_DYNAMIC_MINOR;表示:由内核分配次设备号
        const char *name;   //保存字符设备名称
        const struct file_operations *fops;  //指向文件操作接口对象
       // .....省略更多,在后续分析源码时介绍.......
};

extern int misc_register(struct miscdevice * misc); // 注册混杂设备
extern int misc_deregister(struct miscdevice *misc);//卸载混杂设备

2. Ejemplos de código de kernel:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <cfg_type.h>
struct led_source {
    
    
    char name[10];
    unsigned long gpio ;
};
struct led_source led_info[] = {
    
    
    {
    
    
        .name = "LED1",
        .gpio = PAD_GPIO_C +12
    },
    {
    
    
        .name = "LED2",
        .gpio = PAD_GPIO_C +11
    },
    {
    
    
        .name = "LED3",
        .gpio = PAD_GPIO_C +7
    },
    {
    
    
        .name = "LED4",
        .gpio = PAD_GPIO_B +26
    }
};

void gpio_state(unsigned long kargs[4]){
    
    
    int i =0;
    for(;i < 4 ; i++){
    
    
        kargs[i] = gpio_get_value(led_info[i].gpio);
    }
}
/*用ioctl方式实现开关灯控制,函数说明参考:嵌入式LINUX驱动学习之5*/
#define LED_ON    0X100
#define LED_OFF   0X101
#define LED_STATE 0X110
long myioctl(struct file * file , unsigned int ucmd,unsigned long args){
    
    
    unsigned int kcmd;
    unsigned long kargs[4];
    kcmd = ucmd;
    copy_from_user(&kargs[0],args,sizeof(long));
    switch(kcmd){
    
    
        case LED_ON :
            gpio_set_value(led_info[kargs[0]-1].gpio,0);
            break;
        case LED_OFF :
            gpio_set_value(led_info[kargs[0]-1].gpio,1);
            break;
        case LED_STATE :
            gpio_state(kargs);
            copy_to_user(args,kargs,sizeof(long)*4);
            break;
        default :
            break;
    }
}

struct file_operations fops = {
    
    
    .owner = THIS_MODULE,
    .unlocked_ioctl = myioctl

};

struct miscdevice misc_dev = {
    
     //定义混杂设备结构体对象
    .minor = MISC_DYNAMIC_MINOR,//由内核分配次设备号
    .name = "misc_dev_led",//字符设备名称
    .fops = &fops  //文件操作接口对你象
};

static int led_init(void){
    
    
    int i = 0;
    for(; i <ARRAY_SIZE(led_info);i++){
    
    
        gpio_request(led_info[i].gpio,led_info[i].name);
        gpio_direction_output(led_info[i].gpio,1);
    }
    misc_register(&misc_dev);    //注册混杂设备

    return 0;
}
static void led_exit(void){
    
    
    int i = 0;
    for(; i <ARRAY_SIZE(led_info);i++){
    
    
        gpio_set_value(led_info[i].gpio,1);
        gpio_free(led_info[i].gpio);
    }
    misc_deregister(&misc_dev);//卸载混杂设备

}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

3. Implementación del código de espacio de usuario:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define LED_ON    0X100
#define LED_OFF   0X101
#define LED_STATE 0X110
/*打印LED灯状态信息*/
void led_state_printf(unsigned long uindex[4]){
    
    
    int i =0;
    for(; i<4 ; i++){
    
    
        if(uindex[i] ==0){
    
    
            printf("LED%d灯为开。\n",i+1);
        }
        else {
    
    
            printf("LED%d灯为关。\n",i+1);
        }
    }
}

int main(int argc,char * argv[]){
    
    
    int fp = open(argv[1],O_RDWR);
    unsigned long uindex[4];
    int argv_3;
    if(fp <0){
    
    
        printf ("文件打开失败!!!\n");
        return 0;
    }
    /*
        判断输入胡灯的编号是否正确,只有正确时,才将灯的编号保存到数组中
   */
    if(argc == 4) {
    
    
        argv_3=strtoul(argv[3],NULL,0);
        if((argv_3> 4) || argv_3< 1) {
    
    
            printf("LED灯编号为:1~4\n");
            return -1;
        }
       uindex[0] = argv_3;
    }
    //当用户需要查看LED状态时执行
    if((argc == 3) && (!strcmp(argv[2],"state"))){
    
    
        ioctl(fp,LED_STATE,uindex);
        led_state_printf(uindex);
    }
    //当用户需要打开LED灯时执行
   else if((argc ==4) && (!strcmp(argv[2],"on"))){
    
    
        ioctl(fp,LED_ON,uindex);
    }
    //当用户需要关闭LED灯时执行
    else if((argc ==4) && (!strcmp(argv[2],"off"))){
    
    
        ioctl(fp,LED_OFF,uindex);
    }
    //当用户输入的命令错误时,打印提示信息
    else{
    
    
        printf("命令错误:\n");
        printf("         comm <char_dev_name> <on | off> <led_num>\n");
        printf("         comm <char_dev_name> <state> \n");
        return -1;
    }
    return 0;
}

Cuatro, prueba

/drivers/test # insmod mymisc_dev.ko 
/drivers/test # ./a  /dev/misc_dev_led on 1
/drivers/test # ./a  /dev/misc_dev_led on 2
/drivers/test # ./a  /dev/misc_dev_led on 4
/drivers/test # ./a  /dev/misc_dev_led state
LED1灯为开。
LED2灯为开。
LED3灯为关。
LED4灯为开。
/drivers/test # ./a  /dev/misc_dev_led off 2
/drivers/test # ./a  /dev/misc_dev_led state
LED1灯为开。
LED2灯为关。
LED3灯为关。
LED4灯为开。

Supongo que te gusta

Origin blog.csdn.net/weixin_47273317/article/details/107884565
Recomendado
Clasificación