看了前面那些文邹邹的文字,看得就不舒服,相信大家也一样。所以今天就把代码贴一下,以供大家更
好理解,同时也希望各位大侠多多指点指点,我将不胜感激。
那我们如何验证自己所写的驱动程序功能,那就得看看我们实现了哪些模块了。后面我将为大家演示下
面代码在S3C2440开发板的实验结果。
一、源程序,这是一个实验程序而已,以后会慢慢完善其功能。俗话说的好:麻雀虽小,五脏俱全。希
望这个小小实验能带给大家兴趣。
这是chrdev.h文件
- #ifndef __CHRDEV_H__
- #define __CHRDEV_H__
- #include <linux/cdev.h>
- #include <linux/wait.h>
- #ifndef DEV_SIZE
- #define DEV_SIZE 4096
- #endif
- struct own_dev
- {
- bool data_flag;
- char *p_cdata;
- size_t size;
- //wait_queue_head_t inq;
- struct cdev cdev;
- };
- int chr_open(struct inode *inode, struct file *filp);
- int chr_release(struct inode *inode, struct file *filp);
- ssize_t chr_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
- ssize_t chr_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
- #endif
这是chrdev.c文件
- /******************************************************************************
- *
- * Copyright (C), 2012, XXX有限公司 All rights reserved.
- * @file chrdev.c
- * @brief 实现char devive设备驱动
- *
- * @version 1.0.0
- * @author cyycyh
- * @date 2012-04-02
- * @section history
- * \<author\>\<time\>\<version\>\<desc\>
- * @li cyycyh 20120402 1.0.0 创建
- *
- ******************************************************************************/
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/moduleparam.h>
- #include <linux/fcntl.h>
- #include <linux/stat.h>
- #include <linux/gfp.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <asm/uaccess.h>
- #include <linux/kdev_t.h>
- #include <linux/device.h>
- #include <linux/sched.h>
- #include <linux/version.h>
- #include <linux/utsrelease.h>
- #include <linux/string.h>
- #include "chrdev.h"
- #define DRIVE_NAME "chrdev"
- struct own_dev *p_chr_dev = NULL;
- struct class *p_chr_class = NULL; // 设备类 /sys/class
- struct device *p_chr_device = NULL; // hello的设备结构
- int chr_major = 255; // 主设备号变量
- int chr_minor = 0; // 次设备号变量
- struct file_operations chr_fops =
- {
- open: chr_open,
- read: chr_read,
- write: chr_write,
- release: chr_release,
- };
- /*
- * 模块参数,以供参数输入使用
- */
- module_param(chr_major, int, S_IRUGO);
- module_param(chr_minor, int, S_IRUGO);
- /*
- * @brief 打开设备
- * @param[in] inode 文件节点
- * @param[out] filp 文件结构
- * @return @li 0
- */
- int chr_open(struct inode *inode, struct file *filp)
- {
- /**获取自己数据结构**/
- struct own_dev *dev;
- dev = container_of(inode->i_cdev, struct own_dev, cdev);
- filp->private_data = dev;
-
- /**判断文件读取模式**/
- if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
- {
- printk(KERN_ALERT"cyycyh\n");; //...应该做什么操作哦
- }
- //MOD_INC_USE_COUNT; //?为何会报错
- printk(KERN_ALERT"chrdev open\n");
-
- return 0;
- }
- EXPORT_SYMBOL(chr_open);
- /*
- * @brief 释放chrdev设备资源
- * @param[in] inode 文件节点
- * @param[out] filp 文件结构
- * @return @li 0
- */
- int chr_release(struct inode *inode, struct file *filp)
- {
- //MOD_DEC_USE_COUNT;
- return 0;
- }
- /*
- * @brief 读设备
- * @param[in] filp 文件结构
- * @param[in] count 读数据的字节数
- * @param[out] buf 输出数据的缓冲区
- * @param[in|out] f_pos 文件指针的位置
- * @return 读取的数据量
- * @li >= 0 读取的字节数目
- * @li < 0 错误码
- */
- ssize_t chr_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- {
- struct own_dev *dev =(struct own_dev *) filp->private_data;
- ssize_t ret = 0;
-
- /**判断是否读有效**/
- if (*f_pos > dev->size)
- {
- ret = -EFAULT;
- goto read_out;
- }
- if (*f_pos + count > dev->size)
- {
- count = dev->size - *f_pos;
- }
-
- //printk(KERN_ALERT"read : %s \n", dev->p_cdata);
-
- /**读取数据到用户空间**/
- if (NULL == dev->p_cdata)
- {
- printk(KERN_ALERT"no data to read !\n");
- goto read_out;
- }
- /*
- while (!dev->data_flag) //为何用while 而非if
- {
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- // wait_event_interruptible(dev->inq, dev->data_flag);
- }
- */
- if (copy_to_user(buf, dev->p_cdata, count))
- {
- ret = -EFAULT;
- goto read_out;
- };
-
- *f_pos += count;
- ret = count;
-
- /*为何要做这样的判断*/
- if (dev->p_cdata[count] == '\0')
- {
- ret = 0;
- }
- read_out :
- printk(KERN_ALERT"read over!\n");
- return ret;
- }
- EXPORT_SYMBOL(chr_read);
- /*
- * @brief 写chr设备
- * @param[in] filp 文件结构
- * @param[in] count 读数据的字节数
- * @param[in] buf 输出数据的缓冲区
- * @param[in|out] f_pos 文件指针的位置
- * @return 写出结果
- * @li >= 0 写入的字节数量
- * @li < 0 错误码
- */
- ssize_t chr_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
- {
- struct own_dev *dev =(struct own_dev *)filp->private_data;
- ssize_t ret = -ENOMEM; //why -ENOMEM
-
- /**判断是否写有效**/
-
- if (*f_pos > dev->size)
- {
- goto write_out;
- }
- /*//为何会无限循环
- if (*f_pos + count >= dev->size)
- {
- count = dev->size - *f_pos;
- }
- */
- /**从用户空间写数据到内核**/ //为何要count + 1呢?
- dev->p_cdata = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
- if (NULL == dev->p_cdata)
- {
- printk(KERN_ALERT"no RAM to write\n");
- goto write_out;
- }
-
- dev->size = (count + 1) * sizeof(char);
- if (copy_from_user(dev->p_cdata, buf, count))
- {
- ret = -EFAULT;
- goto write_out;
- };
- dev->p_cdata[count] = '\0'; //记住:结束符
-
- // printk(KERN_ALERT"write : %s \n", dev->p_cdata);
-
- *f_pos += count;
- ret = count;
-
- // dev->data_flag = 1;
- // wake_up(&(dev->inq));
-
- write_out :
- printk(KERN_ALERT"write over !\n");
-
- return ret;
- }
- EXPORT_SYMBOL(chr_write);
- /*
- * @brief chr驱动初始化
- */
- static int __init chr_init(void)
- {
- dev_t dev_no;
- int err = 0;
-
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
- printk(KERN_ALERT"UTS_RELEASE=%s\n", UTS_RELEASE);
- #endif
- printk(KERN_ALERT"Char dev!\n");
-
- // 注册设备号
- if (chr_major != 0)
- {
- dev_no = MKDEV(chr_major, chr_minor);
- err = register_chrdev_region(dev_no, 1, DRIVE_NAME);
- }
- else
- {
- err = alloc_chrdev_region(&dev_no, chr_minor, 1, DRIVE_NAME);
- chr_major = MAJOR(dev_no);
- }
- if (err < 0)
- {
- printk(KERN_WARNING"hello: can't get major %d\n", chr_major);
- goto dev_no_fail;
- }
- /**初始化数据结构**/
- /*
- *1、分配cdev 动态或者静态
- *2、初始化cdev
- *3、注册cdev即通知内核
- */
- p_chr_dev = kmalloc(sizeof(struct own_dev), GFP_KERNEL);
- if (NULL == p_chr_dev)
- {
- printk(KERN_WARNING"own_dev can't kmalloc \n");
- goto kmalloc_fail;
- }
- // init_waitqueue_head(&(p_chr_dev->inq));
- p_chr_dev->data_flag = 0;
- p_chr_dev->p_cdata = NULL;
- p_chr_dev->size = 0;
- cdev_init(&p_chr_dev->cdev, &chr_fops);
- p_chr_dev->cdev.owner = THIS_MODULE;
- p_chr_dev->cdev.ops = &chr_fops;
- err = cdev_add(&p_chr_dev->cdev, dev_no, 1);
- if (err)
- {
- printk(KERN_WARNING "chr: error %d adding led", err);
- goto cdev_add_fail;
- }
-
- // 创建设备类 /sys/class
- /*
- *创建之后用IS_ERR判断是否有错
- *若错用PTR_ERR获取错误码
- */
- p_chr_class = class_create(THIS_MODULE, DRIVE_NAME);
- if (IS_ERR(p_chr_class))
- {
- printk(KERN_WARNING"chr: can't create class %ld\n", PTR_ERR(p_chr_class));
- goto class_fail;
- }
- p_chr_device = device_create(p_chr_class, NULL, dev_no, NULL, DRIVE_NAME);
- if (IS_ERR(p_chr_device))
- {
- printk(KERN_WARNING "chr: create device fail, error code %ld", PTR_ERR(p_chr_device));
- goto device_fail;
- }
- else
- {
- goto exit_ok;
- }
- device_fail:
- class_destroy(p_chr_class);
- class_fail:
- cdev_del(&p_chr_dev->cdev);
- cdev_add_fail:
- kfree(p_chr_dev);
- kmalloc_fail:
- unregister_chrdev_region(dev_no, 1);
- dev_no_fail:
-
- exit_ok:
- return 0;
- }
- /*
- * @brief chr驱动退出
- */
- static void __exit chr_exit(void)
- {
- dev_t dev_no = MKDEV(chr_major, chr_minor);
-
- printk(KERN_ALERT"Goodbye,chr!\n");
-
- device_destroy(p_chr_class, dev_no);
- class_destroy(p_chr_class);
- cdev_del(&p_chr_dev->cdev);
- kfree(p_chr_dev->p_cdata);
- kfree(p_chr_dev);
- unregister_chrdev_region(dev_no, 1);
- }
- module_init(chr_init);
- module_exit(chr_exit);
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("cyycyh");
- MODULE_DESCRIPTION("This module is char dev");
- MODULE_VERSION("v1.0.0");
- MODULE_ALIAS("chr_alias");
二、开发板操作
1、首先进入我们所要操作的目录:我以 /lib/modules 目录为例
cd /lib/modules/
2、下载 xxx.ko (chrdev.ko)文件至开发板
rz 或者 lrz 或者采用网络服务都可以
3、加载模块
insmod chrdev.ko
4、查看是否加载成功
lsmod
若加载成功,则会提醒:chrdev 2023 0 - Live 0xbf000000
5、前期工作都做好,这下做一些功能性测试
验证设备号,是否被注册,
cat /proc/devices
若注册成功,则有我们所申请的设备号/设备名称:
Character devices:
255 chrdev //这个就是我们所申请的设备号
1 mem
4 /dev/vc/0
4 tty
6、查看我们所创建的类是否创建成功
ls /dev/chrdev(这是在/dev 下的类,可以跟下面类名称不同,但一般采用同名称)
ls /sys/class/chrdev/chrdev/ (这是在虚拟文件系统中的类/sys/class)
cat /sys/class/chrdev/chrdev/dev (可以获得给设备的主设备号和次设备号)
7、模块参数检查
ls /sys/module/chrdev/parameters/ (查看模块参数目录)
cat /sys/module/chrdev/parameters/参数名称 (获取参数内容)
8、测试操作方法(struct file_operations)【这是简单测试,一般要写应用程序测试】
echo "字符串">/dev/chrdev (往设备写)
cat
阅读(1077) | 评论(0) | 转发(0) |