LINUX IIO子系統分析之二 IIO子系統數據結構分析

2020-08-30 jerry的編程路

上一章我們簡要說明了IIO子系統的架構,本章我們通過數據結構的定義,分析IIO子系統的設計實現,本章的主要內容如下:

一、IIO子系統各數據結構說明

二、數據結構間的關聯說明

一、IIO子系統各數據結構說明

在上一章我們大概說明了IIO子系統的框架,IIO子系統大概包含幾個主要的部分,此處我們再說明一下:

  1. 對於連續數據採集相關功能,主要由iio buffer實現;
  2. 連續數據採集的觸發機制,主要由iio trigger實現;
  3. Iio device的事件觸發機制,主要由iio event實現;
  4. 提供單次原始數據的採集功能,主要通過syfs屬性文件實現。

基本就是這些內容,iio子系統主要藉助字符設備文件以及sysfs屬性文件實現數據的獲取與參數設定等操作。而在iio子系統中,主要包括如下幾個數據結構:

  1. struct iio_dev,描述一個iio device
  2. struct iio_event_interface,描述iio device的事件觸發模塊的數據結構;
  3. struct iio_buffer,描述iio device連續數據採集功能相關的數據結構;
  4. struct iio_trigger,描述iio device的trigger機制相關的數據結構
  5. struct iio_chan_spec,描述iio device的一個通道的屬性信息;
  6. struct iio_info,描述iio device各通道的原始數據讀取接口、event使能與event參數讀寫相關接口、trigger有效性檢測接口、設備樹節點解析等接口;
  7. struct iio_buffer_setup_ops,描述iio buffer使能與否的接口(建立iio buffer與iio tigger的關聯,從而保證iio trigger觸發後,可將數據刷新到對應的iio buffer中);
  8. struct iio_chan_spec_ext_info,描述一個channel擴展屬性相關的信息,包括屬性名稱、讀寫接口等
  9. struct iio_trigger_ops,表示iio trigger的操作接口,包括設置trigger的狀態(使能與否)、重新使能trigger、設備有效性判斷等接口;
  10. struct iio_buffer_access_funcs,描述iio buffer的access接口,包括數據寫入到iio buffer的緩存、緩存數據是否有效、從緩存中讀取數據等等接口。

基本上就是這些數據結構,iio子系統的數據結構比較多,但是數據結構間的關聯並不太複雜,主

要就是數據結構太多了。下面我們對每一個數據結構進行簡要說明

struct iio_dev

該數據結構表示一個iio device,它屬於IIO子系統中的核心數據結構,它負責將所有的IIO子系統的數據結構關聯起來,下面即是該數據結構主要的內容,下面我們分幾部分進行說明。

  1. modes與currentmode表示該iio device支持的模式及當前所處的模式,目前支持的模式如下,DIRECT_MODE表示不對採集數據進行緩存,可直接讀取單次的數據(可通過訪問sysfs下的屬性文件方式,讀取數據);INDIO_BUFFER_XXX表示支持對iio device採集數據進行緩存的模式,可理解為採集連續的數據(這些數據則需要通過訪問字符設備文件進行讀取);INDIO_EVENT_TRIGGRED則主要表示事件觸發功能,如針對溫度傳感器可監控當前溫度是否超過溫度告警上限或下限,當出現溫度告警後則向SOC發送中斷信號,若支持這類功能則增加INDIO_EVENT_TRIGGRED模式的支持即可(事件告警信息也是通過訪問字符設備文件讀取,但這個字符設備文件有點特殊,其是一個匿名文件)。

/* Device operating modes */

define INDIO_BUFFER_TRIGGERED 0x02

define INDIO_BUFFER_HARDWARE 0x08

#define INDIO_EVENT_TRIGGERED 0x10

  1. dev則主要藉助系統的設備驅動模型,實現對iio device的引用計數,並綁定至iio總線上,同時藉助設備驅動模型可在sysfs目錄下創建該iio dev的目錄,並創建該iio device所有屬性文件等等;
  2. event_interface表示event事件相關的數據結構,該數據結構內部包含一個kfifo,存儲iio device push的event信息;
  3. buffer表示該iio device對應的iio buffer,若系統不支持buffer模式,則無需創建該buffer;
  4. buffer_list則在一個iio buffer enable時,將active iio buffer加入到該鍊表中(目前基本上即將iio_dev->buffer添加到該鍊表上);
  5. scan_bytes表示單次採集數據的長度,該值主要根據當前active channel的個數、每一個通道採集數據的長度計算而得;
  6. available_scan_masks表示當前iio device可使用的channel的掩碼(如當前由8個通道,僅前四個通道可用,則可以設置available_scan_maks值為{0x0F}),而active_scan_mask則表示當前已enable的channelmask,該mask是available_scan_masks的子集

