首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

简单的字符设备驱动带代码

简单的字符设备驱动带代码

本帖最后由 sunplusedu2012a 于 2013-5-28 19:35 编辑

#include "common.h"

    #include <linux/slab.h>

    #define BUFFSIZE 200

    int g_COUNT = 0;

    struct my_cdev

    {

    struct cdev *cdev;

    unsigned char buf[BUFFSIZE];

    };

    struct mydevices

    {

    dev_t dev;

    struct my_cdev cdev;

    };

    struct mydevices * my_dev = NULL;

    static int my_open(struct inode * inode, struct file * filp)

    {

    printk("%s ==>\n", __FUNCTION__);

    filp->private_data = &my_dev->cdev; /*这样可以通过文件私有数据指针得到设备结构体*/

    printk("%s <==\n", __FUNCTION__);

    return 0;

    }

    int my_cdev_release( struct inode *node, struct file *filp )

    {

    return 0;

    }

    static ssize_t my_read(struct file * filp, char __user * usr, size_t size, loff_t * loff)

    {

    unsigned long p = *loff; /*文件当前位置*/

    unsigned int count = size; /*要读取的长度*/

    int ret = 0;

    if (filp == NULL || usr == NULL || loff == NULL)

    {

    return -EINVAL;

    }

    printk("%s ==>\n", __FUNCTION__);

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, size, *loff);

    struct my_cdev * dev = filp->private_data;

    if (size > g_COUNT)

    {

    size = g_COUNT;

    }

    printk("%s --> size: %d.\n", __FUNCTION__, size);

    if (p >= BUFFSIZE)

    return count ? -ENXIO:0;

    if ( copy_to_user(usr, (void *)(dev->buf + p), size) )

    {

    ret = -EFAULT;

    }

    else

    {

    *loff += size;

    ret = size;

    g_COUNT -= size;

    }

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, size, *loff);

    printk("%s <==\n", __FUNCTION__);

    return ret;

    }

    static ssize_t my_write(struct file * filp, const char __user * usr, size_t size, loff_t *loff)

    {

    unsigned long p = *loff; /*文件当前位置*/

    unsigned int count = size; /*要读取的长度*/

    int len = 0;

    int ret = 0;

    printk("%s ==>\n", __FUNCTION__);

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, size, *loff);

    if (filp == NULL || usr == NULL || loff == NULL)

    {

    return -EINVAL;

    }

    if (BUFFSIZE - g_COUNT < size)

    {

    len = BUFFSIZE - g_COUNT;

    }

    else

    len = size;

    struct my_cdev * dev = filp->private_data;

    if (p >= BUFFSIZE)

    return count ? -ENXIO:0;

    if (copy_from_user(dev->buf + p, usr, len))

    {

    ret = -EFAULT;

    }

    else

    {

    *loff += len;

    ret = len;

    }

    g_COUNT += len;

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, size, len);

    printk("%s <==\n", __FUNCTION__);

    return ret;

    }

    static loff_t my_lseek(struct file * filp, loff_t offset, int org)

    {

    loff_t ret;

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, org, offset);

    if (!filp)

    return -EINVAL;

    switch(org)

    {

    case 0:

    if(offset > BUFFSIZE || offset < 0)

    {

    return -EINVAL;

    }

    filp->f_pos = offset;

    ret = filp->f_pos;

    break;

    default:

    if (offset+org < 0 || (offset > (BUFFSIZE-org)))

    {

    return -EINVAL;

    }

    filp->f_pos = offset + org;

    break;

    }

    printk("%s --> size: %d, loff: %d.\n", __FUNCTION__, org, offset);

    return ret;

    }

    static struct file_operations my_cdev_fops =

    {

    .owner = THIS_MODULE,

    .open = my_open,

    .read = my_read,

    .write = my_write,

    .release = my_cdev_release,

    .llseek = my_lseek,

    };

    static int alloc_dev(dev_t *dev, unsigned int num, char * name)

    {

    printk("%s ==>\n", __FUNCTION__);

    if (dev == NULL || num ==0 || name == NULL)

    {

    printk("dev: %p, num: %d, name: %s.\n", dev, num, name);

    return -EINVAL;

    }

    int ret;

    dev_t ldev;

    ret = alloc_chrdev_region(&ldev, 0, num, name);

    *dev = ldev;

    printk("%s:%d <==\n", __FUNCTION__, ret);
    return ret;

    }

    static int reg_dev(struct mydevices * dev)

    {

    printk("%s <==\n", __FUNCTION__);

    if (dev == NULL)

    {

    return -EINVAL;

    }

    int ret;

    struct my_cdev * cdev = &dev->cdev;

    memset(cdev->buf, 0, BUFFSIZE);

    cdev_init( cdev->cdev, &my_cdev_fops );

    cdev->cdev->owner = THIS_MODULE;

    cdev->cdev->ops = &my_cdev_fops; /*我认为在cdev_init里应该做过赋值,应该可以不用写*/

    ret = cdev_add( cdev->cdev, dev->dev, 1 );

    printk("%s:%d ==>\n", __FUNCTION__, ret);

    return ret;

    }

    static int __init dev_init(void)

    {

    int ret;

    printk("%s <==\n", __FUNCTION__);

    my_dev = kmalloc(sizeof(struct mydevices), GFP_KERNEL);

    (&(my_dev->cdev))->cdev = cdev_alloc();

    if (!my_dev)

    {

    return  -ENOMEM;

    }

    if ((ret = alloc_dev(&my_dev->dev, 1, "mydev")) < 0)

    {

    printk("error alloc cdev %d.\n", ret);

    return ret;

    }

    if (ret = reg_dev(my_dev))

    {

    printk("error register cdev %d.\n", ret);

    goto init_failed;

    }

    printk("%s ==>\n", __FUNCTION__);

    return 0;

    init_failed:

    unregister_chrdev_region(my_dev->dev, 1);

    return ret;

    }

    static void __exit dev_exit(void)

    {

    printk("Goodbye kernel.\n");

    cdev_del(&my_dev->cdev.cdev);

    unregister_chrdev_region(my_dev->dev, 1);

    kfree(my_dev);

    }

    module_init(dev_init);

    module_exit(dev_exit);

    // http://hi.baidu.com/yyangjjun/item/95b09c32067fbe1c9cc65eb9

    2. 用户层测试代码。

    首先得到主设备号。

    cat /proc/devicesCharacter devices:

    1 mem

    4 /dev/vc/0

    4 tty

    4 ttyS

    5 /dev/tty

    5 /dev/console

    5 /dev/ptmx

    5 ttyprintk

    6 lp

    7 vcs

    10 misc

    13 input

    21 sg

    29 fb

    81 video4linux

    99 ppdev

    108 ppp

    116 alsa

    128 ptm

    136 pts

    180 usb

    189 usb_device

    195 nvidia

    250 mydev

    251 hidraw

    252 usbmon

    253 bsg

    254 rtc

    sudo mknod mydev0 c 250 0

    usr.c

    #include <stdio.h>

    #include <fcntl.h>

    #include <string.h>

    #include <sys/stat.h>

    #define BUFFERSIZE 200

    int main()

    {

    int fp = 0 , fp2;

    int ret ;

    char str[BUFFERSIZE];

    memset(str, 0, BUFFERSIZE);

    fp = open( "/dev/mydev1", O_RDWR);

    if ( fp < 0 )

    {

    printf("Open device failed\n");

    return -1;

    }

    ret = write( fp, "Hello, my devices", strlen("Hello, my devices") );

    printf("w: %d.\n", ret);

    lseek( fp, 0, 0 );/*修改字符设备里字符数组的位置,将字符数据位置设到开始的位置,不然下面的read操作将读不到数据*/

    ret = read( fp2, str, BUFFERSIZE );

    printf("Read content:%d, %s\n",ret, str );

    #if 0

    ret = write( fp, "Hello, my devices", strlen("Hello, my devices") );

    printf("w: %d.\n", ret);

    lseek( fp, 0, 0 );/*修改字符设备里字符数组的位置,将字符数据位置设到开始的位置,不然下面的read操作将读不到数据*/

    ret = read( fp, str, BUFFERSIZE );

    printf("Read content:%d, %s\n",ret, str );

    #endif

    close(fp);

    return 0;

    }

    gcc -o a usr.c

    sudo ./a

    w: 17.

    Read content:17, Hello, my devices

    结果显示:
    可参考:http://emb.sunplusedu.com/answer/
返回列表