小松之LINUX 驱动学习笔记(二)

这两天一直在看字符驱动那块,后来从网上找啦几个例子,自己编译啦下,安装啥的都挺正常,就是用测试程序测试的时候总出问题,现在找到一个能测试的代码,自己先看看和原来的那个代码有啥不同,后面会继续更新,说下到底是啥问题导致驱动不能用。先附上能用代码的链接,这里先谢谢作者:

http://blog.chinaunix.net/uid-22666248-id-3052861.html

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>//kmalloc
#include <linux/vmalloc.h>//vmalloc()
#include <linux/types.h>//ssize_t
#include <linux/fs.h>//file_operaiotns
#include <linux/uaccess.h>//copy_from_user

#define MEM_MALLOC_SIZE 4096 ////缓冲区大小
#define MEM_MAJOR    240 ////主设备号
#define MEM_MINOR    0

char *mem_spvm = NULL; ////缓冲区指针,指向内存区
struct cdev *mem_cdev = NULL; //字符设备对象指针
struct class *mem_class = NULL; //设备类指针

static int __init mem_init(void);
static void __exit mem_exit(void);
static int mem_open(struct inode *inode,struct file *filp);
static int mem_release(struct inode *inode, struct file *filp);
static ssize_t mem_read(struct file *filp,char __user *buf,size_t count,loff_t *fpos);
static ssize_t mem_write(struct file *filp, char __user *buf,size_t count ,loff_t *fops);

static const struct file_operations mem_fops={
    .owner = THIS_MODULE,
    .open = mem_open,
    .release = mem_release,
    .read = mem_read,
    .write = mem_write,
};

static int __init mem_init(void)
{
    int ret;
    //创建设备号 主次设备号
    int devno = MKDEV(MEM_MAJOR,MEM_MINOR);
    printk("mem_init initial...
");

    //开辟内核内存缓冲区
    mem_spvm = (char *)vmalloc(MEM_MALLOC_SIZE);
    if(mem_spvm == NULL)
    {
        printk("vmalloc mem_spvm error
");
        return -ENOMEM;//
    }
    
    //
    mem_cdev = cdev_alloc();
    if(mem_cdev == NULL)
    {
        printk("cdev_alloc error
");
        return -ENOMEM;
    }
    cdev_init(mem_cdev,&mem_fops);
    mem_cdev->owner = THIS_MODULE;
    ret = cdev_add(mem_cdev,devno,1);//将字符设备键入内核系统
    if(ret)
    {
        cdev_del(mem_cdev);
        mem_cdev = NULL;
        printk("cdev_add error
");
        return -1;
    }

    //
    mem_class = class_create(THIS_MODULE,"ywx_class_char");
    if(IS_ERR(mem_class))
    {
        printk("class_create error..
");
        return -1;
    }
    device_create(mem_class,NULL,MKDEV(MEM_MAJOR,MEM_MINOR),NULL,"ywx_device_char");
    
    printk("init finished..
");
    return 0;
}

static void __exit mem_exit(void)
{
    printk("mem_exit starting..
");
    if(mem_cdev != NULL)
        cdev_del(mem_cdev);
    printk("cdev_del ok
");

    device_destroy(mem_class,MKDEV(MEM_MAJOR,MEM_MINOR));
    class_destroy(mem_class);

    if(mem_spvm != NULL)
        vfree(mem_spvm);

    printk("vfree ok
");
    printk("mem_exit finished..
");
}

static int mem_open(struct inode *inode,struct file *filp)
{
    printk("open vmalloc space..
");
    try_module_get(THIS_MODULE);//模块引用计数器自加
    printk("open vamlloc space ok..
");
    return 0;
}
static int mem_release(struct inode *inode, struct file *filp)
{
    printk("close vmalloc space..
");
    module_put(THIS_MODULE);//模块引用计数器自减
    return 0;
}
static ssize_t mem_read(struct file *filp,char __user *buf,size_t count,loff_t *fpos)
{
    int ret = -1;
    char *tmp;
    printk("copy data to the user space
");
    tmp = mem_spvm;
    if(count > MEM_MALLOC_SIZE)
        count = MEM_MALLOC_SIZE;
    if(tmp != NULL)//将内核数据写入到用户空间
        ret = copy_to_user(buf,tmp,count);
    if(ret == 0)
    {
        printk("read copy data success
");
        return count;
    }
    else
    {
        printk("read copy data error
");
        return 0;
    }
}
static ssize_t mem_write(struct file *filp, char __user *buf,size_t count ,loff_t *fops)
{
    int ret = -1;
    char *tmp;
    printk("read data from the user space.
");
    tmp = mem_spvm;
    if(count > MEM_MALLOC_SIZE)
        count = MEM_MALLOC_SIZE;
    if(tmp != NULL)
        ret = copy_from_user(tmp,buf,count);
    if(ret == 0)
    {
        printk("write copy data success.
");
        return count;
    }
    else
    {
        printk("write copy data error.
");
        return 0;    
    }
}

MODULE_LICENSE("GPL");
module_init(mem_init);
module_exit(mem_exit);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>//memset()

int main(int argc, char *argv[])
{
    int fd,cnt;
    char buf[256];
    int i;
    printf("char device testing..
");
    fd = open("/dev/ywx_device_char",O_RDWR);
    if(fd == 0)
    {
        printf("open failed.
");
        return 1;
    }
    
    printf("input the data for kernel:");
    scanf("%s",buf);
    cnt = write(fd,buf,256);
    if(cnt == 0)
        printf("write error
");
    
    printf("clear buf,and will read from kernel...
");
    for(i=0;i<256;i++)
        buf[i] = 32;//32 =" "

    cnt = read(fd,buf,256);
    if(cnt > 0)
        printf("read data from kernel is:%s
",buf);
    else
        printf("read data error
");
    close(fd);
    printf("close app..
");
    return 0;
}

运行的时候用root用户运行,可以看到/dev目录下有设备节点,然后运行test文件,可以看到能运行。

make;sudo insmod xxx.ko; sudo ./app

原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3688424.html