混雜設(shè)備

1 什么是混雜設(shè)備

在Linux驅(qū)動中抬伺,會把一些無法歸類的設(shè)備定義為混雜設(shè)備——misc(在文件drivers/char/misc.c中實現(xiàn)),它們是擁有著共同的特性的簡單字符設(shè)備(也就是說本質(zhì)上是字符設(shè)備)读慎,它們的特點是共享統(tǒng)一的主設(shè)備號10漱贱,但每個設(shè)備可以選擇一個單獨的次設(shè)備號。如果一個字符設(shè)備驅(qū)動要驅(qū)動多個設(shè)備夭委,那么它就不應(yīng)該用misc設(shè)備來實現(xiàn)幅狮。通常情況下,一個字符設(shè)備都不得不在初始化的過程中進行下面的步驟:
通過alloc_chrdev_region()分配主/次設(shè)備號株灸。
使用cdev_init()和cdev_add()來以一個字符設(shè)備注冊自己崇摄。
而一個misc驅(qū)動,則可以只用一個調(diào)用misc_register()來完成這所有的步驟慌烧。
所有的miscdevice設(shè)備形成一個鏈表逐抑,對設(shè)備訪問時,內(nèi)核根據(jù)次設(shè)備號查找對應(yīng)的miscdevice設(shè)備屹蚊,然后調(diào)用其file_operations中注冊的文件操作方法進行操作厕氨。
在Linux內(nèi)核中,使用struct miscdevice來表示miscdevice汹粤。這個結(jié)構(gòu)體的定義為:

struct miscdevice  {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const char *nodename;
    mode_t mode;
};

minor是這個混雜設(shè)備的次設(shè)備號命斧,若由系統(tǒng)自動配置,則可以設(shè)置為MISC_DYNANIC_MINOR嘱兼,name是設(shè)備名国葬。
每一個misc驅(qū)動會自動出現(xiàn)在/sys/class/misc下,而不需要驅(qū)動程序作者明確的去做芹壕。

2 混雜設(shè)備的API

包含頭文件

#include<linux/miscdevice.h>

建一個miscdevice結(jié)構(gòu)體

static struct miscdevice misc = {
       .minor = MISC_DYNAMIC_MINOR,
       .name = DEVICE_NAME,
       .fops = &dev_fops,
};

在驅(qū)動函數(shù)初始化中注冊這個混雜設(shè)備
misc_register(&misc);
驅(qū)動卸載時胃惜,注銷這個設(shè)備
misc_deregister(&misc);

混雜設(shè)備miscdevice說明
miscdevice結(jié)構(gòu)體

struct miscdevice  {
       int minor;
       const char *name;
       const struct file_operations *fops;
       struct list_head list;
       struct device *parent;
       struct device *this_device;
       const char *nodename;
       mode_t mode;
};

設(shè)備注冊和注銷
extern int misc_register(struct miscdevice * misc);
extern int misc_deregister(struct miscdevice *misc);
函數(shù)具體實現(xiàn)在/drivers/char/misc.c
在misc_init()函數(shù)中
調(diào)用class_create()函數(shù)創(chuàng)建了一個名misc的類,注冊了一個主設(shè)備號為10哪雕,設(shè)備名為misc的字符設(shè)備。
misc_register()函數(shù)用于注冊一個混雜設(shè)備鲫趁,其主設(shè)備號為10斯嚎,如果次設(shè)備號指定為MISC_DYNAMIC_MINOR將由系統(tǒng)去指定一個次設(shè)備號,調(diào)用device_create創(chuàng)建設(shè)備節(jié)點。
misc_deregister用于注銷這個混雜設(shè)備堡僻,其中調(diào)用了device_destroy刪除設(shè)備節(jié)點糠惫。

3 混雜設(shè)備驅(qū)動實例

LED驅(qū)動程序可以用作一個典型的混雜設(shè)備,下面就簡單的看一份代碼來學(xué)習(xí)一下混雜設(shè)備驅(qū)動代碼的編寫:

/*
 *  ioctl 控制 LED
 *  使用庫函數(shù)钉疫,非操作寄存器硼讽,沒有重映射地址
 *  使用混雜設(shè)備驅(qū)動
 */
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
 
 
#define DEVICE_NAME "GPIO_Control_LED"
#define LED_NUM 4
 
/* 定義幻數(shù) */
#define LED_IOC_MAGIC  'L'
 
/* 定義命令 */
#define IOCTL_GPIO_ON       _IOR(LED_IOC_MAGIC,1,int)  //從用戶空間讀
#define IOCTL_GPIO_OFF      _IOR(LED_IOC_MAGIC,2,int)  
#define IOCTL_GPIO_GET_STATE    _IOWR(LED_IOC_MAGIC,3,int)  //向用戶空間寫
 
//最大命令數(shù)
#define LED_IOC_MAXNR 3
 
 
//IO 口
static unsigned long gpio_table [] =
{
    S3C2410_GPB5,
    S3C2410_GPB6,
    S3C2410_GPB7,
    S3C2410_GPB8,
};
 
