文字デバイス---file_operations 、class、device


キャラクタドライバ
-------------------------------------------------------------
コアfile_operations構造体
    
--------------------------------------------------------------
登録文字デバイスメソッド
手順:1.申請設備番号
            2.cdev構造体の設定
            3.cdev構造体の初期化
            4.cdev構造体をチェーンテーブルに追加
申請設備番号:
 1: int register_chrdev_region(dev_t from, unsigned count, const char *name)
 2. int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)

方法1では,まずデバイス番号を設定する必要があり,動的にデバイス番号を申請できない場合には,1つのプライマリデバイスの下のcount個のスレーブデバイスを申請することができる.
方法2では,動的な申請デバイス番号は,サブデバイスのbaseを提供する必要があり,count個のスレーブデバイスを連続的に申請することができる.
申請cdev構造体
cdev構造体はグローバル変数、ポインタを使用できます
ポインタを使用するにはcdev_を使用する必要があります.alloc申請
cdedv構造体の設定
    void cdev_init(struct cdev *cdev, const struct file_operations *fops)

    cdev_init----->file_Opentions構造体がcdevに付与するops
実は手作業での設定もできます
cdevチェーンテーブルに追加
    int cdev_add(struct cdev *p, dev_t dev, unsigned count)

    
----------------------------------------------------------------------------------------
ログアウト:
チェーンテーブルからcdevを削除
    void cdev_del(struct cdev *p)
    
-------------------------------------------------------------------------------------
文字デバイスの登録は、簡略化されたバージョンregister_を使用することもできます.chrdev
 
   int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)

majorが0の場合、プライマリ・デバイス番号を動的に申請します.
    
//登録解除文字デバイス
int unregister_chrdev(unsigned int major, const char *name)    

------------------------------------------------------------------
文字デバイス申請のプライマリデバイス番号は、proc/devicesに申請したプライマリデバイス番号が表示されます.
次の設備番号は、どのように体現されていますか?サブデバイス番号は、/dev/xxxすなわちdevの下のデバイスによって表される.
----------------------------------------------------------------------------------------------------
文字デバイス駆動では、以上の操作はデバイス番号の申請のみを完了し、生成デバイスには関与しない.
デバイスを自動的に生成しない場合は、mknodコマンドを手動で使用してこの設定を作成する必要があります.
デバイスの自動作成:
デバイスを自動的に作成する前提はclassクラスを作成することです.classクラスを作成した後だけです.デバイスの自動作成
    
クラスの作成:struct class*class_create(struct module *owner, const char *name)
機能:create a struct class structure
パラメータ:owner:THIS_MODULE
                              name: pointer to a string for the name of this class.
戻り値:
値を返すにはIS_が必要ですERR判定
              
          if(IS_ERR(cls))
                         {
                             PTR_ERR(cls);
                         }

このような処理方式
クラスのログアウト:void class_destroy(struct class *cls)
                    
以上の操作もクラスが作成されただけです.デバイスの作成は行われていません
                
デバイスの作成:
  
     struct device *device_create(struct class *class, struct device *parent, dev_t devt, const char *fmt, ...)

機能:creates a device and registers it with sysfs
パラメータ:class:作成されたクラス
                          parent: pointer to the parent struct device of this new device, if any
devt:デバイス番号.devt=MKDEV(major,min)
fmt:ここで複数のセカンダリデバイスを作成できます(eg:“dev%d”,i)
戻り値:戻り値の判断にもclass_が必要createのように判断する
                          
デバイスのログアウト:
void device_destroy(struct class *class, dev_t devt)    

//複数のセカンダリデバイスのログアウトがある場合は、MKDEP(major,min)を使用してdevtを生成する必要があります.デバイスをループして呼び出すdestroy    
    ----------------------------------------------------------------------
  
  #include 
#include 
#include 

#include 
#include 

#include 
#include 

#include 
#include 

static struct cdev * pdev = NULL;

#define DEVNAME "demo"

static int major = 0;
static int minor = 0;
static int count = 3;

#define KMAX 1024
static char kbuf[KMAX];
static int counter = 0;

static struct class *cls = NULL;

// 
//int open(const char *pathname, int flags);
static int demo_open(struct inode *inode, struct file *filp)
{
    printk("%s:%d, pid = %d
", __func__, __LINE__, current->pid); printk("%s:%d, %d
", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); return 0; } // //int close(int fd) static int demo_release(struct inode *inode, struct file *filp) { printk("%s:%d, pid = %d
", __func__, __LINE__, current->pid); printk("%s:%d, %d
", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); return 0; } // //ssize_t read(int fd, void *buf, size_t count); static ssize_t demo_read(struct file *filp, char __user *buffer, size_t size, loff_t *offset) { printk("%s:%d, pid = %d
", __func__, __LINE__, current->pid); printk("%s:%p, %d
", __func__, buffer, size); if(0 == counter){ return -EAGAIN; } if(counter < size){ size = counter; } if(size == copy_to_user(buffer, kbuf, size)){ return -EAGAIN; } counter = 0; return size; } // static ssize_t demo_write(struct file *filp, const char __user *buffer, size_t size, loff_t *offset) { printk("%s:%d, pid = %d
", __func__, __LINE__, current->pid); printk("%s:%p, %d
", __func__, buffer, size); if(size > KMAX){ return -ENOMEM; } if(size == copy_from_user(kbuf, buffer, size)){ return -EAGAIN; } counter = size; return size; } static struct file_operations misc = { .owner = THIS_MODULE, .open = demo_open, .release= demo_release, .read = demo_read, .write = demo_write, }; static int main_open(struct inode *inode, struct file *filp) { printk("%s:%d, pid = %d
", __func__, __LINE__, current->pid); printk("%s:%d, %d
", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); filp->f_op = &misc; return filp->f_op->open(inode, filp); } static struct file_operations fops = { .owner = THIS_MODULE, .open = main_open, }; static int __init demo_init(void) { dev_t dev; int ret, i; struct device *device = NULL; printk("%s:%d
", __func__, __LINE__); //1.alloc obj pdev = cdev_alloc(); if(NULL == pdev){ printk("cdev_alloc fail.
"); return -ENOMEM; } //2.init obj cdev_init(pdev, &fops); ret = alloc_chrdev_region(&dev, minor, count, DEVNAME); if(ret){ printk("alloc_chrdev_region fail.
"); goto ERR_STEP; } major = MAJOR(dev); //3. register obj ret = cdev_add(pdev, dev, count); if(ret){ printk("cdev_add fail.
"); goto ERR_STEP1; } cls = class_create(THIS_MODULE, DEVNAME); if (IS_ERR(cls)) { ret = PTR_ERR(cls); goto ERR_STEP1; } for(i = minor; i < count+minor; i++){ device = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i); if (IS_ERR(device)) { ret = PTR_ERR(device); goto ERR_STEP2; } } return 0; //0- ; : , ,( errno) ERR_STEP2: for(i--; i >= minor; i--){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); ERR_STEP1: unregister_chrdev_region(dev, count); ERR_STEP: cdev_del(pdev); return ret; } static void __exit demo_exit(void) { int i; printk("%s:%d
", __func__, __LINE__); //1. free resorce unregister_chrdev_region(MKDEV(major, minor), count); for(i = minor; i < count+minor; i++){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); //2.unregister cdev_del(pdev); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL");