日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 设备驱动开发思想 —— 驱动分层与驱动分离

發(fā)布時間:2023/12/9 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 设备驱动开发思想 —— 驱动分层与驱动分离 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前面我們學習I2C、USB、SD驅(qū)動時,有沒有發(fā)現(xiàn)一個共性,就是在驅(qū)動開發(fā)時,每個驅(qū)動都分層三部分,由上到下分別是:

1、XXX 設備驅(qū)動

2、XXX 核心層

3、XXX 主機控制器驅(qū)動

? ? ? 而需要我們編寫的主要是設備驅(qū)動部分,主機控制器驅(qū)動部分也有少量編寫,二者進行交互主要時由核心層提供的接口來實現(xiàn);這樣結構清晰,大大地有利于我們的驅(qū)動開發(fā),這其中就是利用了Linux設備驅(qū)動開發(fā)中兩個重要思想,下面來一一解析


一、設備驅(qū)動的分層思想

? ? ? ?在面向?qū)ο蟮某绦蛟O計中,可以為某一類相似的事物定義一個基類,而具體的事物可以繼承這個基類中的函數(shù)。如果對于繼承的這個事物而言,其某函數(shù)的實現(xiàn)與基類一致,那它就可以直接繼承基類的函數(shù);相反,它可以重載之。這種面向?qū)ο蟮脑O計思想極大地提高了代碼的可重用能力,是對現(xiàn)實世界事物間關系的一種良好呈現(xiàn)。

? ? ? Linux內(nèi)核完全由C語言和匯編語言寫成,但是卻頻繁用到了面向?qū)ο蟮脑O計思想。在設備驅(qū)動方面,往往為同類的設備設計了一個框架,而框架中的核心層則實現(xiàn)了該設備通用的一些功能。同樣的,如果具體的設備不想使用核心層的函數(shù),它可以重載之。舉個例子:

[cpp]?view plaincopy
  • return_type?core_funca(xxx_device?*?bottom_dev,?param1_type?param1,?param1_type?param2)??
  • {??
  • ????if?(bottom_dev->funca)??
  • ????return?bottom_dev->funca(param1,?param2);??
  • ????/*?核心層通用的funca代碼?*/??
  • ????...??
  • }??
  • ? ? ?上述core_funca的實現(xiàn)中,會檢查底層設備是否重載了funca(),如果重載了,就調(diào)用底層的代碼,否則,直接使用通用層的。這樣做的好處是,核心層的代碼可以處理絕大多數(shù)該類設備的funca()對應的功能,只有少數(shù)特殊設備需要重新實現(xiàn)funca()。

    再看一個例子:

    [cpp]?view plaincopy
  • return_type?core_funca(xxx_device?*?bottom_dev,?param1_type?param1,?param1_type?param2)??
  • {??
  • ????/*通用的步驟代碼A?*/??
  • ????...??
  • ????bottom_dev->funca_ops1();??
  • ????/*通用的步驟代碼B?*/??
  • ????...??
  • ????bottom_dev->funca_ops2();??
  • ????/*通用的步驟代碼C?*/??
  • ????...??
  • ????bottom_dev->funca_ops3();??
  • }??
  • ? ? 上述代碼假定為了實現(xiàn)funca(),對于同類設備而言,操作流程一致,都要經(jīng)過“通用代碼A、底層ops1、通用代碼B、底層ops2、通用代碼C、底層ops3”這幾步,分層設計明顯帶來的好處是,對于通用代碼A、B、C,具體的底層驅(qū)動不需要再實現(xiàn),而僅僅只關心其底層的操作ops1、ops2、ops3。圖1明確反映了設備驅(qū)動的核心層與具體設備驅(qū)動的關系,實際上,這種分層可能只有2層(圖1的a),也可能是多層的(圖1的b)。


    ? ? ? ?這樣的分層化設計在Linux的input、RTC、MTD、I2 C、SPI、TTY、USB等諸多設備驅(qū)動類型中屢見不鮮。


    二、主機驅(qū)動和外設驅(qū)動分離思想

    主機、外設驅(qū)動分離的意義

    ? ? ? ?在Linux設備驅(qū)動框架的設計中,除了有分層設計實現(xiàn)以外,還有分隔的思想。舉一個簡單的例子,假設我們要通過SPI總線訪問某外設,在這個訪問過程中,要通過操作CPU XXX上的SPI控制器的寄存器來達到訪問SPI外設YYY的目的,最簡單的方法是:

    [cpp]?view plaincopy
  • return_type?xxx_write_spi_yyy(...)??
  • {??
  • ????xxx_write_spi_host_ctrl_reg(ctrl);??
  • ????xxx_?write_spi_host_data_reg(buf);??
  • ????while(!(xxx_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));??
  • ????...??
  • }??
  • ? ? ?如果按照這種方式來設計驅(qū)動,結果是對于任何一個SPI外設來講,它的驅(qū)動代碼都是CPU相關的。也就是說,當然用在CPU XXX上的時候,它訪問XXX的SPI主機控制寄存器,當用在XXX1的時候,它訪問XXX1的SPI主機控制寄存器:

    [cpp]?view plaincopy
  • return_type?xxx1_write_spi_yyy(...)??
  • {??
  • ????xxx1_write_spi_host_ctrl_reg(ctrl);??
  • ????xxx1_?write_spi_host_data_reg(buf);??
  • ????while(!(xxx1_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));??
  • ????...??
  • }??
  • ? ? ? 這顯然是不能接受的,因為這意味著外設YYY用在不同的CPU XXX和XXX1上的時候需要不同的驅(qū)動。那么,我們可以用如圖的思想對主機控制器驅(qū)動和外設驅(qū)動進行分離。這樣的結構是, 外設a、b、c的驅(qū)動與主機控制器A、B、C的驅(qū)動不相關,主機控制器驅(qū)動不關心外設,而外設驅(qū)動也不關心主機,外設只是訪問核心層的通用的API進行數(shù)據(jù)傳輸,主機和外設之間可以進行任意的組合 。


    ? ? ? 如果我們不進行上圖的主機和外設分離,外設a、b、c和主機A、B、C進行組合的時候,需要9個不同的驅(qū)動。設想一共有m個主機控制器,n個外設,分離的結果是需要m+n個驅(qū)動,不分離則需要m*n個驅(qū)動。

    ? ? ? Linux SPI、I2C、USB、ASoC(ALSA SoC)等子系統(tǒng)都典型地利用了這種分離的設計思想。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結

    以上是生活随笔為你收集整理的Linux 设备驱动开发思想 —— 驱动分层与驱动分离的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。