简单的字符设备()

来源:互联网 发布:企业名录软件代理 编辑:程序博客网 时间:2024/06/04 19:32


一:  内核程序。

// 这个是基本的。
#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() ;
}



0 0