娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

ARM Linux字符設備驅動程序

發布者:Qianfeng最新更新時間:2024-08-21 來源: cnblogs關鍵字:ARM  Linux  字符設備  驅動程序 手機看文章 掃描二維碼
隨時隨地手機看文章

1、主設備號和次設備號(二者一起為設備號):

一個字符設備或塊設備都有一個主設備號和一個次設備號。主設備號用來標識與設備文件相連的驅動程序,用來反  映設備類型。次設備號被驅動程序用來辨別操作的是哪個設備,用來區分同類型的設備。


linux內核中,設備號用dev_t來描述,2.6.28中定義如下:


typedef u_long dev_t;

在32位機中是4個字節,高12位表示主設備號,低12位表示次設備號。


可以使用下列宏從dev_t中獲得主次設備號:                   


也可以使用下列宏通過主次設備號生成dev_t:

MAJOR(dev_t dev);


MKDEV(int major,int minor);


MINOR(dev_t dev);


//宏定義:

#define MINORBITS    20

#define MINORMASK    ((1U << MINORBITS) - 1)  //1U后面的U表示1是unsigned int (如果是在VS編譯器下的話,就是32位),把1U左移(<<,這是位運算符號,按位左移)20位就相當于1 * 2^20,然后-1,也就是mask替代了(2^20-1)。

                                              //得到的結果就是高12位全為0,低20位全為1

#define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))

#define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))

#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))


2.分配設備號(兩種方法)


(1靜態申請


int register_chrdev_region(dev_t from,unsigned count,const char *name);


 (2)動態分配


int alloc_chardev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name);


注銷設備號:


void unregister_chrdev_region(dev_t from, unsigned count);


創建設備文件:


利用cat /proc/devices查看申請到的設備名,設備號。


(1)使用mknod手工創建:mknod filename type  major minor


 (2) 自動創建:


利用udev(mdev)來實現設備文件的自動創建,首先應保證支持udev(mdev),由busybox


配置,在驅動初始化代碼里調用class_create為該設備創建一個class,再為每個設備調用device_create


創建對應的設備。


3、字符設備驅動程序重要的數據結構

(1)struct file:


代表一個打開的文件描述符,系統中每一個打開的文件在內核中都有一個關聯的struct file。它由內核在open時創建,并傳遞給在文件上操作的任何函數,直到最后關閉。當文件的所有實例都關閉之后,內核釋放這個數據結構。


 //重要成員


const struct file_operations *f_op;  //該操作是定義文件關聯操作的。內核在執行open時對這個指針賦值。


 off_t f_pos;                  //該文件讀寫位置。


 void  *private_data;          //該成員是系統調用時保存狀態信息非常有用的資源。


  2)struct inode:


用來記錄文件的物理信息。它和代表打開的file結構是不同的。一個文件可以對應多個file結構,但只有一個inode結構。inode一般作為file_operations結構中函數的參數傳遞過來。


inode譯成中文就是索引節點。每個存儲設備或存儲設備的分區(存儲設備是硬盤、軟盤、U盤 ... ... )被格式化為文件系統后,應該有兩部份,一部份是inode,另一部份是Block,Block是用來存儲數據用的。而inode呢,就是用來存儲這些數 據的信息,這些信息包括文件大小、屬主、歸屬的用戶組、讀寫權限等。inode為每個文件進行信息索引,所以就有了inode的數值。操作系統根據指令, 能通過inode值最快的找到相對應的文件。


 dev_t i_rdev;   //對表示設備文件的inode結構,該字段包含了真正的設備編號。


 struct cdev *i_cdev;   //是表示字符設備的內核的內部結構,當inode指向一個字符設備文件時,該字段包含了指向struct_cdev結構的指針。


我們也可以使用下邊兩個宏從inode中獲得主設備號和次設備號


unsigned int iminor(struct inode *inode);


unsigned int imajor(struct inode *inode);


 


 (3)struct file_operations


   struct file_operation ***_ops={


 .owner=THIS_MODULE,


 .llseek=***_llseek,


 .read=***_read,


 .write=***_write,


 .ioctl=***_ioctl,


 .open=***_open,


 .release=***_release,


 .....


};   //strude file_operations 是一個函數指針的集合


struct module *owner;


字符設備驅動程序注意事項


 1)open()調用可能由于幾個原因而失敗。


(2)成功運行的read()和write()返回的字節數可能是1至請求的字節數之間的任意值,因此應用程序必須能處理這些情況。

(3)即使1字節的數據讀或寫就緒,select()也會返回成功。

