您的位置:首页 > 运维架构 > Linux

linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)

2017-09-20 20:24 507 查看
一.驱动框架

初始化:insmod 加载

1.确定主设备号:

分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:

[cpp] view plain copy

int result;

dev_t dev;

/*分配主设备号*/

if (scull_major) /*静态分配一个主设备号*/

{

dev = MKDEV(scull_major,0);

result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);

}

else /*动态分配一个主设备号*/

{

result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);

scull_major = MAJOR(dev);

}

if(result <0)

{

printk("LED:can not get major:%d\n",scull_major);

return result;

}

2.构造 file_operations 结构:结构成员对应相应的处理函数:

[cpp] view plain copy

static struct file_operations mini2440_leds_fops = {

.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open = mini2440_leds_open,

.write = mini2440_leds_write,

};

3.将相关操作告诉内核:

内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,

[cpp] view plain copy

led_class = class_create(THIS_MODULE,DEVICE_NAME);

cdev_init(&led_gpio_cdev, &mini2440_leds_fops);

result = cdev_add(&led_gpio_cdev, dev, 1);

if(result <0)

{

printk("LED:cdev_add error\n");

return result;

}

device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");

卸载驱动 rmmod 卸载 代码实现如下:

[cpp] view plain copy

dev_t dev_id = MKDEV(scull_major, 0);

/*卸载主设备号*/

unregister_chrdev_region(dev_id, LED_GPIO_SIZE);

device_destroy(led_class,MKDEV(scull_major, 0));

cdev_del(&led_gpio_cdev);

class_destroy(led_class);

最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:

[cpp] view plain copy

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <mach/io.h>

#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/device.h>

#include <linux/cdev.h>

#define DEVICE_NAME "led_1"

#define LED_GPIO_SIZE 4

static int scull_major = 0;

static struct class *led_class;

static struct cdev led_gpio_cdev[LED_GPIO_SIZE];

static int mini2440_leds_open(struct inode *inode, struct file *file)

{

int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);

printk("/dev/led%d has opened\n",minor);

return 0;

}

static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)

{

char val;

int minor = MINOR(filp->f_dentry->d_inode->i_rdev);

copy_from_user(&val, buf, 1);

printk("/dev/led%d write the val = %d\n",minor,val);

return 0;

}

static struct file_operations mini2440_leds_fops = {

.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open = mini2440_leds_open,

.write = mini2440_leds_write,

};

/*

* 执行insmod命令时就会调用这个函数

*/

static int mini2440_leds_init(void)

{

int result,i;

dev_t dev;

/*分配主设备号*/

if (scull_major) /*静态分配一个主设备号*/

{

dev = MKDEV(scull_major,0);

result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);

}

else /*动态分配一个主设备号*/

{

result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);

scull_major = MAJOR(dev);

}

if(result <0)

{

printk("LED:can not get major:%d\n",scull_major);

return result;

}

led_class = class_create(THIS_MODULE,DEVICE_NAME);

if (IS_ERR(led_class)) {

return PTR_ERR(led_class);

}

for (i=0; i<LED_GPIO_SIZE;i++)

{

cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops);

result = cdev_add(&led_gpio_cdev[i], (dev+i), 1);

if(result <0)

{

printk("LED:cdev_add error\n");

return result;

}

device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i);

}

return 0;

}

/*

* 执行rmmod命令时就会调用这个函数

*/

static void mini2440_leds_exit(void)

{

int i;

dev_t dev_id = MKDEV(scull_major, 0);

/*卸载主设备号*/

unregister_chrdev_region(dev_id, LED_GPIO_SIZE);

for(i=0;i<LED_GPIO_SIZE;i++)

{

device_destroy(led_class,MKDEV(scull_major, i));

cdev_del(&led_gpio_cdev[i]);

}

class_destroy(led_class);

}

/* 这两行指定驱动程序的初始化函数和卸载函数 */

module_init(mini2440_leds_init);

module_exit(mini2440_leds_exit);

/* 描述驱动程序的一些信息,不是必须的 */

MODULE_LICENSE("GPL");

linux 测试代码:

[cpp] view plain copy

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

/*

* ledtest <dev> <on|off>

*/

void print_usage(char *file)

{

printf("Usage:\n");

printf("%s <dev> <on|off>\n",file);

printf("eg. \n");

printf("%s /dev/led0 a\n", file);

printf("%s /dev/led1 b\n", file);

printf("%s /dev/led2 c\n", file);

printf("%s /dev/led3 d\n", file);

}

int main(int argc, char **argv)

{

int fd;

char* filename;

char val;

if (argc != 3)

{

print_usage(argv[0]);

return 0;

}

filename = argv[1];

fd = open(filename, O_RDWR);

if (fd < 0)

{

printf("error, can't open %s\n", filename);

return 0;

}

if (!strcmp("a", argv[2]))

{

val = 10;

write(fd, &val, 1);

}

else if (!strcmp("b", argv[2]))

{

val = 11;

write(fd, &val, 1);

}

else if (!strcmp("c", argv[2]))

{

val = 12;

write(fd, &val, 1);

}

else if (!strcmp("d", argv[2]))

{

val = 13;

write(fd, &val, 1);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: