來自: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/下建立對應的屬性檔案,進而通過對該檔案的讀寫實作特定的資料操作。
|
一、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