<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 189,comments - 115,trackbacks - 0

    linux下的GPIO驅動 2009-06-05 08:29

    字號:    

    編寫驅動程序,首先要了解是什么類型的設備。linux下的設備分為三類,分別為:字符設備,塊設備和網絡設備。字符設備類型是根據是否以字符流為數據的交換方式,大部分設備都是字符設備,如鍵盤,串口等,塊設備則是以塊為單位進行管理的設備,如,磁盤。網絡設備就是網卡等。

    其次要了解應用程序和驅動程序的區別,兩者的主要區別分為以下三點:

    1入口函數的任務不相同,應用程序完成一個任務,驅動只完成初始化工作,比如中斷

          申請,寄存器設置,定時器設置。

    2運行時的cpu模式不相同,驅動具有很高的權限,應用程序是在用戶態下運行,而驅

      動程序是在內核態下執行。

    3 驅動程序不能調用C庫函數,內核為驅動程序提供一些函數。如printk(KERN_NOTICE fmt, ##arg),第一個參數為打印級別,有如下的打印級別:

    KERN_EMERG 用于緊急事件,一般是系統崩潰前的提示信息

    KERN_ALERT 用于需要立即采取動作的場合

    KERN_CRIT 臨界狀態,通常設計驗證的硬件或軟件操作失敗

    KERN_ERR 用于報告錯誤狀態.設備驅動程序通常會用它報告來自硬件的問題

    KERN_WARNING 就可能出現的問題提出警告.這些問題通常不會對系統造成嚴重破壞

    KERN_NOTICE 有必要提示的正常情況.許多安全相關的情況用這個級別匯報

    KERN_INFO 提示性信息.有很多驅動程序在啟動時用這個級別打印相關信息

    KERN_DEBUG 用于調試的信息

    u_long copy_from_user(void *to, const void *from, u_long len),由用戶態拷貝到內核態;

    u_long copy_to_user(void * to, const void *from, u_long len),由內核態拷貝到用戶態。

    鑒于以上區別,驅動程序需要完成以下三點基本功能:

    1:要對設備進行初始化和釋放功能模塊,就如上面的寄存器設置,中斷的申請,向內核注 

       冊驅動程序(register_chrdev()),卸載驅動程序(unregister_chrdev())。

    2:能進行數據傳輸,在read(),write()函數里具體實現,數據傳輸工作。

    3:能進行控制操作,給用戶提供的ioctl()函數里可實現一些用戶的選擇性設置功能。

    確定一個設備的執行函數集(結構體)

    static struct file_operations myGPIO_fops = {

    owner: THIS_MODULE,

    write: myGPIO_write,

    read: myGPIO_read,

    ioctl: myGPIO_ioctl,

    open: myGPIO_open,

    release: myGPIO_release,

    };

    接下來是初始化工作,需要寫在一個init()函數中,這個函數是獨立的也是自動執行的,在這之中主要是對一些寄存器進行初始化操作。同樣需要完成卸載驅動模塊。

    myGPIO_Major = register_chrdev(0, DRIVER_NAME, &myDriver_fops);

    上面的程序完成設備號的注冊,第一個參數為主設備號,一般為0,由系統來分配。

    第二個參數為設備名,這需要在/dev/(/dev目錄下設備名由命令 <mknod  設備名 C 主設備號  從設備號>來生成)目錄下出現的設備名相符合。相反的在卸載中就取消注冊

    unregister_chrdev(myGPIO_Major, DRIVER_NAME);

    最后將這兩個模塊加入到內核中,由程序段的最后兩行完成。

    static int __init myGPIO_init(void)

    {

    PRINTK("GPIO init\n");

    myGPIO_Major = register_chrdev(0, DRIVER_NAME, &myGPIO_fops);

    if(myGPIO_Major < 0)

    {

    PRINTK("register char device fail!\n");

    return myGPIO_Major;

    }

    PRINTK("register myGPIO OK! Major = %d\n", myGPIO_Major);

    #ifdef CONFIG_DEVFS_FS

    devfs_myDriver_dir = devfs_mk_dir(NULL, "GPIO", NULL);

    devfs_myDriver_raw = devfs_register(devfs_myDriver_dir, "raw0", DEVFS_FL_DEFAULT, myGPIO_Major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &myGPIO_fops, NULL);

    PRINTK("add dev file to devfs OK!\n");

    #endif

    return 0;

    }

    static void __exit myGPIO_exit(void)

    {

    /* Module exit code */

    PRINTK("GPIO exit\n");

    /* Driver unregister */

    if(myGPIO_Major > 0)

    {

    #ifdef CONFIG_DEVFS_FS

    devfs_unregister(devfs_myDriver_raw);

    devfs_unregister(devfs_myDriver_dir);

    #endif

    unregister_chrdev(myGPIO_Major, DRIVER_NAME);

    }

    return;

    }

    MODULE_AUTHOR("LiuFan");

    MODULE_LICENSE("Dual BSD/GPL");

    module_init(myGPIO_init);

    module_exit(myGPIO_exit);

    設備執行函數功能的實現將在下面完成。如結構體的函數,但并不是全都需要實現。open()函數中是執行一些設備工作前的初始化工作。rlease()則是將設備的相關寄存器恢復到原來的值。read()函數是將設備中的數據拷貝到內核,write()函數是將內核數據拷貝到對應的設備中。MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT兩個宏是提供給系統對硬件資源進行控制訪問的。在open()和rlease()兩個函數中最基本的操作應是實現以上兩個宏的操作。

    static unsigned char myGPIO_Buffer[1024*1024];

    /* Driver Operation Functions */

    static int myGPIO_open(struct inode *inode, struct file *filp)

    {

    // int Minor = MINOR(inode->i_rdev);

    // filp->private_data = 0;

    MOD_INC_USE_COUNT;

    PRINTK("myDriver open called!\n");

    return 0;

    }

    static int myGPIO_release(struct inode *inode, struct file *filp)

    {

    // int Minor = MINOR(inode->i_rdev);

    MOD_DEC_USE_COUNT;

    PRINTK("myDriver release called!\n");

    return 0;

    }

    static ssize_t myGPIO_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)

    {

    char dat;

    size_t read_size = count;

    PRINTK("GPIO read called!\n");

    PRINTK("\tcount=%d, pos=%d\n", count, (int)*f_pos);

    /* if(*f_pos >= sizeof(myGPIO_Buffer))

    {

    PRINTK("[GPIO read]Buffer Overlap\n");

    *f_pos = sizeof(myGPIO_Buffer);

    return 0;

    }

    if((count + *f_pos) > sizeof(myGPIO_Buffer))

    {

    PRINTK("count + f_pos > sizeof buffer\n");

    read_size = sizeof(myGPIO_Buffer) - *f_pos;

    }*/

    dat= GPFDAT;

    copy_to_user(buf,&dat,1);

    // *f_pos += read_size;

    return read_size;

    }

    static ssize_t myGPIO_write(struct file *filp,const char *buf, size_t count, loff_t *f_pos)

    {

    char dat;

    size_t fill_size = count;

    PRINTK("myDriver write called!\n");

    PRINTK("\tcount=%d, pos=%d\n", count, (int)*f_pos);

    if(*f_pos >= sizeof(myGPIO_Buffer))

    {

    PRINTK("[myDriver write]Buffer Overlap\n");

    *f_pos = sizeof(myGPIO_Buffer);

    return 0;

    }

    if((count + *f_pos) > sizeof(myGPIO_Buffer))

    {

    PRINTK("count + f_pos > sizeof buffer\n");

    fill_size = sizeof(myGPIO_Buffer) - *f_pos;

    }

    copy_from_user(&dat,buf,fill_size);

    GPFDAT = dat;

    // *f_pos += fill_size;

    return fill_size;

    }

    控制ioctl() 函數則是提供給應用層的接口函數,功能并不是固定的,由開發者定義,一般都是對硬件的一些除過上述功能的其他操作。

    static int myGPIO_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

    {

    int i;

    unsigned int mask=0x01;

    GPFUP = 0x00;

    PRINTK("myGPIO ioctl called(%d)!\n", cmd);

        switch(cmd)

    {

    case MOD_IN:

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

    {

    if((mask & arg)!=0x0)

    {

    GPFCON &=~(3<<i*2); 

    }

    mask =mask << 1;

    }

    break;

    case MOD_OUT:

     PRINTK("IOCTRL 0 called(0x%lx)!\n", arg);

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

     {

     if((mask & arg)!=0x00)

     {

            GPFCON &= ~(3 <<( i*2));

    GPFCON |=(0x01<<(i*2));

     }

    mask=mask<<1;

     }

     break;

    case MOD_EXIT_INT:

    PRINTK("IOCTRL 1 called(0x%lx)!\n", arg);

    GPFDAT = 0xFFFFFF00;

    break;

    default:

    break;

    }

    return 0;

    }

    posted on 2009-06-11 21:30 MEYE 閱讀(2620) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 亚洲国产欧美一区二区三区 | 免费大片av手机看片| 2021免费日韩视频网| 亚洲AV日韩精品久久久久| 黄色免费在线网站| 亚洲va中文字幕无码久久不卡| a级片免费观看视频| 亚洲综合日韩久久成人AV| 岛国岛国免费V片在线观看| 好看的电影网站亚洲一区| 在线观看特色大片免费网站| 亚洲国产精品无码av| 久久免费看少妇高潮V片特黄| 亚洲高清国产拍精品26U| 热re99久久6国产精品免费| 亚洲国产福利精品一区二区| 歪歪漫画在线观看官网免费阅读| 亚洲欧美中文日韩视频| 亚洲Aⅴ无码一区二区二三区软件| 日韩精品视频在线观看免费| 亚洲日本一区二区三区在线| 日本免费一区二区三区四区五六区| ass亚洲**毛茸茸pics| 精品久久免费视频| free哆拍拍免费永久视频| 亚洲av永久无码精品网站| 国产卡一卡二卡三免费入口| 国产成人综合亚洲| 亚洲AV中文无码字幕色三| 很黄很黄的网站免费的| 免费人成大片在线观看播放电影| 国产精品亚洲成在人线| 最新仑乱免费视频| 一级免费黄色毛片| 亚洲沟沟美女亚洲沟沟| 亚洲国产成人爱av在线播放| 精品成人免费自拍视频| 亚洲色大成网站www久久九| 久久亚洲国产精品五月天婷| 4455永久在线观免费看| 成人嫩草影院免费观看|