//IO口 配置
static unsigned int gpio_cfg_table [] =
{
    S3C2410_GPB5_OUTP,
    S3C2410_GPB6_OUTP,
    S3C2410_GPB7_OUTP,
    S3C2410_GPB8_OUTP,
};
 
static int tq2440_gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    static int pin_state=0;
    static int ret = 0;
    static int ioarg = 0;
    static int err = 0;
     
        /* 檢測命令的有效性 */
    if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) 
        return -EINVAL;
    if (_IOC_NR(cmd) > LED_IOC_MAXNR) 
        return -EINVAL;
     
        /* 根據(jù)命令類型,檢測參數(shù)空間是否可以訪問 */
    if (_IOC_DIR(cmd) & _IOC_READ)  //如果是讀命令牲阁,則判斷是否可以向用戶空間 寫
        err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
    else if (_IOC_DIR(cmd) & _IOC_WRITE)
        err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
        if (err) 
        return -EFAULT;

    /* 根據(jù)命令固阁,來選擇執(zhí)行哪個分支,并根據(jù)傳入的參數(shù)打開城菊、關(guān)閉或得到某個燈的狀態(tài) */
    switch(cmd)
    {
        case IOCTL_GPIO_ON:
            ret = __get_user(ioarg, (int *)arg);
             
            printk("SET the LED  %d  to ON  \n",ioarg);
            s3c2410_gpio_setpin(gpio_table[ioarg], 0);
            return 0;
 
        case IOCTL_GPIO_OFF:
            ret = __get_user(ioarg, (int *)arg);
             
            printk("SET the LED  %d  to OFF  \n",ioarg);
            s3c2410_gpio_setpin(gpio_table[ioarg], 1);
            return 0;
             
        case IOCTL_GPIO_GET_STATE:
            ret = __get_user(ioarg, (int *)arg);
             
            pin_state=s3c2410_gpio_getpin(gpio_table[ioarg]);
                ret = __put_user(pin_state, (int *)arg);
                printk("IN KERNEL ---===>>>  I got the stat of pin is  %d   \n",pin_state);
                return 0;
                 
        default:
            return -EINVAL;
    }
}
 
static struct file_operations dev_fops = {
    .owner  =   THIS_MODULE,
    .ioctl  =   tq2440_gpio_ioctl, 
};
  /* 這個函數(shù)是混雜設(shè)備的關(guān)鍵函數(shù)备燃,用以注冊混雜設(shè)備 */
static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,   //自動分配次設(shè)備號
    .name  = DEVICE_NAME,
    .fops  = &dev_fops,  //關(guān)聯(lián)你的操作函數(shù)
};
 
static int __init dev_init(void)
{
    int ret;
    int i;
     
    for (i = 0; i < LED_NUM; i++)
    {
        s3c2410_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]);
        s3c2410_gpio_setpin(gpio_table[i], 1);   //開始時LED全亮
    }
 
    ret = misc_register(&misc);  //混雜設(shè)備驅(qū)動注冊
         
    printk ("%s initialized    ---===>>>\n",DEVICE_NAME);
 
    return ret;
}
 
static void __exit dev_exit(void)
{
    misc_deregister(&misc);
    printk ("%s UNloaded  ---===>>>\n",DEVICE_NAME);
 
}
 
module_init(dev_init);
module_exit(dev_exit);
 
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIO control for  My 2440 Board");
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凌唬,隨后出現(xiàn)的幾起案子并齐,更是在濱河造成了極大的恐慌,老刑警劉巖客税,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件况褪,死亡現(xiàn)場離奇詭異,居然都是意外死亡更耻,警方通過查閱死者的電腦和手機测垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酥夭,“玉大人赐纱,你說我怎么就攤上這事“颈保” “怎么了疙描?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讶隐。 經(jīng)常有香客問我起胰,道長,這世上最難降的妖魔是什么巫延? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任效五,我火速辦了婚禮,結(jié)果婚禮上炉峰,老公的妹妹穿的比我還像新娘畏妖。我一直安慰自己,他們只是感情好疼阔,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布戒劫。 她就那樣靜靜地躺著半夷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迅细。 梳的紋絲不亂的頭發(fā)上巫橄,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音茵典,去河邊找鬼湘换。 笑死,一個胖子當著我的面吹牛统阿,可吹牛的內(nèi)容都是我干的彩倚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼砂吞,長吁一口氣:“原來是場噩夢啊……” “哼署恍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜻直,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盯质,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后概而,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呼巷,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年赎瑰,在試婚紗的時候發(fā)現(xiàn)自己被綠了王悍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡餐曼,死狀恐怖压储,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情源譬,我是刑警寧澤集惋,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站踩娘,受9級特大地震影響刮刑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜养渴,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一雷绢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧理卑,春花似錦翘紊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孵滞。三九已至,卻和暖如春鸯匹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泄伪。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工殴蓬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蟋滴。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓染厅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親津函。 傳聞我的和親對象是個殘疾皇子肖粮,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容