驅動04.平臺匯流排驅動模型——點亮LED燈

来源:http://www.cnblogs.com/Lwd-linux/archive/2017/01/09/6265746.html
-Advertisement-
Play Games

1 平臺匯流排的簡介 平臺匯流排是一種虛擬的匯流排,相應的設備則為platform_device,而驅動則為platform_driver。匯流排將設備和驅動綁定,在系統每註冊一個設備的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的設備,而匹配由匯流排完成。 我們可以把一個驅 ...


1 平臺匯流排的簡介

  平臺匯流排是一種虛擬的匯流排,相應的設備則為platform_device,而驅動則為platform_driver。匯流排將設備和驅動綁定,在系統每註冊一個設備的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的設備,而匹配由匯流排完成。

  我們可以把一個驅動程式抽出來分為兩部分,一部分是硬體相關的dev,另一部分則是穩定的純軟體部分driver。而匯流排只是一種機制,把dev和driver這兩部分建立“聯繫”的機制。

eg:

①dev部分

  a.把device放入bus的dev鏈表

  b.從bus的drv鏈表取出每一個drv,用bus的match函數判斷drv是否支持dev

  c.如果支持,將調用drv的probe函數

 

②drv部分

  a.把driver放入bus的drv鏈表

  b.從bus的dev鏈表取出每一個dev,用bus的match函數判斷dev是否支持drv

  c.如果支持,將調用drv的probe函數

2 linux平臺匯流排的代碼分析

struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,  //dev和drv匹配時調用的函數
    .uevent        = platform_uevent,
    .suspend    = platform_suspend,
    .suspend_late    = platform_suspend_late,
    .resume_early    = platform_resume_early,
    .resume        = platform_resume,
};
static int platform_match(struct device * dev, struct device_driver * drv)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);

    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);//當dev的設備名與drv的名字相同時,則匹配成功
}

platform_device
結構體的定義
struct platform_device {
    const char    * name;
    u32        id;
    struct device    dev;
    u32        num_resources;//資源數目
    struct resource    * resource;//設備信息,使用platform_get_resource函數來獲取資源信息
};

註冊平臺設備platform_device_register,實際上是加入到bus的dev鏈表中

1 int platform_device_register(struct platform_device * pdev)
2 {
3     device_initialize(&pdev->dev);//初始化platform_device的device成員
4     return platform_device_add(pdev);//實際上是調用device_add函數
5 }

 同樣的,也有platform_driver結構體的定義

 1 struct platform_driver {
 2     int (*probe)(struct platform_device *);
 3     int (*remove)(struct platform_device *);
 4     void (*shutdown)(struct platform_device *);
 5     int (*suspend)(struct platform_device *, pm_message_t state);
 6     int (*suspend_late)(struct platform_device *, pm_message_t state);
 7     int (*resume_early)(struct platform_device *);
 8     int (*resume)(struct platform_device *);
 9     struct device_driver driver;
10 }
//device_driver的定義:
 1 struct device_driver {
 2     const char        * name;
 3     struct bus_type        * bus;
 4 
 5     struct kobject        kobj;
 6     struct klist        klist_devices;
 7     struct klist_node    knode_bus;
 8 
 9     struct module        * owner;
10     const char         * mod_name;    /* used for built-in modules */
11     struct module_kobject    * mkobj;
12 
13     int    (*probe)    (struct device * dev);
14     int    (*remove)    (struct device * dev);
15     void    (*shutdown)    (struct device * dev);
16     int    (*suspend)    (struct device * dev, pm_message_t state);
17     int    (*resume)    (struct device * dev);
18 };
註冊device_driver結構體:
 1 int driver_register(struct device_driver * drv)
 2 {
 3     if ((drv->bus->probe && drv->probe) ||
 4         (drv->bus->remove && drv->remove) ||
 5         (drv->bus->shutdown && drv->shutdown)) {
 6         printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
 7     }
 8     klist_init(&drv->klist_devices, NULL, NULL);
 9     return bus_add_driver(drv);
10 }
 

3 寫代碼

3.1框架

(1)分配、設置、註冊一個platform_device/platform_driver結構體

(2)按照led.c的框架來構建

3.2 源代碼

 1 #include <linux/module.h>
 2 #include <linux/version.h>
 3 
 4 #include <linux/init.h>
 5 
 6 #include <linux/kernel.h>
 7 #include <linux/types.h>
 8 #include <linux/interrupt.h>
 9 #include <linux/list.h>