scan_bytes、available_scan_masks、active_scan_mask主要由iio buffer使用,scan_bytes是單次採集數據的長度,因此通過字符設備文件讀取buffer採集數據時,傳遞的內存長度至少應為scan_bytes;

  1. scan_timestamp、scan_index_timestamp主要對於通過buffer採集的數據是否需要時間戳,如果需要對採集的數據增加時間戳,則增加IIO_TIMESTAMP類型的虛擬channel,主要用於對採集的數據增加時間戳;
  2. trig表示一個trigger,針對event、buffer而言,均需要結合trigger機製作為數據可採集的信號,一般在trigger中將event信息、數據信息刷新到event的kfifo或buffer中去(不過目前event信息一般並沒有使用trigger機制,大多數event信息均是在event irq的中斷處理函數中push到event 的kfifo中,雖然IIO子系統設計上期望通過trigger將數據push到buffer或event上去,但event信息一般並不是連續事件,且trigger內部又實現了虛擬的irq chip,而在虛擬irq的中斷處理函數中實現數據push到buffer或event的kfifo中。顯然對於event信息處理而言,若使用trigger機制,則多了一個虛擬中斷的觸發與處理操作,也沒有必要啊,因此現有系統中基本上沒有使用trigger機制將event信息push到event kfifo的驅動);
  3. pollfunc、pollfunc_event則為buffer、event的中斷處理函數的接口信息(使用的中斷即為trigger中virtual irq chip註冊的irq),現在僅需要關注pollfunc即可,基本上沒有使用pollfunc_event的;
  4. channels是該iio device所有channel相關的參數信息,我們在iio_chan_spec中將詳細說明;
  5. channel_attr_list鍊表包含了IIO子系統為所有channel創建的動態屬性(針對hwmon子系統我們之前也分析過,其主要通過在sysfs下創建屬性文件實現與hwmon device的通信,而IIO子系統也類似,其也在sysfs下創建屬性文件實現與iio device的通信,而channel_attr_lis則主要是channel相關的屬性的集合);
  6. groups中包含了所有的group指針,包括channel、event、buffer子模塊創建的group,而在調用device_add將該iio device對應的struct device類型變量註冊到設備驅動模型子系統中,即遍歷該數組,創建屬性文件或目錄。
  7. setup_ops則主要是建立buffer與trigger的關聯,在該ops中的enable接口中,主要是申請trigger的virt irq chip提供的中斷及中斷處理函數;在該ops的disable接口中則釋放中斷。

struct iio_event_interface

