首页 > 代码库 > 字符设备(二)
字符设备(二)
Open-(“/dev/tcdev”) c 248 0-> 调用sys_open->do_sys_open->调用do_file_open ->调用的do_last ->调用 nameidata_to_filp ->执行__dentry_open (里面open(inode,f)其中用到了chrdev_open 你打开字符类设备节点时那么这个函数就会被调用到 ->filp->f_op->open实则是tcdev_open)
/dev/tcdev起到的作用?
手工创建 mknod
自动创建设备节点文件的方式
include<linux/device.h>
struct class *dev_class =NILL
struct device *dev_device =NULL
注册设备类
效果是/sys/class/xxxx的文件夹
class_create(THIS_MIDULE,”XXXXX”);
注册设备
效果:
用户态的程序创建的设备节点文件
/sbin/udevd udev (mdev嵌入式使用) 根据/sys/的变化,动态在创建设备节点文件
udev是个后台守护进程,会接受uevent事件
而device_create 会发生出该事件即udev根据事件信息创建/dev/xxxx(根据/sys/class/xxxx/xxx)
mdev device_create 函数中会直接调用 /sbin/mdev程序来创建设备节点文件。
在文件系统中:
/proc ->procfs导出内核运行状态信息
/sys ->sysfs 重点在于导出内核中所有硬件设备的层次结构
设备节点文件 内核中 参数
/dev/xxxx0 cdev0 led=0
/dev/xxxx1 cdev1 led=1
........ ....... ......
struct inode
{
dev_t i_rdev; //记录设备号
Union{
Struct cdev *i_cdev; //指向了cdev_add时添加的cdev
}
}
inode译成中文就是索引节点,它用来存放档案及目录的基本信息,包含时间、档名、使用者及群组等。
内核中的inode包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。inode结构中的静态信息取自物理设备上的文件系统,由文件系统指定的函数填写,它只存在于内存中,可以通过inode缓存访问。虽然每个文件都有相应的inode结点,但是只有在需要的时候系统才会在内存中为其建立相应的inode数据结构,建立的inode结构将形成一个链表,我们可以通过遍历这个链表去得到我们需要的文件结点,VFS也为已分配的inode构造缓存和哈希表,以提 高系统性能。inode结构中的struct inode_operations *i_op为我们提供了一个inode操作列表,通过这个列表提供的函数我们可以对inode结点进行各种操作。每个inode结构都有一个i结点号i_ino,在同一个文件系统中每个i结点号是唯一的。
我们主要关心的是
struct inode {
unsigned longi_ino; /*每一个inode都有一个序号,经由super block结构和其序号,我们可以很轻易的找到这个inode。*/
atomic_t i_count; /*在Kernel里,很多的结构都会记录其reference count,以确保如果某个结构正在使用,它不会被不小心释放掉,i_count就是其reference count。*/
kdev_t i_dev; /* inode所在的device代码 */
umode_t i_mode; /* inode的权限 */
nlink_t i_nlink; /* hard link的个数 */
uid_t i_uid; /* inode拥有者的id */
gid_t i_gid; /* inode所属的群组id */
kdev_t i_rdev; /* 如果inode代表的是device的话,那此字段将记录device的代码 */
off_t i_size; /* inode所代表的档案大小 */
time_t i_atime; /* inode最近一次的存取时间 */
time_t i_mtime; /* inode最近一次的修改时间 */
time_t i_ctime; /* inode的产生时间 */
unsigned long i_blksize; /* inode在做IO时的区块大小 */
unsigned long i_blocks; /* inode所使用的block数,一个block为512 byte*/
unsigned long i_version; /* 版本号码 */
struct file_operations *i_fop;/* former ->i_op->default_file_ops */
struct super_block *i_sb; /* inode所属档案系统的super block */
struct file_lock *i_flock; /* 用来做file lock */
unsigned long i_state; /* inode目前的状态,可以是I_DIRTY,I_LOCK和 I_FREEING的OR组合 */
unsigned int i_flags; /* 记录此inode的参数 */
unsigned char i_sock; /* 用来记录此inode是否为socket */
unsigned int i_attr_flags; /* 用来记录此inode的属性参数 */
以上的可能以后用的上
struct file{
loff_t f_pos //offset
File->private_data
Const struct file operations *f_op
....
}
文 件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码 中,struct file的指针通常被命名为file或filp。
const struct file_operations *f_op;
被定义在linux/include/linux/fs.h中,其中包含着与文件关联的操作,如:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。当打开一个文件时,内核就创建一个与该文件相关联的struct file结构,其中的*f_op就指向的是
具 体对该文件进行操作的函数。例如用户调用系统调用read来读取该文件的内容时,那么系统调用read最终会陷入内核调用sys_read函数,而 sys_read最终会调用于该文件关联的struct file结构中的f_op->read函数对文struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.11内核)
loff_t f_pos;
当前的文件指针位置,即文件的读写位置。
loff_t被定义为:
typedef long long __kernel_loff_t;
typedef __kernel_loff_t loff_t;
Open(“/dev/xxx”)
xxx_open(....)
{
}
/dev/xxx的设备节点
device_create(struct *class cls,struct device parent,dec_t devt,...,cinst char *fmt...)
device_destroy(dev_class,dev)
Class_destroy(dev_class)
内核空间和用户空间数据的交互
内核态数据向用户态拷贝 copy_to_user(to,from,n)
反之 copy_from_user(to,from,n)
在arch/arm/include/asm/uaccess.h中
示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Songmao");
MODULE_DESCRIPTION("cdev tast");
#define TCDEV_MAJOR 0
#define TCDEV_MINOR 0
#define TCDEV_NUM 5
#define TCDEV_NO 1
#define count1 6
#define TCDEV_NAME "mytcdev"
int tcdev_major =TCDEV_MAJOR,tcdev_minor=TCDEV_MINOR;
module_param(tcdev_major,int,S_IRWXU);
module_param(tcdev_minor,int,S_IRWXU);
struct class *tcdev_class =NULL;
struct tast_cdev {
struct device *dev_device;
struct cdev tcdev;
int gbuff;
};
struct tast_cdev *tast_cdevp;
static int tcdev_open(struct inode * inode,struct file * filep)
{
int i=0;
struct tast_cdev *tcdevp=NULL;
tcdevp =container_of(inode->i_cdev,struct tast_cdev,tcdev);
i=MINOR(inode->i_rdev);
printk(KERN_INFO "tcdev open tcdev %d\n");
filep->private_data=http://www.mamicode.com/tcdevp;
return 0;
}
static ssize_t tcdev_read(struct file *filep, char __user *buf, size_t count, loff_t *fops)
{ char tgbuff[30]="sfsdfsfdsfdfdfsgsdfs";
struct tast_cdev *tcdevp=NULL;
tcdevp=filep->private_data;
copy_to_user(buf,tgbuff,count);
printk(KERN_INFO "tcdev read %d\n",tgbuff);
return count;
}
static ssize_t tcdev_write(struct file *filep, char __user *buf, size_t count, loff_t *fops)
{
char tgbuff[30]={0};
struct tast_cdev *tcdevp=NULL;
tcdevp=filep->private_data;
copy_from_user(tgbuff,buf,count);
printk(KERN_INFO "tcdev write %d\n",tgbuff);
return count;
}
static int tcdev_release(struct inode * node,struct file * filep)
{
printk(KERN_INFO "tcdev write\n");
return 0;
}
static struct file_operations tcdev_fops = {
.owner=THIS_MODULE,
.open=tcdev_open,
.read=tcdev_read,
.write=tcdev_write,
.release=tcdev_release,
};
static struct cdev tcdev;
static int tast_cdevadd(struct tast_cdev *tastcdev,int index)
{
int ret=0;
dev_t dev=0;
dev = MKDEV(tcdev_major,tcdev_minor+index);
cdev_init(&(tastcdev->tcdev),&tcdev_fops);
ret=cdev_add(&tastcdev->tcdev,dev,TCDEV_NO);
if(ret<0){
printk(KERN_ERR"tcdev cdev cdev_add is fail\n");
return -ENOANO;
}
printk(KERN_INFO"tcdev %d cdev_add apply is success\n",index);
tastcdev->dev_device=device_create(&tcdev_class,NULL,dev,NULL,TCDEV_NAME);
if(IS_ERR(tastcdev->dev_device)){
printk(KERN_ERR "tastcdev.dev_device fail");
return 0;
}
printk(KERN_INFO "tastcdev.dev_device success");
//tastcdev.gbuff="20130+i";
return 0;
}
static int __init tcdev_init(void)
{
int ret =-EFAULT,i=0;
dev_t tcdev_t;
tcdev_t=MKDEV(tcdev_major,tcdev_minor);
printk(KERN_INFO "tcdev start ...\n");
if(tcdev_major==0){
ret= alloc_chrdev_region(&tcdev_t,tcdev_minor,TCDEV_NUM,TCDEV_NAME);
if(ret<0){
printk(KERN_ERR"tcdev cdev num apply is fail\n");
goto tcdev_cdev_fail;
}
}
else{
ret=register_chrdev_region(tcdev_t,TCDEV_NUM,TCDEV_NAME);
if(ret<0){
printk(KERN_ERR "tcdev cdev num apply is fail\n");
goto tcdev_cdev_fail;
}
}
printk(KERN_INFO "tcdev cdev num apply is success,dev_t is %d\n",tcdev_t);
tast_cdevp = kmalloc(sizeof(struct cdev)*TCDEV_NUM,GFP_KERNEL);
if(IS_ERR(tast_cdevp)){
printk(KERN_ERR "kmalloc fail");
goto kmalloc_fail;
}
memset(&tast_cdevp,0,sizeof(struct cdev)*TCDEV_NUM);
tcdev_class =class_create(THIS_MODULE,TCDEV_NAME);
if(IS_ERR(tcdev_class)){
printk(KERN_ERR "class_create fail");
goto class_create_fail;
}
for(;i<TCDEV_NUM;i++){
ret=tast_cdevadd(&(tast_cdevp[i]),i);
if(ret==0){
device_del(&(tast_cdevp[i].dev_device));
cdev_del(&(tast_cdevp[i].tcdev));
goto tcdev_cdev_add_fail;
}
if(ret<0){
cdev_del(&(tast_cdevp[i].tcdev));
goto tcdev_cdev_add_fail;
}
}
printk(KERN_INFO"tcdev cdev_add apply is success\n");
return 0;
tcdev_cdev_add_fail:
class_destroy(tcdev_class);
class_create_fail:
kfree(tast_cdevp);
kmalloc_fail:
unregister_chrdev_region(tcdev_t,TCDEV_NUM);
tcdev_cdev_fail:
return 0;
}
static void __exit tcdev_exit (void)
{
int i=0;
printk(KERN_INFO "tcdev stop ...\n");
cdev_del(&tcdev);
printk(KERN_INFO"tcdev del success\n");
for(;i<TCDEV_NUM;i++){
device_del(&(tast_cdevp[i].dev_device));
cdev_del(&(tast_cdevp[i].tcdev));
}
class_destroy(tcdev_class);
kfree(tast_cdevp);
unregister_chrdev_region(MKDEV(tcdev_major,tcdev_minor),TCDEV_NUM);
printk(KERN_INFO "tcdev dev_num del success\n");
}
module_init(tcdev_init);
module_exit(tcdev_exit);
本文出自 “毛散人” 博客,请务必保留此出处http://songmao.blog.51cto.com/11700139/1877748
字符设备(二)