1. 程式人生 > >linux misc device字元雜項裝置驅動程式

linux misc device字元雜項裝置驅動程式

雜項裝置也是在嵌入式系統中用得比較多的一種裝置驅動。miscdevice共享一個主裝置號MISC_MAJOR(即10),但次裝置號不同。misc裝置其實就是特殊的字元裝置,主裝置編號採用10,並且可自動生成裝置節點。

雜項裝置作為字元裝置的封裝,為字元裝置提供的簡單的程式設計介面,如果編寫新的字元驅動,可以考慮使用雜項裝置介面,方便簡單,只需要初始化一個miscdevice的結構,呼叫misc_register就可以了,misc_register最終也是通過呼叫register_chrdev()來註冊裝置。系統最多有255個雜項裝置,因為雜項裝置模組自己佔用了一個次裝置號。

1. 實現struct file_operations

static struct file_operations leds_ops = {

.owner = THIS_MODULE,

.open = leds_open,

.release = leds_release,

.unlocked_ioctl = leds_ioctl,

};

2. 初始化struct miscdevice,定義一個misc裝置

static struct miscdevice leds_dev = {

.minor = MISC_DYNAMIC_MINOR,

.fops = &leds_ops,

.name = "leds", //此名稱將顯示在/dev目錄下面

};

注:其中minor如果填充MISC_DYNAMIC_MINOR,則是動態動態次裝置號。

3. 註冊和釋放misc裝置

1)註冊

int misc_register(struct miscdevice * misc);

misc_register(&leds_dev);

注:此函式中會自動建立裝置節點,即裝置檔案。無需mknod指令建立裝置檔案,因為misc_register()會呼叫device_create()建立裝置節點。

2)釋放

int misc_deregister(struct miscdevice *misc);

misc_deregister(&leds_dev);

4. 其它

1)標頭檔案 #include <linux/miscdevice.h>

2)miscdevice 結構體

struct miscdevice { int minor; //次裝置號 通常為MISC_DYNAMIC_MINOR 動態分配 const char *name; //裝置的名字 const struct file_operations *fops;//函式操作集 struct list_head list; struct device *parent; struct device *this_device; const char *nodename; umode_t mode; };

通常 miscdevice的 minor 、name 和 fops是需要實現的。

5. A33下一個GPIO驅動例項

#include <linux/init.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <mach/gpio.h>

#include <linux/gpio.h>

#include <linux/miscdevice.h>



static int led_gpios[] = {

GPIOH(7),

};



#define LED_NUM ARRAY_SIZE(led_gpios)



int leds_open(struct inode *inode,struct file *filp)

{

printk("leds device opened success!\n");

return nonseekable_open(inode,filp); //通知核心你的裝置不支援llseek

}



int leds_release(struct inode *inode,struct file *filp)

{

printk("leds device closed success!\n");

return 0;

}





long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)

{

printk("debug: leds_ioctl cmd is %d\n" , cmd);



switch(cmd)

{

case 0: //不加break,執行case1

case 1:

if (arg > LED_NUM) {

return -EINVAL;

}

gpio_set_value(led_gpios[arg], cmd);

break;



default:

return -EINVAL;

}



return 0;

}



static struct file_operations leds_ops = {

.owner = THIS_MODULE,

.open = leds_open,

.release = leds_release,

.unlocked_ioctl = leds_ioctl,

};



static struct miscdevice leds_dev = {

.minor = MISC_DYNAMIC_MINOR,

.fops = &leds_ops,

.name = "leds", //此名稱將顯示在/dev目錄下面

};





static int __init leds_init(void)

{

int ret, i;

char *banner = "leds Initialize\n";



printk(banner);



for(i=0; i<LED_NUM; i++)

{

//申請gpio,設定為輸出,高電平

ret = gpio_request_one(led_gpios[i], GPIOF_OUT_INIT_HIGH,"LED");

if (ret) {

printk("leds: request GPIO %d for LED failed, ret = %d\n", led_gpios[i], ret);

return ret;

}



}



ret = misc_register(&leds_dev);

if(ret<0)

{

printk("leds: register device failed!\n");

goto exit;

}



return 0;



exit:

misc_deregister(&leds_dev);

return ret;

}



static void __exit leds_exit(void)

{

misc_deregister(&leds_dev);



}



module_init(leds_init);

module_exit(leds_exit);



MODULE_LICENSE("Dual BSD/GPL");