(4)很多字符驅動程序方法是可選的,并不是所有的方法都提供。

另外,字符驅動程序不僅在drivers/char/目錄下。下面是一些“超級”字符驅動程序:

(1)串行驅動程序,放在drivers/serial/目錄下。

(2)輸入驅動程序,放在drivers/input/目錄下。

(3)幀緩存區(/dev/fb/*)提供對顯存的訪問,/dev/mem提供對系統內存的訪問途徑。

(4)一些設備類支持少量采用字符接口的硬件。

(5)一些子系統提供額外的字符接口,以向用戶空間提供原始的設備模型。例如MTD子系統。

(6)一些內核層提供鉤子,通過導出相應的字符接口實現用戶空間的設備驅動程序。 例如ioctl。

在drivers/目錄下的register_chrdev上運行grep-r可了解內核中字符驅動程序的大致情況。

 


 設備驅動程序是內核的一部分,它完成以下的功能


1、對設備初始化和釋放;


(1)字符設備cdev結構體初始化:


***********不是每個字符設備驅動都需要,cdev是為了構建設備模型,便于設備文件的管理所產生的。如果你的字符設備比較簡單或者你不需要構建設備模型,是可以不需要cdev.

file_operation結構是虛擬層上的東西,這樣使得驅動程序可以操作設備。*******************

           內核中每個字符設備都對應一個 cdev 結構的變量,下面是它的定義: linux-2.6.22/include/linux/cdev.h

struct cdev {

   struct kobject kobj;          // 每個 cdev 都是一個 kobject

   struct module *owner;       // 指向實現驅動的模塊

   const struct file_operations *ops;   // 操縱這個字符設備文件的方法

   struct list_head list;       // 與 cdev 對應的字符設備文件的 inode->i_devices 的鏈表頭

   dev_t dev;                   // 起始設備編號

   unsigned int count;       // 設備范圍號大小

};

        靜態內存定義初始化:

                        struct cdev my_cdev;

                        cdev_init(&my_cdev, &fops);

                        my_cdev.owner = THIS_MODULE;


                        void cdev_init(struct cdev *cdev, const struct file_operations *fops)

                        {

                           memset(cdev, 0, sizeof *cdev);

                           INIT_LIST_HEAD(&cdev->list);

                           kobject_init(&cdev->kobj, &ktype_cdev_default);

                           cdev->ops = fops;

}      


      


        動態內存定義初始化:

                        struct cdev *my_cdev = cdev_alloc();

                        my_cdev->ops = &fops;

                        my_cdev->owner = THIS_MODULE;

                        struct cdev *cdev_alloc(void)

                        {

                         struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);

                         if (p) {

                                 INIT_LIST_HEAD(&p->list);

                                 kobject_init(&p->kobj, &ktype_cdev_dynamic);

                                }

                         return p;

                        }

 


        


             由此可見,兩個函數完成都功能基本一致,只是 cdev_init() 還多賦了一個 cdev->ops 的值。

      初始化 cdev 后,需要把它添加到系統中去。為此可以調用 cdev_add() 函數。傳入 cdev 結構的指針,起始設備編號,以及設備編號范圍。

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

{

   p->dev = dev;

   p->count = count;

   return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);

}

關 于 kobj_map() 函數就不展開了,我只是大致講一下它的原理。內核中所有都字符設備都會記錄在一個 kobj_map 結構的 cdev_map 變量中。這個結構的變量中包含一個散列表用來快速存取所有的對象。kobj_map() 函數就是用來把字符設備編號和 cdev 結構變量一起保存到 cdev_map 這個散列表里。當后續要打開一個字符設備文件時,通過調用 kobj_lookup() 函數,根據設備編號就可以找到 cdev 結構變量,從而取出其中的 ops 字段。

當一個字符設備驅動不再需要的時候(比如模塊卸載),就可以用 cdev_del() 函數來釋放 cdev 占用的內存。

void cdev_del(struct cdev *p)

{

   cdev_unmap(p->dev, p->count);

   kobject_put(&p->kobj);

}

其中 cdev_unmap() 調用 kobj_unmap() 來釋放 cdev_map 散列表中的對象。kobject_put() 釋放 cdev 結構本身。

 


下面這個是必須要有的:


設備初始化


 


 static int first_drv_init(void)           

 {

   major=register_chrdev(0,'first_drv',&first_drv_fops); //注冊,告訴內核。

   firstdrv_class=class_create(THIS_MODULE,'firstdrv');   //創建一個類

   if(IS_ERR(firstdrv_class))

   return PTR_ERR(firstdrv_class);

   

   firstdrv_class_dev=class_device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,'xyz');//xyz為設備名字

   gpfcon=(volatile unsigned long *)ioremap(0x56000050,16);

   gpfdat=gpfcon+1;

   if(unlikely(IS_ERR(firstdrv_class_dev)))

   return PTR_ERR(firstdev_class_drv);

   return 0;

 }

 

 設備卸載

 static vodi first_drv_exit(void)

 {

   unregister_chrdev(major,'first_drv');//卸載

   class_device_unregister(firstdrv_class_dev);

   class_destroy(firstdrv_class);

   iounremap();

 }

 

 


  2、把數據從內核傳送到硬件(copy_to_user)和從硬件讀取數據(copy_form_user);


 結構體file_operations在頭文件 linux/fs.h中定義,用來存儲驅動內核模塊提供的對設備進行各種操作的函數的指針。該結構體的每個域都對應著驅動內核模塊用來處理某個被請求的 事務的函數的地址。


     fileoprations結構體上定義的函數進行具體的數據操作。


 


static struct  file_operations second_drv fops={

        .owner=THIS_MODULE;

        .write=second_drv_write;

        .open=second_drv_open;

        .read=second_drv_read;

        }    

        

      int major;

 

 


      


static int first_drv_open(struct inode *inode,struct file *file)

    {

     gpfcon &= ~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2)));    //GPF4,5,6為輸出

     gpfcon |=  ((0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)));    //

     

     return 0;

    }

 

 static ssize_t first_drv_read(struct inode *inode,struct file *file)

    {

      

      return 0;

    }

    

    static ssize_t first_drv_write(struct file *file,const char _user *buf,size_t count,loff_t *ppos)

    {

      int val;

[1] [2]
關鍵字:ARM  Linux  字符設備  驅動程序 引用地址:ARM Linux字符設備驅動程序

上一篇:s3c2440串口裸板驅動(使用fifo)
下一篇:Linux設備驅動中的異步通知與異步I/O

0

推薦閱讀最新更新時間:2025-03-26 12:15

【IMX6ULL學習筆記】十二、Linux字符設備
一、新字符設備驅動原理 1.1 分配和釋放設備號 使用 register_chrdev 函數注冊字符設備的時候只需要給定一個主設備號即可,但是這樣會帶來兩個問題: ①、需要我們事先確定好哪些主設備號沒有使用。 ②、會將一個主設備號下的所有次設備號都使用掉 解決辦法就是在要使用設備號的時候向 Linux 內核申請。 如果沒有指定設備號的話就使用如下函數來申請設備號,定義在 /fs/char_dev.c 中文件中: int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) 在注冊字符設備之前先申請一個設備號
[單片機]
linux 一個簡單的字符設備驅動例子
先包含這些頭文件 #include linux/module.h #include linux/types.h #include linux/fs.h #include linux/errno.h #include linux/mm.h #include linux/sched.h #include linux/init.h #include linux/cdev.h #include asm/io.h #include asm/system.h #include asm/uaccess.h #define BUFFERSIZE 200 #define DEVICE_MAJOR 250 /*設置一個主設備號*/ static
[嵌入式]
嵌入式Linux操作系統的驅動程序開發要點
在Linux操作系統下有3類主要的設備文件類型:塊設備、字符設備和網絡設備。這種分類方法可以將控制輸入/輸出設備的驅動程序與其他操作系統軟件分離開來。 字符設備與塊設備的主要區別是:在對字符設備發出讀/寫請求時,實際的硬件I/O一般緊接著發生。塊設備則不然,它利用一塊系統內存作為緩沖區,若用戶進程對設備的請求能滿足用戶的要求,就返回請求的數據;否則,就調用請求函數來進行實際的I/O操作。塊設備主要是針對磁盤等慢速設備設計的,以免耗費過多的CPU時間用來等待。網絡設備可以通過BSD套接口訪問數據。 每個設備文件都有其文件屬性(c/b),表示是字符設備還是塊設備。另外每個文件都有2個設備號,第一個是主設備號,標識驅動程序;第二個是
[應用]
arm-linux-gcc .s 和 .S 的區別 !
unix/linux 對 大小寫敏感: .s 操作 :匯編 .S 操作 : cpp + 匯編 eg: /* start.s */ #define rTEXT 0x12345678 LDR R0,=rTEXT .... # arm-linux-gcc -g -c -nostdlib start.s -o start.o # nm -u start.o rTEXT # arm-linux-objdump -S -t start.o start.l # cat start.i | grep ''R0 LDR R0,【PC,#0】 經典錯誤: arm-linux-gcc 將.s 文件誤認為cpp處理后
[單片機]
ARM協處理器訪問指令(Linux學習記錄)
什么是協處理器? 協處理器用于執行特定的處理任務,如:數學協處理器可以控制數字處理,以減輕處理器的負擔。ARM可支持多達16個協處理器,其中CP15是最重要的一個。 CP15的作用? 系統控制協處理器,CP15提供額外的寄存器,用于配置和控制緩存。MMU,保護系統,時鐘模式,以及其他的系統選項,如大或小門的操作。 如何訪問CP15? 通過CP15提供的16組寄存器,來達到訪問目的。 協處理器訪問:mcr (把通用寄存器的值復制或移動到協處理器中的寄存器中)、mrc(把協處理器中的寄存器的值復制或移動到通用寄存器中) 訪問例: MCR{cond} P15, Opcode_1 , Rd , CRn , C
[單片機]
基于ARM-LINUX的溫度傳感器驅動(DS18B20)
DS18B20數字溫度傳感器接線方便,封裝成后可應用于多種場合,如管道式,螺紋式,磁鐵吸附式,不銹鋼封裝式,型號多種多樣,有LTM8877,LTM8874等等。主要根據應用場合的不同而改變其外觀。封裝后的DS18B20可用于電纜溝測溫,高爐水循環測溫,鍋爐測溫,機房測溫,農業大棚測溫,潔凈室測溫,彈藥庫測溫等各種非極限溫度場合。耐磨耐碰,體積小,使用方便,封裝形式多樣,適用于各種狹小空間設備數字測溫和控制領域。 技術性能描述 1. 獨特的單線接口方式,DS18B20在與微處理器連接時僅需要一條口線即可實現微處理器與DS18B20的雙向通訊。 2. 測溫范圍 -55℃~+125℃,固有測溫分辨率0.5℃。 3. 支持
[單片機]
基于<font color='red'>ARM</font>-<font color='red'>LINUX</font>的溫度傳感器驅動(DS18B20)
arm-linux交叉編譯ACE
ACE應用于主站數據采集核心的開發已告一段落了。現在打算涉足嵌入式linux應用程序的設計。俗話說“工欲善其事,必先利其器”,ACE支持arm系列的嵌入式系統,當然首先折騰他了,后期還打算整整apache的運行時庫apr。嵌入式系統的仿真平臺采用skyeye,在這樣一個平臺里我已經實現了nfs mount 宿主機目錄。測試交叉編譯后的程序十分方便。 網上搜到一篇《機電之家 嵌入式Linux系統攻略--ACE程序移植過程詳細解析》交叉編譯工具是Moxa tool chain for DA66x,寫的滿詳細,主要參照它就完成了arm-linux的交叉編譯。詳細過程如下: 1.解壓ace源代碼到/root 2.設置環境變量ACE_
[單片機]
<font color='red'>arm</font>-<font color='red'>linux</font>交叉編譯ACE
基于ARM的嵌入式Linux移植真實體驗(1)――基本概念
1.引言 ARM是Advanced RISC Machines(高級精簡指令系統處理器)的縮寫,是ARM公司提供的一種微處理器知識產權(IP)核。 ARM的應用已遍及工業控制、消費類電子產品、通信系統、網絡系統、無線系統等各類產品市場?;贏RM 技術的微處理器應用約占據了32位RISC 微處理器75%以上的市場份額。揭開你的手機、MP3、 PDA,嘿嘿,里面多半藏著一個基于ARM的微處理器! ARM內核的數個系列(ARM7、ARM9、ARM9E、ARM10E、SecurCore、Xscale、StrongARM),各自滿足不同應用領域的需求,無孔不入的滲入嵌入式系統各個角落的應用。這是一個ARM的時代! 下面的圖片顯示了AR
[單片機]
基于<font color='red'>ARM</font>的嵌入式<font color='red'>Linux</font>移植真實體驗(1)――基本概念
添点儿料...
无论热点新闻、行业分析、技术干货……
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 大港区| 常山县| 呈贡县| 宜州市| 兰州市| 吉安市| 长宁县| 科技| 兴仁县| 巴青县| 波密县| 钟祥市| 睢宁县| 灵川县| 屯昌县| 青神县| 棋牌| 克山县| 于田县| 华宁县| 平阳县| 彭山县| 峨山| 郸城县| 浠水县| 澳门| 山东省| 阿克陶县| 阿拉善左旗| 高要市| 漾濞| 玉田县| 连江县| 聊城市| 江孜县| 搜索| 建德市| 威远县| 平顶山市| 新蔡县| 楚雄市|