怎么安裝pos機驅(qū)動,字符設備驅(qū)動

 新聞資訊  |   2023-05-04 09:57  |  投稿人:pos機之家

網(wǎng)上有很多關于怎么安裝pos機驅(qū)動,字符設備驅(qū)動的知識,也有很多人為大家解答關于怎么安裝pos機驅(qū)動的問題,今天pos機之家(m.afbey.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!

本文目錄一覽:

1、怎么安裝pos機驅(qū)動

怎么安裝pos機驅(qū)動

前言

字符設備驅(qū)動是Linux最基本的驅(qū)動,很多學習驅(qū)動的朋友都是從這個開始的,比如LED,或者按鍵驅(qū)動等。但是很多時候你看一些視頻教程或書籍時,會發(fā)現(xiàn)其實不是很完整,特別是既看書又看視頻教程的,會發(fā)現(xiàn)好像不怎么一樣。接下來一起來總結(jié)一下!

字符設備結(jié)構(gòu)體

在Linux內(nèi)核中, 使用cdev結(jié)構(gòu)體來描述一個字符設備。

struct cdev { struct kobject kobj; //內(nèi)嵌的kobject對象 struct module *owner;//所屬模塊 const struct file_operations *ops; //文件操作結(jié)構(gòu)體 struct list_head list; dev_t dev; //設備號 unsigned int count;};

cdev結(jié)構(gòu)體的dev_t成員定義了設備號,為32位,其中12位為主設備號,20位為次設備號。

使用下面的宏來定義dev_t

MKDEV(int major, int minor)

使用下面的宏來獲取主設備號和次設備號

MAJOR(dev_t dev)MINOR(dev_t dev)字符設備API

/*函數(shù)功能:分配一些設備號參數(shù)說明: from:起始設備號,必須要包含主設備號 count: 連續(xù)分配的數(shù)量 name: 設備或驅(qū)動的名稱*/int register_chrdev_region(dev_t from, unsigned count, const char *name)/*函數(shù)功能:分配一些字符設備號參數(shù)說明: dev:第一個被分配的設備號 baseminor:起始次設備號 count:分配的次設備號數(shù)(分配的設備號數(shù)) name: 相關設備或驅(qū)動的名稱*/int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)/*函數(shù)功能: 釋放一些設備號參數(shù)說明: from:釋放的起始設備號 count: 釋放的設備號數(shù)*/ void unregister_chrdev_region(dev_t from, unsigned count)

/*函數(shù)功能:初始化一個cdev結(jié)構(gòu)體參數(shù)說明: cdev:要初始化的cdev結(jié)構(gòu)體 fops:該字符設備的file_operations (操作函數(shù))*/void cdev_init(struct cdev *cdev, const struct file_operations *fops)/*函數(shù)功能:動態(tài)分配一個cdev結(jié)構(gòu)體說明:該函數(shù)不常用,因為字符設備都會封裝一個新的結(jié)構(gòu)體, 然后使用kzalloc來分配內(nèi)存(結(jié)構(gòu)體)*/struct cdev *cdev_alloc(void)/*函數(shù)功能: 添加一個字符設備到系統(tǒng)參數(shù)說明: p:設備的cdev結(jié)構(gòu)體 dev:第一個設備的設備號 count:連續(xù)的次設備號數(shù)*/int cdev_add(struct cdev *p, dev_t dev, unsigned count)/*函數(shù)功能: 從系統(tǒng)中移除一個cdev參數(shù)說明: p:要移除的cdev結(jié)構(gòu)體*/void cdev_del(struct cdev *p)

把上面的API分成兩段,一段是分配和釋放設備號的,另一段就是分配字符設備和注冊到系統(tǒng)中的。

register_chrdev_region() 和 alloc_chrdev_region() 的區(qū)別:

register_chrdev_region() 函數(shù)用于已知起始設備的設備號的情況,而alloc_chrdev_region() 用于設備號未知,向系統(tǒng)動態(tài)申請未被占用的設備號的情況。alloc_chrdev_region() 相比于 register_chrdev_region() 的優(yōu)點就在于它會自動避開設備號重復的沖突。

字符設備的驅(qū)動架構(gòu)

下面是寫一個字符設備驅(qū)動的一般步驟:

(1) 為設備定義一個設備相關的結(jié)構(gòu)體(包含設備所涉及的cdev,私有數(shù)據(jù)及鎖等信息)

(2) 初始化函數(shù)xxx_init的定義

1. 向系統(tǒng)申請設備號(register_chrdev_region()或alloc_chrdev_region())

2. 使用kzalloc申請設備內(nèi)存(為(1)中定義的結(jié)構(gòu)體申請存儲空間)

3. 調(diào)用cdev_init()初始化cdev

4. 調(diào)用cdev_add()向系統(tǒng)注冊設備

(3) 卸載函數(shù)xxx_exit的定義

1. 釋放設備號(unregister_chrdev_region())

2. 調(diào)用cdev_del()注銷設備

(4) 定義file_operations

1. 實現(xiàn)write()函數(shù) (copy_to_user())

2. 實現(xiàn)read()函數(shù)(copy_from_user())

3. 根據(jù)需要實現(xiàn)其他函數(shù)....

模板程序

/*設備結(jié)構(gòu)體*/struct xxx_dev_t{ struct cdev cdev; ...};struct xxx_dev_t *dev;dev_t devno;//讀設備ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, loff_t* f_pos){ ... copy_to_user(buf, ..., ...);}//寫設備ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t* f_pos){ ... copy_from_user(..., buf, ...);}//操作函數(shù)file_operationsstruct file_operations xxx_fops = { .owner = THIS_MODULE, .read = xxx_read, .write = xxx_write, ...};//設備驅(qū)動模塊加載函數(shù)static int __init xxx_init(void){ ... devno = MKDEV(xxx_major, 0); //(1)申請設備號 if(xxx_major) { register_chrdev_region(devno, 1, "xxx_dev"); } else { alloc_chrdev_region(&devno, 0, 1, "xxx_dev"); } //(2)為設備結(jié)構(gòu)體申請內(nèi)存(推薦使用devm_kzalloc) dev = kzalloc(sizeof(struct xxx_dev_t), GFP_KERNEL); //(3)初始化cdev cdev_init(&dev.cdev, &xxx_fops); dev.cdev.owner = THIS_MODULE; //(4)向系統(tǒng)注冊設備 cdev_add(dev.cdev, dev_no, 1);}module_init(xxx_init);//設備驅(qū)動模塊卸載函數(shù)static void __exit xxx_exit(void){ //釋放設備號 unregister_chrdev_region(dev_no, 1); //注銷設備 cdev_del(&dev.cdev); ...}module_exit(xxx_exit);MODULE_LICENSE("GPL v2");簡化字符設備驅(qū)動架構(gòu)

每次編寫初始化函數(shù)都要一步一步寫,為了簡化這個流程,Linux提供了一些封裝的接口函數(shù)來讓我們調(diào)用。

/*函數(shù)功能:注冊字符設備參數(shù)說明:major:主設備號,0表示動態(tài)分配 name: 設備名 fops: 操作函數(shù)返回值: 申請的主設備號 */static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)/*函數(shù)功能:注銷字符設備參數(shù)說明:major:主設備號 name: 設備名*/static inline void unregister_chrdev(unsigned int major, const char *name)

