首页 > 代码库 > 字符设备(二)

字符设备(二)

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的指针通常被命名为filefilp

 

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_usertofromn

反之                   copy_from_user(tofromn)

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

字符设备(二)