天天看點

Class create, device create, device create file【轉】

來自:http://www.hovercool.com/en/Class_create,_device_create,_device_create_file

開始寫Linux裝置驅動程式的時候,很多時候都是利用mknod指令手動建立裝置節點(包括ldd3中不少例子也是這樣),實際上現在Linux核心為我們提供了一組函數,可以用來在子產品加載的時候自動在/dev目錄下建立相應裝置節點,并在解除安裝子產品時删除該節點。

核心中定義了struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,核心同時提供了class_create(…)函數,可以用它來建立一個類,這個類存放于sysfs下面,一旦建立好了這個類,再調用device_create(…)函數來在/dev目錄下建立相應的裝置節點。這樣,加載子產品的時候,使用者空間中的udev會自動響應device_create(…)函數,去/sysfs下尋找對應的類進而建立裝置節點。

此外,利用device_create_file函數可以在/sys/class/下建立對應的屬性檔案,進而通過對該檔案的讀寫實作特定的資料操作。

  • 1 一、class_create
  • 2 二、device_create
  • 3 三、device_create_file
    • 3.1 a.在驅動程式中使用 device_create_file建立屬性檔案
    • 3.2 b.在使用者空間讀取屬性
  • 4 四、使用示例

一、class_create

官方說明:

/* This is a #define to keep the compiler from merging different
 * instances of the __key variable */
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})

/**
 * class_create - create a struct class structure
 * @owner: pointer to the module that is to "own" this struct class
 * @name: pointer to a string for the name of this class.
 * @key: the lock_class_key for this class; used by mutex lock debugging
 *
 * This is used to create a struct class pointer that can then be used
 * in calls to device_create().
 *
 * Returns &struct class pointer on success, or ERR_PTR() on error.
 *
 * Note, the pointer created here is to be destroyed when finished by
 * making a call to class_destroy().
 */
struct class *__class_create(struct module *owner, const char *name,
			     struct lock_class_key *key)      

關鍵的一句是:

* This is used to create a struct class pointer that can then be used
 * in calls to device_create().
 -->這個函數用來建立一個struct class的結構體指針,這個指針可用作device_create()函數的參數。
      

也就是說,這個函數主要是在調用device_create()前使用,建立一個struct class類型的變量,并傳回其指針。

二、device_create

/**
 * device_create - creates a device and registers it with sysfs
 * @class: pointer to the struct class that this device should be registered to
 * @parent: pointer to the parent struct device of this new device, if any
 * @devt: the dev_t for the char device to be added
 * @drvdata: the data to be added to the device for callbacks
 * @fmt: string for the device's name
 *
 * This function can be used by char device classes.  A struct device
 * will be created in sysfs, registered to the specified class.
 *
 * A "dev" file will be created, showing the dev_t for the device, if
 * the dev_t is not 0,0.
 * If a pointer to a parent struct device is passed in, the newly created
 * struct device will be a child of that device in sysfs.
 * The pointer to the struct device will be returned from the call.
 * Any further sysfs files that might be required can be created using this
 * pointer.
 *
 * Returns &struct device pointer on success, or ERR_PTR() on error.
 *
 * Note: the struct class passed to this function must have previously
 * been created with a call to class_create().
 */
struct device *device_create(struct class *class, struct device *parent,
			     dev_t devt, void *drvdata, const char *fmt, ...)      

首先解釋一下"sysfs":sysfs是linux2.6所提供的一種虛拟檔案系統;在裝置模型中,sysfs檔案系統用來表示裝置的結構,将裝置的層次結構形象的反應到使用者空間中,進而可以通過修改sysfs中的檔案屬性來修改裝置的屬性值;sysfs被挂載到根目錄下的"/sys"檔案夾下。

三、device_create_file

/**
 * device_create_file - create sysfs attribute file for device.
 * @dev: device.
 * @attr: device attribute descriptor.
 */
int device_create_file(struct device *dev,
		       const struct device_attribute *attr)      

使用這個函數時要引用 device_create所傳回的device*指針,作用是在/sys/class/下建立一個屬性檔案,進而通過對這個屬性檔案進行讀寫就能完成對應的資料操作。

如:

a.在驅動程式中使用 device_create_file建立屬性檔案

static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);  

/*讀取寄存器val的值到緩沖區buf中,内部使用*/  
static ssize_t __hello_get_val(struct xxx_dev* dev, char* buf) {  
    int val = 0;          
  
    /*同步通路*/  
    if(down_interruptible(&(dev->sem))) {                  
        return -ERESTARTSYS;          
    }          
  
    val = dev->val;          
    up(&(dev->sem));          
  
    return snprintf(buf, PAGE_SIZE, "%d/n", val);  
}  
  
/*把緩沖區buf的值寫到裝置寄存器val中去,内部使用*/  
static ssize_t __hello_set_val(struct xxx_dev* dev, const char* buf, size_t count) {  
    int val = 0;          
  
    /*将字元串轉換成數字*/          
    val = simple_strtol(buf, NULL, 10);          
  
    /*同步通路*/          
    if(down_interruptible(&(dev->sem))) {                  
        return -ERESTARTSYS;          
    }          
  
    dev->val = val;          
    up(&(dev->sem));  
  
    return count;  
}  
  
/*讀取裝置屬性val*/  
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {  
    struct xxx_dev* hdev = (struct xxx_dev*)dev_get_drvdata(dev);          
  
    return __hello_get_val(hdev, buf);  
}  
  
/*寫裝置屬性val*/  
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const