上一章我們介紹了iio子系統中的iio event模塊,本章我們將介紹iio buffer模塊,iio buffer主要用於連續數據採集與緩存功能。IIO buffer模塊藉助IIO DEVICE字符設備文件與應用程式通信,同時藉助iio trigger模塊與iio device進行交互,因此本章內容分為如下幾部分:
一、 IIO DEVICE字符設備文件操作接口
二、iio buffer相關數據結構
三、IIO trigger-buffer介紹
四、IIO buffer相關接口說明
一、 IIO DEVICE字符設備文件操作接口
在IIO 子系統中,每一個IIO DEVICE均會創建一個字符設備文件,名稱為/dev/iio:deviceX,該字符設備文件節點在iio_device_register中調用cdev_init、cdev_add完成字符設備文件節點的創建,且文件操作接口為iio_buffer_fileops(而藉助sysfs的kobject uevent,則會將cdev add的信息發送給應用程式,應用層的mdev/udev接收到cdev add的uevent之後,則會調用mknod完成字符設備文件節點的創建,詳細內容可參考我之前寫的字符設備文件專欄的內容《》)。
而/dev/iio:deviceX主要實現兩個功能:
- 用於讀取iio device緩存的已採集數據,從而讓應用程式對採集的數據進行分析;
- 藉助該字符設備文件的ioctl接口,實現匿名iio event fd的創建,從而讓應用程式藉助select/epoll監控該匿名文件是否有event信息可讀;
如下即是/dev/iio:deviceX的訪問流程,應用程式通過open/read/poll/ioctl接口則會調用內核中VFS提供的操作接口,最終則調用iio_buffer_fileops中定義的接口。
iio_buffer_fileops的定義如下
二、iio buffer相關數據結構
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主要包括如下幾個方面的內容:
- iio_buffer緩存數據的個數(即length);
- iio_buffer每一次採集數據的長度(bytes_per_datum,而bytes_per_datum*length即為kfifo存儲數據的內存空間大小);
- Scan_el_dev_attr_list主要用於將所有iio_buffer子模塊創建的屬性變量集合在一起(iio_buffer);
- scan_el_attrs存儲各設備驅動自行定義的靜態屬性(生成的屬性文件在scan_elements子目錄下);
- attrs也是存儲存儲各設備驅動自行定義的靜態屬性(該變量定義的屬性文件在buffer子目錄下);
- buffer_group、scan_el_group包含iio buffer子模塊下所有屬性,其中buffer_group裡的屬性均在buffer子目錄下創建對應的屬性文件;scan_el_group裡的屬性均在scan_elements子目錄下創建對應的屬性文件;
- pollq為等待隊列,主要為iio device的字符設備文件使用(該字符設備文件對應的讀接口和poll接口使用,當buffer中不存在數據時則sleep在該等待隊列中);
- 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中取出緩存數據等
三、IIO trigger-buffer介紹
藉助於IIO trigger機制,iio-device在數據可讀時,將數據push 到iio buffer子模塊的緩存中,實現緩存連續採集的數據。如下圖所示,即為iio trigger-buffer的實現機制,其中紅線部分即是iio trigger的部分,而右邊黃線部分則是iio buffer的部分(關於iio trigger的介紹請參考)。具體說明如下:
- 實現iio trigger的註冊,該iio trigger 可支持多個consumer(此處的consumer即為iio buffer),而iio trigger主要是藉助其內部實現的虛擬中斷控制器,從而實現支持多個consumer;而iio trigger需要與iio device進行綁定,僅在iio device與iio trigger綁定後,iio device driver則可以通過監控iio device觸發事件(如中斷),然後調用iio_trigger_poll接口,該接口調度所有虛擬中斷對應的中斷處理函數(即調用iio trigger consumer提供的中斷處理接口,而在該中斷處理接口中從iio device中讀取數據,並調用iio_push_to_buffer,將數據push到iio buffer的kfifo中;
- 而應用程式則通過iio buffer 字符設備文件接口,從iio buffer的kfifo中讀取採集的數據信息。)
藉助以上的信息,則實現了iio trigger與iio buffer的結合,並實現iio device 採集數據的緩存與讀取操作。
四、IIO buffer相關接口說明
iio trigger與iiobuffer關聯接口
主要提供接口iio_triggered_buffer_setup用於實現該功能,該接口實現的功能主要包括:
- 申請iio buffer類型的變量,同時完成iio_dev->pollfunc的定義(struct iio_poll_func*類型的變量,該變量主要包含iio trigger內部虛擬中斷處理接口的賦值、申請的虛擬中斷id等);
- 完成iio_dev->setup_ops的賦值(即struct iio_buffer_setup_ops*類型的變量,該數據結構主要用於實現iio buffer與iiotrigger的綁定與解綁接口,一般使用iio buffer實現的默認變量iio_triggered_buffer_setup_ops), iio_triggered_buffer_setup_ops的定義如下。
- 其中iio_triggered_buffer_postenable則實現iio trigger與iio buffer的綁定,即通過調用iio_trigger_attach_poll_func接口從iio trigger中申請一個虛擬的irq,並完成該irq的中斷處理函數的設置;當iio device調用iio_trigger_poll接口將觸發信息發送給iio trigger時,iio trigger則會觸發所有虛擬中斷處理接口,由各中斷的中斷處理函數從iio device中進行數據的採集,並調用iio_push_buffer接口,將採集的數據push到iio buffer的kfifo中。
- 而iio_triggered_buffer_predisable則解除iio trigger與iio buffer的綁定,即free申請的虛擬irq。
iio buffer相關的sysfs屬性文件創建接口
iio_buffer_alloc_sysfs_and_mask接口用於實現iio buffer相關sysfs屬性文件的創建,其中創建兩類sysfs屬性文件:
- iio buffer使能、iio kfifo長度、應用程式可讀取數據的最小等待個數,主要是在/sys/bus/iio/devices/iio:deviceX目錄下創建子目錄buffer,該子目錄下創建三個屬性文件,分別為enable、length、watermark;
- 其中enable用於實現iio buffer使能的設置及查看,當通過該文件使能iio buffer時,則完成iio buffer的kfifo大小申請、單次採集數據大小更新、已使能的採集通道數據等更新,並最終調用iio_buffer_setup_ops->postenable接口,實現iio trigger與iio buffer的綁定;
- length主要設置iio buffer的kfifo的容量大小;
- watermark則主要修改應用程式一次可讀取數據的最小等待個數,當buffer中存儲的數據個數超過該值後,則在poll接口iio_buffer_poll中標記該文件可讀(epoll、select監控該標記);
- iio buffer相關的採集通道的使能與否相關的sysfs屬性文件,主要是在/sys/bus/iio/devices/iio:deviceX目錄下創建子目錄scan_elements,創建採集通道使能屬性文件、採集數據的格式、採集通道的index等,如本專欄實現的虛擬溫度晶片(virt0824型號),為兩個通道創建了採集通道使能相關的屬性文件,如下圖所示:
scan_elements目錄下的屬性文件,則主要是根據iio device driver中定義的struct iio_chan_spec類型變量進行創建,上面的文件主要是根據下面的定義進行創建的(如下藍色陰影部分,定義了scan index的值、scan type,其中scan index即對應io_tempX_index,而in_tempX_type則主要為scan_type定義的值,這兩個屬性文件的屬性為只讀屬性):
此處以該device為例,說明如何開啟iio buffer,主要分為如下幾步:
- 使能採集通道:
- echo 1 >scan_elements/in_temp0_en
- 設置iio buffer kfifo長度
- echo 16 > buffer/length
- 設置iio buffer watermark
- echo 2 > buffer/watermark
- 使能iio buffer
- echo 1 > buffer/enable
執行以上各步驟,即可完成iio buffer的使能,現在我們讓virt0824xinp觸發兩次中斷,從而觸發iio-trigger-buffer進行數據的採集
然後執行如下命令,看獲取到採集數據:
以上即是iio buffer的主要功能,主要說明了iio trigger與iio buffer的綁定部分、iio buffer字符設備文件訪問流程、iio buffer相關sysfs屬性文件的定義及使用過程。下一章我們分析iio device的註冊流程。