該數據結構主要是對event子模塊的定義,其中:

  1. 等待隊列wait,當應用程式讀取觸發事件信息時,若當前無數據可讀,則將當前進程加入到該等待隊列,待調用iio_push_event將觸發事件信息加入kfifo後,則wakeup該隊列中的進程;
  2. 定義kfifo,存儲所有觸發的事件信息,供應用程式獲取;
  3. 將even子模塊動態定義的event attribute均添加至該鍊表中(屬性名稱格式為{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_{ev_type}_{ev_dir}_{ev_info});
  4. flags標記該event是否已使能(即應用程式是否通過ioctl調用創建一個匿名fd,若使能則置位IIO_BUSY_BIT_POS)

struct iio_buffer與struct iio_buffer_setup_ops

iio_buffer主要是用於存儲連續採集數據的緩存,其主要包括兩個主要的數據結構struct iio_buffer、struct iio_buffer_access_func(其實是三個數據結構,還有數據結構struct iio_kfifo,其內部包含struct iio_buffer類型變量和struct kfifo類型變量用於緩存數據)。

針對struct iio_buffer主要包括如下幾個方面的內容:

  1. iio_buffer緩存數據的個數(即length);
  2. iio_buffer每一次採集數據的長度(bytes_per_datum,而bytes_per_datum*length即為kfifo存儲數據的內存空間大小);
  3. Scan_el_dev_attr_list主要用於將所有iio_buffer子模塊創建的屬性變量集合在一起(iio_buffer);
  4. scan_el_attrs存儲各設備驅動自行定義的靜態屬性(生成的屬性文件在scan_elements子目錄下);
  5. attrs也是存儲存儲各設備驅動自行定義的靜態屬性(該變量定義的屬性文件在buffer子目錄下);
  6. buffer_group、scan_el_group包含iio buffer子模塊下所有屬性,其中buffer_group裡的屬性均在buffer子目錄下創建對應的屬性文件;scan_el_group裡的屬性均在scan_elements子目錄下創建對應的屬性文件;
  7. pollq為等待隊列,主要為iio device的字符設備文件使用(該字符設備文件對應的讀接口和poll接口使用,當buffer中不存在數據時則sleep在該等待隊列中);
  8. watermark為緩存多少個數據後,喚醒pollq(實際內存空間大小為watermark*bytes_per_datum)。

針對struct iio_buffer_access_funcs則是該iio_buffer對應的緩存空間的訪問訪問,目前使用kfifo緩存數據,則其訪問方法為iio_store_to_kfifo、iio_read_first_n_kfifo等,主要是將數據存儲至kfifo或從kfifo中取出緩存數據等

struct iio_trigger與struct iio_trigger_ops

這兩個數據結構主要實現iio 的trigger機制,類似於led子系統的led trigger。主要內容如下:

  1. id表示trigger的id、name為名稱;
  2. 該iio trigger也使用struct device類型的變量加入到iio總線上,iio trigger與iio device均註冊到iio總線上,因此它們在sysfs目錄下是同級的;
  3. list用於將struct iio trigger添加系統全局鍊表iio_trigger_list中;
  4. alloc_list主要用於同一類型的trigger可註冊多個trigger實例的請求,如trigger-period則使用該變量將trigger插入到iio_prtc_trigger_list中,目前使用這一變量的trigger並不多;
  5. 使用計數use_count;
  6. 而subirq_chip、subirq_base、subirqs、pool則主要用於創建虛擬的irq chip,在trigger內部,當多個trigger consumer註冊時,則trigger內部會為其分配一個虛擬的irq,並根據trigger consumer提供給pollfunc,為該irq註冊中斷處理函數,這樣當該trigger觸發後,則會遍歷所有該trigger上已註冊的虛擬irq,調用其中斷處理函數從而執行trigger consumer提供的處理函數(關於linux中斷子系統的內容可參考我之前寫的中斷子系統專欄,我在中斷子系統專欄也實現了一個虛擬的irq chip,實現的原理和此處trigger實現的虛擬irq chip的原理是一樣的)。

iio trigger也提供了操作接口,set_trigger_state主要設置trigger的狀態(使能與否)、reenable接口(try_reenable),validate_device(如實現的trigger只允許父device相同的iio device綁定,則可以實現該接口進行限制操作)

struct iio_chan_spec

該數據結構主要說明iio device一個channel的信息,主要涉及struct iio_chan_spec、struct iio_event_spec、struct iio_chan_spec_ext_info

針對struct iio_chan_spec主要涉及如下內容:

  1. 該channel的類型,channel類型的定義為等等enum iio_chan_type,包括IIO_TEMP、IIO_VOLTAGE等;
  2. channel表示該channel的index,當indexed為1時,才使用該index表示channel裡的屬性參數;
  3. channel2表示channel的別稱,當modified為1時,則使用該index對應的string描述channel的別稱(如針對三軸陀螺儀而言,如果還使用channel0、channel1進行識別的話不好區分,可使用modified識別為channelX、channelY、channelZ等)
  4. info_mask_separate表示channel的某一個屬性為channel專屬的
  5. Shared_by_type則表示該iio device下所有相同類型channel所共享的屬性;
  6. Shared_by_dir則表示該iio device下所有相同方向channel所共享的屬性;
  7. Shared_by_all則表示該iio device下所有channel所共享的屬性
  8. scan_index、scan_type則表示採集數據的index及數據的類型等(這兩個變量主要由buffer使用)
  9. event_spec定義event相關的信息;

該數據結構定義的變量,主要用於創建channel相關的屬性參數,命名規則為{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_xxx。

而struct iio_event_spec主要內容如下:

  1. 該event的type、dir,而mask_separate等參數與iio_chan_spec中的info_mask_xxx的意義類似;而該數據結構體也主要用於創建該channel中event相關的屬性參數,屬性參數在sysfs文件系統創建的屬性文件的名稱規則為{iio_dir}_{iio_channel_type}{channel-Index/channel_modify}_{ev_type}_{ev_dir}_{ev_info})

struct iio_info

該數據結構主要定義了通過syfs讀寫channel屬性的接口,其中read_raw、write_raw可用於讀取通道的raw數據等;而write_event_value則主要用於event事件觸發的閾值參數的設置與讀取等、而read_event_config、write_event_config則可以用於實現event的使能與否;而event_attrs、attrs則主要用於設備驅動自定義的屬性參數(包括event屬性參數以及iio device相關的屬性參數)

二、數據結構間的關聯說明

如下為上述這些數據結構間的關聯圖,通過struct iio_dev,將所有定義的數據結構關聯起來,這些數據結構基本上是在iio_device_register時完成關聯的。藉助這種數據結構間的關聯也方便我們較好的理解該子系統的設計實現。

以上即是本章的主要內容,對於iio子系統而言,其定義的數據結構種類雖然多,但大多數數據結構主要用於創建sysfs的attribute而設計的,而真正體現到架構設計部分的設計,主要就是trigger、buffer、event這幾個方面,而我認為設計的比較好的就是其trigger機制中,每一個trigger均實現一個虛擬irq chip,對於所有attach到該trigger上的consumer均為其分配虛擬的irq並註冊對應的中斷處理函數,當一個trigger觸發後,則通過generic_handle_irq觸發所有已註冊的虛擬中斷的處理操作。下一章我們就介紹iio trigger的設計。

相關焦點

  • LINUX IIO子系統專欄分析之一 IIO子系統概述
    從本章開始,我們進行IIO子系統專欄的分析文檔,本次IIO子系統專欄分析文檔大概包含如下幾章:一、 IIO子系統概述二、IIO子系統相關數據結構分析三、iio trigger 介紹四、iio event介紹五、iio buffer介紹六、iio device的註冊與註銷介紹七、iio trigger
  • LINUX IIO子系統分析之三 IIO trigger分析
    上一章我們分析了IIO子系統的數據結構定義,本章我們主要介紹IIO TRIGGER的設計實現,主要內容如下:一、數據結構簡述 二、設計實現說明 三、提供接口說明一、數據結構簡述 這兩個數據結構主要實現iio 的trigger機制,類似於led子系統的led trigger。
  • LINUX IIO子系統分析之四 IIO EVENT設計分析
    上一章我們介紹了iio子系統中的iio trigger模塊,本章我們將介紹iio event模塊,iio event主要用於閾值監測、自由落體監測等監測功能。因為IIO EVENT涉及IIO DEVICE字符設備文件操作,因此本章內容主要分為如下幾部分:一、 IIO DEVICE字符設備文件操作接口 二、IIO EVENT設計分析 三、IIO EVENT相關接口說明 一、 IIO DEVICE字符設備文件操作接口
  • LINUX IIO子系統分析之五 iio buffer介紹
    上一章我們介紹了iio子系統中的iio event模塊,本章我們將介紹iio buffer模塊,iio buffer主要用於連續數據採集與緩存功能。IIO buffer模塊藉助IIO DEVICE字符設備文件與應用程式通信,同時藉助iio trigger模塊與iio device進行交互,因此本章內容分為如下幾部分:一、 IIO DEVICE字符設備文件操作接口 二、iio buffer相關數據結構 三、IIO trigger-buffer介紹 四
  • LINUX IIO子系統分析之七 虛擬iio設備驅動實現
    前面幾章我們基本完成了IIO子系統的所有內容,而該章即為本專欄的結束篇,主要用來實現一個虛擬的IIO DEVICE DRIVER,本章的內容主要包括如下幾部分:一、 虛擬IIO DEVICE的說明 二、虛擬IIO DEVICE DRIVER實現所需的知識點 三、虛擬IIO DEVICE DRIVER的數據結構及實現說明
  • LINUX IIO子系統分析之六 IIO設備驅動開發流程說明
    前面五章我們基本上把IIO 子系統的內部設計實現均作了說明,本章我們將說明iio device的驅動開發流程,本章的主要內容大致安排如下:一、IIO子系統的關鍵技術點總結 二、IIO DEVICE的註冊與註銷接口說明 三、IIO DEVICE的驅動開發流程
  • Linux regmap子系統分析之三 regmap bus實例分析
    在前面一章我們分析了regmap子系統的數據結構,基本上熟悉了數據結構的關聯,也就大概理解了regmap子系統的實現流程,本章我們簡要介紹下regmap子系統中接口的調用過程,然後介紹下regmap bus的實現及其提供的regmap的創建及註銷接口。
  • Linux regmap子系統分析之二 從數據結構分析系統實現
    上一章我們簡要分析了regmap子系統,本章我們將從regmap子系統的數據結構介紹regmap子系統的實現。 一、數據結構間的關聯及說明 針對regmap子系統,我們首先要知道regmap子系統要解決的痛點是什麼?
  • Linux regulator子系統分析之二 從數據結構理解系統實現
    上一章我們分析了regulator子系統的總體框架,本章我們將從數據結構入手,從而理解regulator子系統實現。 針對linux 內核各子系統學習而言,在理解了各子系統的實現背景後,再從數據結構入手,可快速理解其子系統的實現流程。因此本章我們從regulator子系統的數據結構入手,從而理解regulator子系統的實現。
  • Linux CommonClock Framework分析之二 CCF子系統內部實現簡述
    我們主要從如下幾點說明CCF子系統的內部設計流程:一、 CCF子系統內部數據結構的定義與關聯二、CCF子系統提供的接口一、 CCF子系統內部數據結構的定義與關聯在我們學習linux內核各子系統模塊時,通過其內部數據結構的定義及關聯,即可大致掌握其實現過程及所需要提供的接口等等
  • Linux regmap子系統分析之一 系統概述
    本周開始我們學習下regmap子系統的架構。本系統專欄主要涉及如下幾個子章節:一、regmap子系統概述二、regmap子系統數據結構分析三、regmap子系統接口說明四、regmap bus實例說明(以i2c為例)本章我們主要對regmap子系統做一個簡單的說明。
  • LINUX CommonClock Framework子系統分析之一 系統概述
    本專欄主要介紹linux的ccf子系統,主要用於系統clock的管理等操作。本專欄我們大概分為如下幾章進行學習:一、CCF子系統概述二、CCF子系統數據結構分析及關聯說明三、CCF子系統的clk註冊與註銷接口實現分析四、虛擬的clk設備驅動實現 本章我們主要進行CCF子系統的概述。
  • Linux regulator子系統分析之三 regulator註冊、註銷接口分析
    在上一章我們介紹了regulator子系統相關的數據結構間的關聯以及每一個數據結構的定義。針對數據結構間的關聯則需要regulator子系統提供的接口實現。而本章我們就說明這些接口。本章的章節如下:一、regulator device的註冊與註銷二、regulator的註冊與註銷(regulator device的使用者)三、regulator子系統提供的接口一、regulator device的註冊與註銷針對regulator device的註冊與註銷函數主要涉及regulator_register、regulator_unregister
  • Linux regulator子系統分析之一 總體概述
    Linux regulator 子系統主要用於管理電壓、電流電源設備的電壓、電流輸入使能、動態調整電壓、電流等,屬於電源管理的一部分。從本章開始我們分析regulator子系統。主要分為如下幾部分:一、regulator子系統總體概述二、regulator相關數據結構分析三、regulator相關註冊、註銷函數分析四、regulator設備驅動實現本章主要對regulator子系統進行簡要說明。
  • Linux V4l2子系統專欄之一 子系統概述
    從本章開始,我們開始分析V4L2子系統(Video for Linux two),主要用於音視頻設備的框架。V4l2主要用於驅動視頻輸出設備(video outpt interface)、Video overlay interface、Video output overlay device、VBI interface、Radio interface等。
  • Linux pinctrl子系統分析之六 設備與pinctrl子系統的bind
    本章我們分析設備與pinctrl子系統的bind,在前面幾章我們介紹了soc pin 描述相關的數據結構與註冊接口、board pin 描述相關的數據結構與註冊接口,但是我們卻沒有看到是在何時由誰實現對設備相關的引腳進行引腳復用與引腳配置的,而這些就是本章的內容。
  • Linux GUI子系統概述 GUI子系統的構成及工作流程
    Linux GUI子系統概述 GUI子系統的構成及工作流程 Nick 發表於 2020-12-05 10:45:54 作者:Nick 開始前的幾點說明
  • Linux pinctrl子系統分析之四 pinctrl device的註冊與註銷
    前面我們分析了pinctrl子系統相關的數據結構等內容,本章我們分析pinctrl device的註冊與註銷接口。 針對pinctrl device的註冊與註銷主要涉及pinctrl_register、pinctrl_unregister、devm_pinctrl_register、devm_pinctrl_unregister這幾個接口。
  • Linux input子系統編程、分析與模板
    輸入設備都有共性:中斷驅動+字符IO,基於分層的思想,Linux內核將這些設備的公有的部分提取出來,基於cdev提供接口,設計了輸入子系統,所有使用輸入子系統構建的設備都使用主設備號13,同時輸入子系統也支持自動創建設備文件,這些文件採用阻塞的IO讀寫方式
  • Linux Scsi子系統框架介紹
    因為scsi命令已經標準化,因此scsi子系統也成為了linux kernel眾多子系統中的一份子。這個也涉及到通用塊設備層的配置,後面會講二、Linux scsi子系統軟體模型接下來會基於linux設備驅動模型描述scsi子系統的框圖。看到這裡的小夥伴接下來需要有linux設備驅動模型的基礎知識背景了。