3-文字デバイスフレーム_デバイスファイルの作成

13430 ワード

文字デバイスフレーム:
  • 文字デバイスクラスには、同じ種類の文字デバイスが含まれています./sys/class
  • 各デバイスにはstruct cdevが記述されている:
  • struct file_operations *ops = &hello_op    
    cdev_init(&cdev,&hello_op)
    dev_t *dev = &devno                             
    cdev_add(&cdev,devno,1)
    

    ユーザースペース
  • アプリケーション(使用デバイスファイル名-mknod"/dev/デバイスファイル名"cプライマリデバイス番号セカンダリデバイス番号)
  • カーネルスペース
                
                |
               vfs  (struct cdev   struct file_operations)
                |
                      = MKDEV(    ,    );
    
    //struct cdev cdev;
    struct cdev *cdev;
    3、   file_operations   
    struct file_operations op = {
        .owner = THIS_MODULE,//          ,     
        .open = hello_open
    };
    

    関数のロード
  • 1、申請設備番号——dev_t devno = mar_num << 20 | min_numまたは呼び出しMKDEP(プライマリ・デバイス番号、セカンダリ・デバイス番号)
  • 2、登録デバイス番号*静的登録:register_chrdev_region(devno、登録する必要があるデバイスの数、デバイスファイル名);動的登録:alloc_chrdev_region(devno、開始次デバイス番号、次デバイス番号個数、デバイスファイル名);静的登録の利点は、デバイスの起動に要する時間が短いことであるが、デバイス番号と競合しやすい*cdev=kzalloc(sizeof(struct cdev)、GFP_KERNEL);
  • 4、初期化文字デバイスcdev_init(&cdev,&op);
  • 5、文字デバイスをカーネルに追加cdev_add(&cdev,devno,1);

  • アンインストール関数
  • 6、cdev_del(&cdev);
  • 7、設備番号の抹消
  • unregister_chrdev_region(devno、ログアウトされた文字デバイスの数);


  • 著作権の回避
    デバイスノード記述を自動的に作成すると、デバイスノードがデバイスファイルになります.
  • デバイスノードの自動作成について説明する前に、sysfsというファイルシステムのデフォルトが/sysディレクトリにマウントされていることを理解する必要があります.カーネル内の情報(デバイス番号など)をユーザ空間に導出、モジュール名で命名された/ueventファイルに/sys/module/ディレクトリ名(モジュール名で命名された)/ueventファイルに情報を格納インタフェースをユーザ空間とカーネル空間に提供する役割を果たす.ユーザースペースにはudevという小さなプログラムがあり、電源を入れるたびにすべてのueventファイルを巡り、デバイス番号を抽出して/dev/ディレクトリの下でデバイスファイルを作成します.作成が完了するとudevがブロックされ、ドライバを新しくロードするとsysfsは新しいロードされたドライバ情報をユーザースペースにエクスポートし、新しいueventファイルを生成します.ueventファイルが生成されるとudevが起動します.
  • struct class *cls;
    cls = class_create(THIS_MODULE,"hello");
       hello       ,  /sys/class            hello, hello                  
    

    デバイスファイルインタフェースの作成
    struct device *devs;
    devs = device_create(      ,         ,);
    
    struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
    
  • 機能:/devディレクトリの下でデバイスファイル
  • を自動的に作成する
  • パラメータ1:クラス構造体ポインタcls
  • パラメータ2:親デバイスのデバイスポインタ、NULL
  • を書く必要がない場合
  • パラメータ3:デバイス番号
  • パラメータ4:NULL
  • を書かない場合、いくつかのプライベートデータ
  • パラメータ5:デバイスファイル名ですが、必ずしも完全なデバイスファイル名ではありません.6番目のパラメータを使用しない場合、5番目のパラメータは完全なデバイスファイル名です.
  • が6番目のパラメータを使用する場合、デバイスファイル名は5番目と6番目の2つのパラメータから構成される.

  • パラメータ6:
  • を省略する必要はない.
    sturct inode
    {
        umode_t i_mode       
        struct cdev *i_cdev         cdev       
    }
    inode       ,          ,                。inode               。
    
    
    struct file {
        const struct file_operations *f_op;        file_operations       
    }
                ,                struct file   
    
    int (*open) (struct inode *, struct file *);
         open     :    ,    ,      ,      
    

    ユーザースペース
  • システム呼び出しインタフェースopen上位層のopenは、システム呼び出し番号によってシステム呼び出しソースコード
  • に一致する.
    カーネルスペース
  • システムコール
  • カーネル内:
  • 1、
    vi arch/arm/include/uapi/asm/unistd.h
    33 #define __NR_open           (__NR_SYSCALL_BASE+  5)
    5      
    
  • 2、
      
    __Nr_open
    713 __SYSCALL(__NR_open, sys_open)
             sys_open        
    
  • 3、
    SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
    
             return do_sys_open(AT_FDCWD, filename, flags, mode);
                        ||
                        \/
            struct file *f = do_filp_open(dfd, tmp, &op);
                                ||
                                \/
                filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
                            ||
                            \/
                3181     error = do_last(nd, &path, file, op, &opened, pathname);
                                    ||
                                    \/
                        2882         goto finish_open;
                                            ||
                                            \/
                                794     error = do_dentry_open(file, open, current_cred());
                                                    ||
                                                    \/
                                         727         open = f->f_op->open;
                                          f->f_op->open;                   ,  .open = hello_open
    

  • アプリケーション層も下層のいわゆる読み書きも,アプリケーション層の観点から見られる.
  • 読み:カーネル空間からユーザ空間
  • へデータが流れる.
  • 書き込み:反対
  • 読み取り:
  • 機能:カーネル空間のデータをユーザ空間
  • にコピーする
  • パラメータ1:最初のパラメータカーネルが作成されます.
  • パラメータ2:ユーザ空間アドレス
  • パラメータ3:カーネル空間からユーザ空間に伝達するデータサイズ
  • パラメータ4:オフセット
  •     size_t read(struct file *,char __user *,size_t ,loff_t *)
        {
                            copy_to_user();
        }
    
    static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n);
    
  • 戻り値:正常に0、失敗した戻りエラーコード
  • パラメータ1:ユーザ空間のアドレス
  • パラメータ2:カーネル空間のアドレス
  • パラメータ3:ユーザ空間へのコピーが必要なバイト数
  •     size_t write(struct file *,const char __user *,size_t ,loff_t *)
        {
                            copy_from_user();
        }
    
        static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
    
  • 戻り値:正常に0、失敗した戻りエラーコード
  • パラメータ1:カーネル空間のアドレス
  • パラメータ2:ユーザ空間のあるアドレス
  • パラメータ3:ユーザ空間がカーネル空間に伝達するデータのバイト数
  • アプリケーション層:
  • int ioctl(int fd,int cmd,...);
  • パラメータ1:ファイル記述子
  • パラメータ2:コマンド
  • パラメータ3:必要でなければ省略し、必要であれば通常変数でもアドレスでも可能
  • パラメータ3が構造を渡す必要がある場合、このとき、この構造のヘッダアドレスを渡す必要があります.また、駆動層がデータを取得するにはcopy_を呼び出す必要があります.from_userまたはcopy_to_user
  • パラメータ3が基本タイプのデータを伝達するだけである場合、駆動層は、第3のパラメータによってアプリケーション層のデータを直接受信する.

  • 駆動層:
  • long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  • パラメータ2:コマンド
  • パラメータ3:受信アプリケーションから送信されたデータ
  • cmd   32       ,      4   
                 8                        8           2             14 
         (      ,     )                                
    

    仮想アドレス=ioremap(物理アドレス、物理アドレス占有バイト数)
    練習:
    Makefile
    ifeq ($(KERNELRELEASE),)
    #KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    KERNELDIR ?= /home/linux/linux-3.14/
    PWD ?= $(shell pwd)
    modules:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
        cp *.ko /rootfs
    app:
        arm-none-linux-gnueabi-gcc test.c -o test
        cp test /rootfs
    clean:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
    .PHONY: modules clean
    else
        obj-m += led.o
    endif
    

    head.h
    #ifndef     __HEAD_H_
    #define     __HEAD_H_
    
    #define     MAGIC   'l'
    
    #define     LED2_ON     _IO(MAGIC,0)
    #define     LED2_OFF    _IO(MAGIC,1)
    #define     LED3_ON     _IO(MAGIC,2)
    #define     LED3_OFF    _IO(MAGIC,3)
    #define     LED4_ON     _IO(MAGIC,4)
    #define     LED4_OFF    _IO(MAGIC,5)
    #define     LED5_ON     _IO(MAGIC,6)
    #define     LED5_OFF    _IO(MAGIC,7)
    #define     LEDALL_ON   _IO(MAGIC,8)
    #define     LEDALL_OFF  _IO(MAGIC,9)
    
    #endif
    

    led.c
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "head.h"
    
    #define     LED_MAJOR   505
    #define     LED_MINOR   0
    #define     LED_NUM     1
    #define     LED_NAME    "ledx"
    #define     CLS_NAME    "led_cls"
    #define     DEV_NAME    "led"
    
    #define     GPX2CON     0x11000c40
    #define     GPX1CON     0x11000c20
    #define     GPF3CON     0x114001e0
    
    volatile unsigned int * gpx2con;
    volatile unsigned int * gpx1con;
    volatile unsigned int * gpf3con;
    volatile unsigned int * gpx2dat;
    volatile unsigned int * gpx1dat;
    volatile unsigned int * gpf3dat;
    
    dev_t devno;
    struct cdev led_cdev;
    struct class * cls;
    int led_open (struct inode *inode, struct file *file)
    {
         printk(" led_open!!!
    "); return 0; } int led_release (struct inode *inode, struct file *file) { printk(" led_release!!!
    "); return 0; } long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg) { printk(" led_ioctl !!!
    "); switch (cmd) { case LED2_ON: *gpx2dat = (*gpx2dat)|(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LED2_OFF: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LED3_ON: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)|(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LED3_OFF: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LED4_ON: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)|(0x1 << 4); *gpf3dat = (*gpf3dat)&~(0x1 << 5); break; case LED4_OFF: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LED5_ON: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)|(0x1 << 5); *gpf3dat = (*gpf3dat)&~(0x1 << 4); break; case LED5_OFF: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; case LEDALL_ON: *gpx2dat = (*gpx2dat)|(0x1 << 7); *gpx1dat = (*gpx1dat)|(0x1 << 0); *gpf3dat = (*gpf3dat)|(0x3 << 4); break; case LEDALL_OFF: *gpx2dat = (*gpx2dat)&~(0x1 << 7); *gpx1dat = (*gpx1dat)&~(0x1 << 0); *gpf3dat = (*gpf3dat)&~(0x3 << 4); break; default: printk(" fault cmd!!!
    "); return -EFAULT; break; } return 0; } struct file_operations led_fops={ .owner = THIS_MODULE, .open = led_open, .release = led_release, .unlocked_ioctl = led_ioctl, }; int __init led_init(void) { int ret; printk(" led_init!!!
    "); devno = MKDEV(LED_MAJOR,LED_MINOR); ret = register_chrdev_region(devno,LED_NUM,LED_NAME); if (ret < 0) { printk(" register_chrdev_region fail!!!
    "); return -EFAULT; } printk(" register_chrdev_region success!!!
    "); printk(" major=%d,minor=%d
    ",MAJOR(devno),MINOR(devno)); cdev_init(&led_cdev,&led_fops); led_cdev.owner = THIS_MODULE; cdev_add(&led_cdev,devno,LED_NUM); cls = class_create(THIS_MODULE,CLS_NAME); if (IS_ERR(cls)) { printk(" class_create fail!!!
    "); return -EFAULT; } device_create(cls,NULL,devno,NULL,DEV_NAME); gpx2con = ioremap(GPX2CON,0x4); if (NULL == gpx2con) { printk(" gpx2con ioremap fail!!!
    "); return -EFAULT; } gpx1con = ioremap(GPX1CON,0x4); if (NULL == gpx1con ) { printk(" gpx1con ioremap fail!!!
    "); return -EFAULT; } gpf3con = ioremap(GPF3CON,0x4); if (NULL == gpf3con) { printk(" gpf3con ioremap fail!!!
    "); return -EFAULT; } gpx2dat = gpx2con + 1; //gpx2dat = ioremap(0x1100c44,0x4); gpx1dat = gpx1con + 1; gpf3dat = gpf3con + 1; *gpx2con = ((*gpx2con)&~(0xf << 28))|(0x1 << 28); *gpx1con = ((*gpx1con)&~(0xf << 0))|(0x1 << 0); *gpf3con = ((*gpf3con)&~(0xff <<16))|(0x11 << 16); *gpx2dat =(*gpx2dat)|(0x1 << 7); *gpx1dat =(*gpx1dat)|(0x1 << 0); *gpf3dat =(*gpf3dat)|(0x3 << 4); return 0; } module_init(led_init); void __exit led_exit(void) { printk(" led_exit!!!
    "); iounmap(gpf3con); iounmap(gpx1con); iounmap(gpx2con); device_destroy(cls,devno); class_destroy(cls); cdev_del(&led_cdev); unregister_chrdev_region(devno,LED_NUM); } module_exit(led_exit); MODULE_LICENSE("GPL");

    led.c
    #include 
    #include 
    #include 
    #include "head.h"
    
    int main(int argc, char *argv[])
    {
        int fd;
        fd = open("/dev/led",O_RDWR);
        if (fd < 0)
        {
            printf(" open fail!!!
    "); return -1; } for(;;) { ioctl(fd,LED2_ON); sleep(1); ioctl(fd,LED3_ON); sleep(1); ioctl(fd,LED4_ON); sleep(1); ioctl(fd,LED5_ON); sleep(1); ioctl(fd,LEDALL_ON); sleep(1); } close(fd); return 0; }