使用结构体 file_operations封装驱动设备的操作

Posted xiaohujian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用结构体 file_operations封装驱动设备的操作相关的知识,希望对你有一定的参考价值。

最近学习到了Linux驱动章节的课程,对设备的对应驱动的注册有些困惑,看了下发现是把设备的所有操作方法封装到结构体 file_operations 中,这个结构体为所有的设备文件都提供了统一的操作函数接口。然后把这个结构体连同设备的主设备号、名字(没啥用)一起,通过函数 register_chrdev(0, "first_drv", &first_drv_fops) 注册驱动模块到内核的字符设备数组chrdev的第xx项,具体注册和使用方法和裸机LCD及LCD控制器的一模一样!
 
使用的都是以面向对象的思维,结构化编程的思想。
 
1. 驱动程序使用如下:
 1 /*
 2 2018-10-18
 3 功能: 第一个驱动程序;
 4 */
 5 
 6 #include <linux/module.h>
 7 #include <linux/kernel.h>
 8 #include <linux/fs.h>
 9 #include <linux/init.h>
10 #include <linux/delay.h>
11 #include <asm/uaccess.h>
12 #include <asm/irq.h>
13 #include <asm/io.h>
14 #include <asm/arch/regs-gpio.h>
15 #include <asm/hardware.h>
16 
17 static int first_drv_open(struct inode * inode, struct file *file)
18 {
19     printk("first_drv_open
");
20 }
21 
22 static ssize_t first_drv_write(struct file *file, const char __usr *buf, size_t count, loff_t * ppos)
23 {
24     printk("first_drv_write
");
25 }
26 
27 static struct file_operations first_drv_fops =
28 {
29     .owner = THIS_MODULE,
30     .open  = first_drv_open,
31     .write = first_drv_write
32 };
33 
34 int major;
35 static int first_drv_init(void)
36 {
37     major = register_chrdev(0, "first_drv", &first_drv_fops);
38     firstdrv_class = class_create(THIS_MODULE, "firstdrv");
39     first_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz");
40     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
41     gpfdat = gpfcon + 1;
42     return 0;
43 }
44 
45 static void first_drv_exit(void)
46 {
47     unregister_chrdev(major, "first_drv");
48     class_device_unregister(firstdrv_class_dev);
49     class_destroy(firstdrv_class);
50 }
51 
52 module_init(first_drv_init);
53 module_exit(first_drv_exit);
54 MODULE_LICENSE("GPL");

 2.文件lcd.h如下:

 1 #ifndef _LCD_H
 2 #define _LCD_H
 3 
 4 
 5 enum {
 6     NORMAL = 0,
 7     INVERT = 1,
 8 };
 9 
10 /* NORMAL : 正常极性
11  * INVERT : 反转极性
12  */
13 typedef struct pins_polarity {
14     int de;    /* normal: 高电平时可以传输数据 */
15     int pwren; /* normal: 高电平有效 */
16     int vclk;  /* normal: 在下降沿获取数据 */
17     int rgb;   /* normal: 高电平表示1 */
18     int hsync; /* normal: 高脉冲 */
19     int vsync; /* normal: 高脉冲 */
20 }pins_polarity, *p_pins_polarity;
21 
22 typedef struct time_sequence {
23     /* 垂直方向 */
24     int tvp; /* vysnc脉冲宽度 */
25     int tvb; /* 上边黑框, Vertical Back porch */
26     int tvf; /* 下边黑框, Vertical Front porch */
27 
28     /* 水平方向 */
29     int thp; /* hsync脉冲宽度 */
30     int thb; /* 左边黑框, Horizontal Back porch */
31     int thf; /* 右边黑框, Horizontal Front porch */
32 
33     int vclk;
34 }time_sequence, *p_time_sequence;
35 
36 
37 typedef struct lcd_params {
38     char *name;
39     
40     /* 引脚极性 */
41     pins_polarity pins_pol;
42     
43     /* 时序 */
44     time_sequence time_seq;
45     
46     /* 分辨率, bpp */
47     int xres;
48     int yres;
49     int bpp;
50     
51     /* framebuffer的地址 */
52     unsigned int fb_base;
53 }lcd_params, *p_lcd_params;
54 
55 void get_lcd_params(unsigned int *fb_base, int *xres, int *yres, int *bpp);
56 
57 #endif /* _LCD_H */

3.文件lcd_4.3.c如下:

#include "lcd.h"

#define LCD_FB_BASE 0x33c00000

lcd_params lcd_4_3_params = {
    .name = "lcd_4.3",
    .pins_pol = {
        .de    = NORMAL,    /* normal: 高电平时可以传输数据 */
        .pwren = NORMAL,    /* normal: 高电平有效 */
        .vclk  = NORMAL,    /* normal: 在下降沿获取数据 */
        .rgb   = NORMAL,    /* normal: 高电平表示1 */
        .hsync = INVERT,    /* normal: 高脉冲 */
        .vsync = INVERT,     /* normal: 高脉冲 */
    },
    .time_seq = {
        /* 垂直方向 */
        .tvp=    10, /* vysnc脉冲宽度 */
        .tvb=    2,  /* 上边黑框, Vertical Back porch */
        .tvf=    2,  /* 下边黑框, Vertical Front porch */

        /* 水平方向 */
        .thp=    41, /* hsync脉冲宽度 */
        .thb=    2,  /* 左边黑框, Horizontal Back porch */
        .thf=    2,  /* 右边黑框, Horizontal Front porch */

        .vclk=    9,  /* MHz */
    },
    .xres = 480,
    .yres = 272,
    .bpp  = 32,  /* 16, no 24bpp */
    .fb_base = LCD_FB_BASE,
};


void lcd_4_3_add(void)
{
    register_lcd(&lcd_4_3_params);
}

 

 

链接: https://www.jb51.net/article/37246.htm
本篇文章是对C语言中结构体的初始化进行了详细的分析介绍,需要的朋友参考下
 
《代码大全》建议在变量定义的时候进行初始化,但是很多人,特别是新人对结构体或者结构体数组定义是一般不会初始化,或者不知道怎么初始化。
1、初始化
复制代码代码如下:

typedef struct _TEST_T {
        int i;
        char c[10];
}TEST_T;
TEST_T gst  = {1, “12345”};//可以初始化,设置i为1,s为一个字符串.
TEST_T gst  = {1};//初始化个数少于实际个数时,只初始化前面的成员。
TEST_Tgst  = {.c=“12345”};//有选择的初始化成员。

2、复合字面量。
gst = (TEST_T){122, "1256"};//这是一个赋值语句,也可以作为初始化。可以出现在程序的任何地方。
当然也可以使用复合字面量来初始化:
gst = (TEST_T){.i=122, .c="123"};
3、结构体数组
可以用多个大括号括起来:
TEST_T gst[10] = {{},{},{},{}}
也可以初始化其中的一个元素:
TEST_T gst[10] = {[2]={}, [3]={}}
也可以使用复合字面量:
TEST_T gst[10] = {[2].i=0, [3].i={}}
为什么要初始化:
1、对局部变量初始化可以防止随机值产生的危害。
2、对全局变量初始化可以告诉编译器,这是一个定义,而不是一个声明。(如果两个c中有相同的全局变量定义,且没有初始化,编译器会认为第二个是声明而不是定义。)























以上是关于使用结构体 file_operations封装驱动设备的操作的主要内容,如果未能解决你的问题,请参考以下文章

Linux驱动开发file_operations结构体

驱动中重要的三个结构体介绍:struct inodestruct filestruct file_operations

字符设备驱动之结构体

驱动01.LED

2.制作第一个驱动程序

基于分层思想的驱动程序软件框架