10 #include <linux/timer.h>
11 #include <linux/init.h>
12 #include <linux/serial_core.h>
13 #include <linux/platform_device.h>
14 
15 static struct resource myled_dev_resource[] = {
16     [0] = {
17         .start = 0x56000050,
18         .end   = 0x56000050 + 8 - 1,
19         .flags = IORESOURCE_MEM,
20     },
21     [1] = {
22         .start = 6,
23         .end   = 6,
24         .flags = IORESOURCE_IRQ,
25     }
26 };
27 
28 
29 static void myled_dev_release(struct device * dev)
30 {
31 }
32 
33 
34 static struct platform_device myled_dev = {
35     .name          = "myled",
36     .id       = -1,
37     .num_resources      = ARRAY_SIZE(myled_dev_resource),
38     .resource      = myled_dev_resource,
39     .dev              = {
40         .release   = myled_dev_release,
41     }
42 };
43 
44 static int myled_dev_init(void)
45 {
46     platform_device_register(&myled_dev);
47     return 0;
48 }
49 
50 static void myled_dev_exit(void)
51 {
52     platform_device_unregister(&myled_dev);
53 }
54 
55 module_init(myled_dev_init);
56 module_exit(myled_dev_exit);
57 
58 MODULE_LICENSE("GPL");
myled_dev.c
  1 #include <linux/module.h>
  2 #include <linux/version.h>
  3 
  4 #include <linux/init.h>
  5 #include <linux/fs.h>
  6 #include <linux/interrupt.h>
  7 #include <linux/irq.h>
  8 #include <linux/sched.h>
  9 #include <linux/pm.h>
 10 #include <linux/sysctl.h>
 11 #include <linux/proc_fs.h>
 12 #include <linux/delay.h>
 13 #include <linux/platform_device.h>
 14 #include <linux/input.h>
 15 #include <linux/irq.h>
 16 #include <asm/uaccess.h>
 17 #include <asm/io.h>
 18 
 19 
 20 
 21 static struct class *g_ptMyledCls;
 22 static struct class_device    *g_ptMyledClsDev;
 23 static int g_iPin;
 24 
 25 volatile unsigned long *gpiocon = NULL;
 26 volatile unsigned long *gpiodat = NULL;
 27 
 28 
 29 static int myled_open(struct inode *inode, struct file *file)
 30 {
 31     //printk("first_drv_open\n");
 32     /* 配置GPF4,5,6為輸出 */
 33     *gpiocon &= ~(0x3<<(g_iPin*2)) ;
 34     *gpiodat |= (0x1<<(g_iPin*2)) ;
 35     return 0;
 36 }
 37 
 38 static ssize_t myled_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 39 {
 40     int val;
 41 
 42     //printk("first_drv_write\n");
 43 
 44     copy_from_user(&val, buf, count); //    copy_to_user();
 45 
 46     if (val == 1)
 47     {
 48         // 點燈
 49         *gpiodat &= ~(1<<g_iPin);
 50     }
 51     else
 52     {
 53         // 滅燈
 54         *gpiodat |= (1<<g_iPin);
 55     }
 56     
 57     return 0;
 58 }
 59 
 60 
 61 static struct file_operations myled_fops = {
 62     .owner  =   THIS_MODULE,    /* 這是一個巨集,推向編譯模塊時自動創建的__this_module變數 */
 63     .open    =  myled_open,     
 64     .write      =    myled_write,       
 65 };
 66 
 67 
 68 static int g_iMajor;
 69 
 70 static int myled_probe(struct platform_device *dev)
 71 {    
 72     struct resource *tRes;
 73     tRes = platform_get_resource(dev, IORESOURCE_MEM, 0);
 74     gpiocon = ioremap(tRes->start, tRes->end - tRes->start +1);
 75     gpiodat = gpiocon + 1;
 76 
 77     tRes    = platform_get_resource(dev, IORESOURCE_IRQ, 0);
 78     g_iPin = tRes->start;
 79 
 80     printk("myled_probe, found led\n");
 81     
 82     g_iMajor = register_chrdev(0, "myled", &myled_fops); // 註冊, 告訴內核
 83     g_ptMyledCls = class_create(THIS_MODULE, "myled");
 84 
 85     g_ptMyledClsDev = class_device_create(g_ptMyledCls, NULL, MKDEV(g_iMajor, 0), NULL, "myled"); /* /dev/xyz */
 86     return 0;
 87 }
 88 
 89 static int myled_remove(struct platform_device *dev)
 90 {
 91     printk("led_remove, remove led\n");
 92 
 93     class_device_destroy(g_ptMyledCls, MKDEV(g_iMajor, 0));
 94     class_destroy(g_ptMyledCls);
 95     unregister_chrdev(g_iMajor, "myled");
 96     iounmap(gpiocon);
 97     
 98     return 0;
 99 }