分析一下上面兩個函數(shù)的源碼

//register_chrdev調(diào)用了__register_chrdevint __register_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name, const struct file_operations *fops){ struct char_device_struct *cd; struct cdev *cdev; int err = -ENOMEM; //1. 申請設備號 cd = __register_chrdev_region(major, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); //2. 為設備結(jié)構(gòu)體申請內(nèi)存 cdev = cdev_alloc(); if (!cdev) goto out2; // 3. 初始化cdev cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); //4. 向系統(tǒng)注冊設備 err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major;out: kobject_put(&cdev->kobj);out2: kfree(__unregister_chrdev_region(cd->major, baseminor, count)); return err;}//unregister_chrdev調(diào)用__unregister_chrdevvoid __unregister_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name){ struct char_device_struct *cd; //釋放設備號 cd = __unregister_chrdev_region(major, baseminor, count); if (cd && cd->cdev) cdev_del(cd->cdev); //注銷設備 kfree(cd);}

通過上面的分析發(fā)現(xiàn)和上面的驅(qū)動框架是一樣的,只是做了個封裝罷了。這時候是不是發(fā)現(xiàn)了兩者之間的關系,是不是很多驅(qū)動都是用這兩個函數(shù)來注冊的。有些書就只講前面的,而有些教程又只講后面。所以搞得云里霧里的。

簡化上面的驅(qū)動模板

/*設備結(jié)構(gòu)體*/struct xxx_dev_t{ struct cdev cdev; ...};struct xxx_dev_t *dev;dev_t devno;//讀設備ssize_t xxx_read(struct file *filp, char __user *buf, size_t count, loff_t* f_pos){ ... copy_to_user(buf, ..., ...);}//寫設備ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t* f_pos){ ... copy_from_user(..., buf, ...);}//操作函數(shù)file_operationsstruct file_operations xxx_fops = { .owner = THIS_MODULE, .read = xxx_read, .write = xxx_write, ...};//設備驅(qū)動模塊加載函數(shù)static int __init xxx_init(void){ ... //注冊字符設備 xxx_major = register_chrdev(0, "xxx_dev", &xxx_fops);}module_init(xxx_init);//設備驅(qū)動模塊卸載函數(shù)static void __exit xxx_exit(void){ //注銷字符設備 unregister_chrdev(major, "xxx_dev"); ...}module_exit(xxx_exit);MODULE_LICENSE("GPL v2");

喜歡這篇文章,歡迎點贊,分享,關注!

更多精彩文章,歡迎關注微信公眾號"嵌入式軟件開發(fā)交流"

以上就是關于怎么安裝pos機驅(qū)動,字符設備驅(qū)動的知識,后面我們會繼續(xù)為大家整理關于怎么安裝pos機驅(qū)動的知識,希望能夠幫助到大家!

轉(zhuǎn)發(fā)請帶上網(wǎng)址:http://m.afbey.com/news/36572.html

你可能會喜歡:

版權聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 babsan@163.com 舉報,一經(jīng)查實,本站將立刻刪除。