分类

linux驱动框架程序初始化总结

浏览量:169 日期:2014-07-11 08:55:00
内容介绍

一.驱动框架

初始化:insmod 加载

     1.确定主设备号:

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

 

    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 结构:结构成员对应相应的处理函数:

 

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连接在一起,

 

	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 卸载 代码实现如下:

 

 

	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);

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

 

#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 4static 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 测试代码:

 

 

#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;}

相关阅读
手机版 | 电脑版
Copyright @ 2021 豆豆系统