100 
101 static struct platform_driver myled_driver = {
102     .probe        = myled_probe,
103     .remove        = myled_remove,
104     .driver        = {
105         .name        = "myled",
106     },
107 };
108 
109 static int myled_drv_init(void)
110 {
111     platform_driver_register(&myled_driver);
112     return 0;
113 }
114 
115 static void myled_drv_exit(void)
116 {
117     platform_driver_unregister(&myled_driver);
118 }
119 
120 
121 module_init(myled_drv_init);
122 module_exit(myled_drv_exit);
123 
124 MODULE_LICENSE("GPL");
myled_drv.c
 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <stdio.h>
 5 
 6 /* firstdrvtest on
 7   * firstdrvtest off
 8   */
 9 int main(int argc, char **argv)
10 {
11     int fd;
12     int val = 1;
13     fd = open("/dev/myled", O_RDWR);
14     if (fd < 0)
15     {
16         printf("can't open!\n");
17     }
18     if (argc != 2)
19     {
20         printf("Usage :\n");
21         printf("%s <on|off>\n", argv[0]);
22         return 0;
23     }
24 
25     if (strcmp(argv[1], "on") == 0)
26     {
27         val  = 1;
28     }
29     else
30     {
31         val = 0;
32     }
33     
34     write(fd, &val, 4);
35     return 0;
36 }
測試程式

編輯於2017-01-09 16:36:01

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 參考s3c2410fb.c總結出框架 1.代碼分析 1.1 入口函數 註冊一個platform_driver結構體,如果存在同名的設備dev時,將調用probe函數。 搜索s3c2410-lcd可得下麵的s3c_device_lcd結構體 1.2 probe函數(只列出關鍵性代碼) 由此可知,其主要 ...
  • 一、 下載mysql5.7 http://mirrors.sohu.com/mysql/MySQL-5.7/ Linux下載: 輸入命令:wget http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.17-linux-glibc2.5-x86_64.t ...
  • 我們平時在做web開發運行web伺服器或運行某個應用時會報錯,提示該應用的埠號已被占用,我們可以用以下的方法解決。 解決方法一:重新為應用配置埠。 解決方法二:找到占用埠的應用並關閉該應用釋放占用的埠: 1、win+r運行cmd或在開菜單的運行中運行 2、運行命令 netstat -aon| ...
  • 系統window8.1 1、安裝IIS組件:點開始菜單—選擇控制面板——程式——打開或關閉WINDOWS功能——展開Internet信息服務,勾選FTP伺服器(包括FTP服務和FTP擴展性),點確定。 由於我的電腦已將安裝了IIS服務所以找不到了,不知道你電腦有沒有安裝可以在 控制面板\所有控制面板 ...
  • 運行級別 說明 0 系統關機狀態 1 單用戶工作狀態,用於root對系統進行維護,此時不予許其他用戶使用主機。(類似於windows 的安全模式) 2 多用戶狀態(沒有NFS) 3 多用戶狀態(有NFS),主機做為伺服器常在該模式下工作 4 系統未定義 5 多用戶狀態,並且在系統啟動後運行xwind ...
  • 我這裡要講的並不是IPC中的消息隊列,我要講的是在進程內部實現自定義的消息隊列,讓各個線程的消息來推動整個進程的運動。進程間的消息隊列用於進程與進程之間的通信,而我將要實現的進程內的消息隊列是用於有序妥當處理來自於各個線程請求,避免一窩蜂的請求而導致消息的異常丟失。想想socket編程里的liste ...
  • Linux系統下給非root用戶添加sudo許可權 有時,在linux系統中非root用戶運行sudo命令,會提示類似信息: xxx is not in the sudoers file. This incident will be reported. 這裡,xxx是當前用戶名,該用戶無法執行sudo ...
  • 鏈接: top:命令提供了實時的對系統處理器的狀態監視.它將顯示系統中CPU最“敏感”的任務列表. 該命令可以按CPU使用.記憶體使用和執行時間對任務進行排序; 而且該命令的很多特性都可以通過互動式命令或者在個人定製文件中進行設定. top - 01:06:48 up 1:22, 1 user, lo ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...