标题:
简单的字符设备驱动带代码
[打印本页]
作者:
sunplusedu2012a
时间:
2013-5-28 19:34
标题:
简单的字符设备驱动带代码
本帖最后由 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/
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0