linux驱动学习-3th

来源:互联网 发布:风机scada数据与故障 编辑:程序博客网 时间:2024/05/22 03:12

字符类驱动程序,大致的框架:

1. init中要做的事:
  1)分配设备号,major为0动态分配,不为0手工指定
  2)字符设备文件的注册,关联file_operation 结构体到cdev上
2.编写file_operation 中,几个函数,open,read,write,ioctl,release
3.exit中回滚init的操作

测代码:
1.insmod 以后,cat /proc/devices 在Character devices:可以看到led_dev 以及系统分别的主设备号253
2.手动创建一个设备节点
mknod /dev/xxx_dev c 253 0
ls /dev/xxx_dev
/*最简单字符类led驱动模版*//*[0].必须的头文件*///#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/kernel.h>/* printk() */#include <linux/slab.h>/* kmalloc() */#include <linux/fs.h>/* everything... */#include <linux/errno.h>/* error codes */#include <linux/types.h>/* size_t */#include <linux/proc_fs.h>#include <linux/fcntl.h>/* O_ACCMODE */#include <linux/seq_file.h>#include <linux/cdev.h>#include <asm/system.h>/* cli(), *_flags */#include <asm/uaccess.h>/* copy_*_user *//*********************************************************************/#define __DEBUG__#ifdef __DEBUG__#define DEBUG(format,...) printk("[%05d] ""%s:""%s. "  format "",__LINE__, __FILE__, __FUNCTION__,  ##__VA_ARGS__)#else#define DEBUG(format,...)#endif/*********************************************************************//*[1].定义设备名*/#define DEVICE_NAME "led_dev"/*[2].定义主设备号 0:动态分配 (!0):手动分配找一个kernel没有使用的*/#define DEVICE_MAJOR 0/*[3].定义次设备号个数*/#define MINOR_COUNT 1/*[4].定义自己的设备led_dev结构体(包含了基本的cdev字符设结构体)*/struct led_dev{struct cdev cdev;   /*c_dev结构体*/};/*********************************************************************//*[5].定义一个全局变量记录主设备号*/static int major = DEVICE_MAJOR;/*[6].定义起始次设备号*/static int first_minor = 0;/*[7].定义次设备号个数*/static int minor_count = MINOR_COUNT;/*[8].定义一个led_dev结构体指针,其实是一个数组*/struct led_dev *led_dev_array = NULL;/*[9].定义一个class结构体用于mdev自动创建设备结点*///struct class *led_dev_class;/*********************************************************************/static int led_dev_open(struct inode *inode,struct file *file);static int led_dev_release(struct inode *inode,   struct file *file);static ssize_t led_dev_read(struct file *file,    char __user *buf,    size_t count,    loff_t *off);static ssize_t led_dev_write(struct file *file,     char __user *buf,     size_t count,     loff_t *off);static ssize_t led_dev_ioctl(struct inode *inode,     struct file *file,     unsigned int cmd,     unsigned long arg);static int led_dev_setup_cdev(struct led_dev *mydev,   int minor_index);static int __init led_dev_init_module(void);static void __exit led_dev_cleanup_module(void);/*********************************************************************//*打开设备,对应于用户空间的open系统调用*/static int led_dev_open(struct inode *inode,struct file *file){    int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);switch(minor){case 0: /* /dev/led */printk("/dev/led opened!\n");break;case 1: /* /dev/led1 */printk("/dev/led1 opened!\n");break;case 2: /* /dev/led2 */printk("/dev/led2 opened!\n");break;case 3: /* /dev/led1 */printk("/dev/led3 opened!\n");break;}    //填充一些资源的初始化return 0;}/*关闭设备,对应于用户空间的close系统调用*/static int led_dev_release(struct inode *inode,   struct file *file){printk("%s closed!\n", DEVICE_NAME);//填充一些资源的释放return 0;}/*实现读功能,对应于用户空间的read系统调用*/static ssize_t led_dev_read(struct file *file,    char __user *buf,    size_t count,    loff_t *off){return 0;}/*实现写功能,对应于用户空间的write系统调用*/static ssize_t led_dev_write(struct file *file,     char __user *buf,     size_t count,     loff_t *off){return 0;}/*实现控制功能,对应于用户空间的ioctl系统调用*/static ssize_t led_dev_ioctl(struct inode *inode,     struct file *file,     unsigned int cmd,     unsigned long arg){return 0;}/*设置file_operations 结构体,提供给应用空间的接口*/static struct file_operations led_dev_fops ={.owner   = THIS_MODULE,.open    = led_dev_open,.release = led_dev_release,.read    = led_dev_read,.write   = led_dev_write,.ioctl   = led_dev_ioctl,};/*设备建立子函数,被led_dev_init_module函数调用*/static int led_dev_setup_cdev(struct led_dev *mydev,   int minor_index)       /*minor_index*/{int err;dev_t devno = MKDEV(major, first_minor + minor_index);cdev_init(&mydev->cdev, &led_dev_fops);mydev->cdev.owner = THIS_MODULE;           //这里要用.mydev->cdev.ops   = &led_dev_fops;         //这里要用.err = cdev_add(&mydev->cdev, devno, 1);if (err){printk("[errno = %d] Failed to add %s , minor_index=%d\n", err, DEVICE_NAME, minor_index);}return err;}/*驱动模块的初始化*/static int __init led_dev_init_module(void){int result;int i;dev_t dev_no = 0;   /*设备号 高12bits:major 低20bits:minor*//*注册设备号*/if (major) /*静态分配主设备号的注册*/{dev_no = MKDEV(major, first_minor);result = register_chrdev_region(dev_no,      /*分配设备号起始值*/        minor_count, /*请求的连续设备号的个数*/        DEVICE_NAME);/*设备号范围内关联的设备名称    *出现在/proc/devices和sysfs中*/}else  /*动态分配主设备号的注册*/{result = alloc_chrdev_region(&dev_no,     first_minor,     minor_count,    /*请求的连续设备号的个数*/     DEVICE_NAME);major = MAJOR(dev_no);/*保存动态分配的主设备号*/}if (result < 0){printk("%s : Failed to  get major %d\n", DEVICE_NAME, major);        result = -1;goto fail;  /*失败了,应该回滚前面的操作撒*/}else{DEBUG("%s : Successed to  get major %d\n", DEVICE_NAME, major);}/*字符设备文件的注册*/led_dev_array = kmalloc(minor_count * sizeof(struct led_dev), GFP_KERNEL);if (!led_dev_array){result = -ENOMEM;printk("%s : Failed to kmalloc *led_dev_array(%d * sizeof(struct %s))\n",DEVICE_NAME, minor_count, DEVICE_NAME);goto fail;  /* Make this more graceful */}memset(led_dev_array, 0, minor_count * sizeof(struct led_dev));for(i = 0; i < minor_count; i++){result = led_dev_setup_cdev(&led_dev_array[i], i);if (result < 0)goto fail;}DEBUG("%s : Successed to init!\n", DEVICE_NAME);return 0;fail:led_dev_cleanup_module();return result;}/*驱动模块的清除*/static void __exit led_dev_cleanup_module(void){int i;dev_t devno = MKDEV(major, first_minor);if (led_dev_array){for (i = 0; i < minor_count; i++){cdev_del(&led_dev_array[i].cdev);//注意是.}kfree(led_dev_array);}/* cleanup_module is never called if registering failed */unregister_chrdev_region(devno, 1);DEBUG("%s : successed to exit!\n", DEVICE_NAME);}/**/MODULE_AUTHOR("onejacky wanshijie@126.com");MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("simple cdev driver module for led");module_init(led_dev_init_module);   //insmodmodule_exit(led_dev_cleanup_module);//rmmod




0 0
原创粉丝点击