<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > linux 一個(gè)簡(jiǎn)單的字符設備驅動(dòng)例子

linux 一個(gè)簡(jiǎn)單的字符設備驅動(dòng)例子

作者: 時(shí)間:2011-06-30 來(lái)源:網(wǎng)絡(luò ) 收藏

先包含這些頭文件
#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/system.h>
#include asm/uaccess.h>

#define BUFFERSIZE 200
#define DEVICE_MAJOR 250 /*設置一個(gè)主設備號*/


static int device_major = DEVICE_MAJOR;
定義一個(gè)與字符設備對應的結構體
struct my_cdev
{
struct cdev cdev; /*cdev結構體,與字符設備對應*/

/*下面可以定義一些與字符設備相關(guān)的數據*/
usigned char mem[BUFFERSIZE];
};

struct my_cdev *my_cdevp; /*設備結構體指針*/

int my_cdev_open( struct inode *node, struct file *filp )
{
/*將設備結構體指針賦給文件私有數據指針*/
filp->private_data = my_cdevp /*這樣可以通過(guò)文件私有數據指針得到設備結構體*/
return 0;
}

int my_cdev_release( struct inode *node, struct file *filp )
{
return 0;
}

static size_t my_cdev_read( struct file *filp, char __user *buf, size_t size, loff_t *ppos )
{
unsigned long p = *ppos; /*文件當前位置*/
unsigned int count = size; /*要讀取的長(cháng)度*/
int ret = 0;

struct my_cdev *dev = filp->private_data; /*通過(guò)文件私有數據指針得到設備結構體,和前面的open對應*/

if ( p >= BUFFERSIZE )
return count ? -ENXIO:0;
if ( count > BUFFERSIZE - p )
count = BUFFERSIZE - p;

/*內核空間->用戶(hù)空間*/
if ( copy_to_user(buf, (void *)(dev->mem + p), count) )
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
}

return ret;
}

static size_t my_cdev_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;

struce my_cdev *dev = filp->private_data;

if( p >= BUFFERSIZE )
return count ? -ENIX : 0;
if (count > BUFFERSIZE - p )
count = BUFFERSIZE - p;

if ( copy_from_user( dev->mem + p, buf, count))
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
}

return ret
}

static loff_t my_cdev_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch (orig)
{
case 0:
if ( offset 0 )
{
ret = -EINVAL;
break;
}
if (offset > BUFFERSIZE)
{
ret = -EINVAL;
break;
}
filp->f_pos = (unsigned int)offset;
ret = fips->f_pos;
break;
default:
ret = -EINVAL;
break;
}

return ret;
}

/*文件操作結構體*/
static const struct file_operstions my_cdev_fops =
{
.owner = THIS_MODULE,
.open = my_cdev_open,
.release = my_cdev_release,
.read = my_cdev_read,
.write = my_cdev_write,
.llseek = my_cdev_llseek,
};

/*初始化并注冊cdev,就是注冊我們自己的字符設備*/
static void my_cdev_setup( struct my_cdev *dev, int index )
{
int err;
dev_t devno = MKDEV(DEVICE_MAJOR, index);

cdev_init( dev->cdev, my_cdev_fops );
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = my_cdev_fops; /*我認為在cdev_init里應該做過(guò)賦值,應該可以不用寫(xiě)*/
err = cdev_add( dev->cdev, devno, 1 );
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

static int __init my_cdev_init(void)
{
int result;
dev_t devno = MKDEV(DEVICE_MAJOR, index);

/*申請設備號*/
if ( device_major )
{
result = register_chrdev_region(devno, 1, "my_cdev");
}
else
{
result = alloc_chrdev_region( devno, 0, 1, "my_cdev");
device_major = MAJOR(devno);
}
if ( result 0 )
{
return result;
}

my_cdevp = kmalloc(sizeof(struct my_cdev), GFP_KERNEL);
if ( !my_cdevp )
{
result = -ENOMEM;
goto fail_malloc;
}
memset(my_cdevp, 0, sizeof(struct my_cdev));

my_cdev_setup(my_cdevp, 0);
return 0;

fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}

static void __exit my_cdev_exit(void)
{
cdev_del(my_cdevp->cdev);
kfree(my_cdevp);
unregister_chrdev_region(MKDEV(device_major, 0), 1);
}

MODULE_AUTHOR("Song Baohua");
MODULE_LICENSE("Dual BSD/GPL");

module_init(my_cdev_init);
module_exit(my_cdev_exit);

*********************************************************************************
然后可以寫(xiě)一個(gè)簡(jiǎn)單的內核模塊的Makefile,編譯make后生成mycdev.ko文件,insmod mycdev.ko,
裝上我們自己的驅動(dòng),注意有可能在裝的時(shí)候提示說(shuō)device busy什么的,這就是我們前面指定的主設備號現在
有設備在用,我們就在重新指定一個(gè)在編譯。
那怎么看有那些設備呢?可以用cat /proc/devices,就可以查看已經(jīng)有哪些主設備號已被占用。

然后就可以自己先創(chuàng )建一個(gè)虛擬的字符設備mknod /dev/mycdev c 250 0

******************************************************
下面就可以自己寫(xiě)一個(gè)應用程序來(lái)看我們自己的字符設備驅動(dòng)是否OK。

#include stdio.h>
#include fctl.h>
#include string.h>
#include sys/stat.h>

#define BUFFERSIZE 200

int main( void )
{
int fp = 0 ;
char str[BUFFERSIZE];

fp = open( "/dev/mycdev", O_RDWR, S_IRUSR|S_IWUSR );
if ( !fp )
{
printf("Open device failedn");
return -1;
}

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

lseek( fp, 0, 0 );/*修改字符設備里字符數組的位置,將字符數據位置設到開(kāi)始的位置,不然下面的read操作將讀不到數據*/

read( fp, str, BUFFERSIZE );

printf("Read content: %sn", str );

close(fp);
}

gcc -o sample sample.c

最后運行./sample

應該會(huì )輸出:Read content: Hello, my devices

總結一下,我個(gè)人覺(jué)得字符設備驅動(dòng)相關(guān)的API和數據結構。
1. struct cdev 一個(gè)設備對應一個(gè)這個(gè)的數據結構,結構體是重要的兩個(gè)字段ops 和dev(設備號)
2. struct file_opertions 文件操作結構體
3. cdev_init(struct cdev *, struct file_opertions *) 主要就是把字符設備和對這個(gè)設備的文件操作結構體對應起來(lái)
4. cdev_add(struct cdev *, dev_t, unsigned) 注冊設備
5. register_chrdev_region(dev_t, unsigned, const char *name)/alloc_chrdev_region() 申請設備號,為注冊設備(cdev_add())準備
6. 就是內核空間的數據和用戶(hù)空間的數據交換

本文有粵嵌教育(www.gec-edu.org)培訓機構提供。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)

linux相關(guān)文章:linux教程


電機保護器相關(guān)文章:電機保護器原理


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>