一: 内核程序。
// 这个是基本的。
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#include <linux/slab.h>
#include <linux/device.h>
#define CDEVDEMO_MAJOR 255
static int cdevdemo_major = CDEVDEMO_MAJOR;
#define MEMDEV_SIZE 4096
#define FILTER_LEN 100
struct cdevdemo_dev
{
struct cdev cdev;
char *buf ;
char *filter ;
};
struct cdevdemo_dev *cdevdemo_devp ;
int cdevdemo_open(struct inode *inode, struct file *filp)
{
filp->private_data = cdevdemo_devp;
return 0;
}
int cdevdemo_release(struct inode *inode, struct file *filp)
{
printk(KERN_NOTICE "======== cdevdemo_release ");
return 0;
}
void cdevdemo_save_data_from_kenl(char __user *buf)
{
int len = strlen(cdevdemo_devp->buf) ;
strcpy(cdevdemo_devp->buf + len, buf) ;
return ;
}
static ssize_t cdevdemo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
/*记录文件指针偏移位置*/
unsigned int count = size;
/*记录需要读取的字节数*/
int ret = 0;
/*返回值*/
struct cdevdemo_dev *dev = filp->private_data;
/*获得设备结构体指针*/
/*判断读位置是否有效*/
if (p >= MEMDEV_SIZE)
/*要读取的偏移大于设备的内存空间*/
return 0;
if (count > MEMDEV_SIZE - p)
/*要读取的字节大于设备的内存空间*/
count = MEMDEV_SIZE - p;
/*读数据到用户空间:内核空间->用户空间交换数据*/
if (copy_to_user(buf, (void*)(dev->buf + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count;
}
return ret;
}
/*写函数*/
static ssize_t cdevdemo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct cdevdemo_dev *dev = filp->private_data;
/*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= FILTER_LEN)
return 0;
if (count > FILTER_LEN - p)
/*要写入的字节大于设备的内存空间*/
count = FILTER_LEN - p;
/*从用户空间写入数据*/
if (copy_from_user(dev->filter+ p, buf, count))
ret = - EFAULT;
else
{
*ppos += count;
/*增加偏移位置*/
ret = count;
/*返回实际的写入字节数*/
}
return ret;
}
static const struct file_operations cdevdemo_fops =
{
.owner = THIS_MODULE,
.open = cdevdemo_open,
.write = cdevdemo_write,
.release = cdevdemo_release,
.read = cdevdemo_read,
};
static void cdevdemo_setup_cdev(struct cdevdemo_dev *dev, int index)
{
int err, devno ;
devno = MKDEV(cdevdemo_major, index);
printk(KERN_NOTICE "======== cdevdemo_setup_cdev 2");
/*鍒濆鍖栦竴涓瓧绗﹁澶囷紝璁惧鎵€鏀寔鐨勬搷浣滃湪cdevdemo_fops涓?/
cdev_init(&dev->cdev, &cdevdemo_fops);
printk(KERN_NOTICE "======== cdevdemo_setup_cdev 3");
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &cdevdemo_fops;
printk(KERN_NOTICE "======== cdevdemo_setup_cdev 4");
err = cdev_add(&dev->cdev, devno, 1);
printk(KERN_NOTICE "======== cdevdemo_setup_cdev 5");
if(err)
{
printk(KERN_NOTICE "Error %d add cdevdemo %d", err, index);
}
return ;
}
int cdevdemo_init(void)
{
int ret;
dev_t devno = MKDEV(cdevdemo_major, 0);
struct class *cdevdemo_class;
if(cdevdemo_major)
{
printk(KERN_NOTICE "======== cdevdemo_init 1");
ret = register_chrdev_region(devno, 1, "cdevdemo");
}
else
{
printk(KERN_NOTICE "======== cdevdemo_init 2");
ret = alloc_chrdev_region(&devno,0,1,"cdevdemo");
cdevdemo_major = MAJOR(devno);
}
if(ret < 0)
{
printk(KERN_NOTICE "======== cdevdemo_init 3");
return ret;
}
cdevdemo_devp = kmalloc(sizeof(struct cdevdemo_dev), GFP_KERNEL);
if(!cdevdemo_devp)
{
ret = -ENOMEM;
printk(KERN_NOTICE "Error add cdevdemo");
goto fail_malloc;
}
printk(KERN_NOTICE "======== cdevdemo_init 3");
memset(cdevdemo_devp,0,sizeof(struct cdevdemo_dev));
cdevdemo_devp->buf = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
if (cdevdemo_devp->buf)
{
memset(cdevdemo_devp->buf, 0, MEMDEV_SIZE);
strcpy(cdevdemo_devp->buf, "hello world [0]") ;
}
else
{
printk(KERN_NOTICE "======== cdevdemo_init 3 error \n");
}
cdevdemo_devp->filter = kmalloc(FILTER_LEN, GFP_KERNEL);
if (cdevdemo_devp->filter)
{
memset(cdevdemo_devp->filter, 0, FILTER_LEN);
strcpy(cdevdemo_devp->filter, "hello world [1]") ;
}
else
{
printk(KERN_NOTICE "======== cdevdemo_init 3 error \n");
}
cdevdemo_setup_cdev(cdevdemo_devp, 0) ;
cdevdemo_class = class_create(THIS_MODULE, "cdevdemo");
device_create(cdevdemo_class, NULL, MKDEV(cdevdemo_major, 0), NULL, "cdevdemo");
printk(KERN_NOTICE "======== cdevdemo_init 4");
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return 0 ;
}
void cdevdemo_exit(void)
{
printk(KERN_NOTICE "End cdevdemo");
cdev_del(&cdevdemo_devp->cdev);
kfree(cdevdemo_devp);
unregister_chrdev_region(MKDEV(cdevdemo_major,0),1);
}
MODULE_LICENSE("Dual BSD/GPL");
module_param(cdevdemo_major, int, S_IRUGO);
module_init(cdevdemo_init);
module_exit(cdevdemo_exit);
EXPORT_SYMBOL(cdevdemo_save_data_from_kenl) ;
二: 用户空间程序。
#define TEST_DEV_PATH "/dev/cdevdemo"
int test_fd = -1 ;
static int test_flow_stat_init(void)
{
test_fd = open(TEST_DEV_PATH, O_RDONLY);
return 0;
}
static void test_flow_stat_process(void)
{
char buf[20] = {0} ;
read(test_fd, buf, 10) ;
printf("test_flow_stat_process = %s", buf);
}
void test_uc_flow_stat_thread()
{
sleep(5);
printf("test_uc_flow_stat_thread 1\n");
test_flow_stat_init() ;
test_flow_stat_process();
printf("test_uc_flow_stat_thread 2 \n");
}
void main()
{
test_uc_flow_stat_thread() ;
}