Linux設備驅動之IIO子系統——IIO框架及IIO數據結構

  因爲須要對ADC進行驅動設計,所以學習了一下Linux驅動的IIO子系統。本文翻譯自《Linux Device Drivers Development 》--John Madieu,本人水平有限,如有錯誤請你們指出。linux

IIO Framework redis

  工業I / O(IIO)是專用於模數轉換器(ADC)和數模轉換器(DAC)的內核子系統。隨着愈來愈多的具備不一樣代碼實現的傳感器(具備模擬到數字或數字到模擬,功能的測量設備)分散在內核源上,收集它們變得必要。這就是IIO框架以通用的方式所作的事情。自2009年以來,Jonathan Cameron和Linux-IIO社區一直在開發它。api

 

  加速度計,陀螺儀,電流/電壓測量芯片,光傳感器,壓力傳感器等都屬於IIO系列器件。數組

  IIO模型基於設備和通道架構:數據結構

    l 設備表明芯片自己。它是層次結構的頂級。架構

    l 通道表明設備的單個採集線。設備能夠具備一個或多個通道。例如,加速度計是具備  三個通道的裝置,每一個通道對應一個軸(X,Y和Z)。框架

  IIO芯片是物理和硬件傳感器/轉換器。它做爲字符設備(當支持觸發緩衝時)暴露給用戶空間,以及包含一組文件的sysfs目錄條目,其中一些文件表明通道。單個通道用單個sysfs文件條目表示。dom

  下面是從用戶空間與IIO驅動程序交互的兩種方式:ide

    l /sys/bus/iio/iio:deviceX/:表示傳感器及其通道函數

    l /dev/iio:deviceX: 表示導出設備事件和數據緩衝區的字符設備

 

 IIO框架架構和佈局 

  上圖顯示瞭如何在內核和用戶空間之間組織IIO框架。 驅動程序使用IIO核心公開的一組工具和API來管理硬件並向IIO核心報告處理。 而後,IIO子系統經過sysfs接口和字符設備將整個底層機制抽象到用戶空間,用戶能夠在其上執行系統調用。

  IIO API分佈在多個頭文件中,以下所示:

 #include <linux/iio/iio.h>    /* mandatory */
#include <linux/iio/sysfs.h>  /* mandatory since sysfs is used */
#include <linux/iio/events.h> /* For advanced users, to manage iio events */
#include <linux/iio/buffer.h> /* mandatory to use triggered buffers */
#include <linux/iio/trigger.h>/* Only if you implement trigger in your driver (rarely used)*/

  在如下文章中,咱們將描述和處理IIO框架的每一個概念,例如

    遍歷其數據結構(設備,通道等)

    觸發緩衝支持和連續捕獲,以及其sysfs接口

    探索現有的IIO觸發器

    以單次模式或連續模式捕獲數據

    列出可用於幫助開發人員測試其設備的可用工具

 

(一):IIO data structures:IIO數據結構

  IIO設備在內核中表示爲struct iio_dev結構體的一個實例,並由struct iio_info結構體描述。 全部重要的IIO結構都在include/linux/iio/iio.h中定義。

  iio_dev structure(iio_dev結構)

  該結構表明IIO設備,描述設備和驅動程序。 它告訴咱們:

  l  設備上有多少個通道?

  l  設備能夠在哪些模式下運行:單次,觸發緩衝?

  l  這個驅動程序可使用哪些hooks鉤子?

struct iio_dev {
   [...]
   int modes;
   int currentmode;
   struct device dev;
   struct iio_buffer *buffer;
   int scan_bytes;
   const unsigned long *available_scan_masks;
   const unsigned long *active_scan_mask;
   bool scan_timestamp;
   struct iio_trigger *trig;
   struct iio_poll_func *pollfunc;
   struct iio_chan_spec const *channels;
   int num_channels;
   const char *name;
   const struct iio_info *info;
   const struct iio_buffer_setup_ops *setup_ops;
   struct cdev chrdev;

};

完整的結構在IIO頭文件中定義。 咱們將不感興趣的字段在此處刪除。 

   modes: 這表示設備支持的不一樣模式。 支持的模式有:

     INDIO_DIRECT_MODE表示設備提供的sysfs接口。

     INDIO_BUFFER_TRIGGERED表示設備支持硬件觸發器。使用iio_triggered_buffer_setup()函數設置觸發緩衝區時,此模式會自動添加到設備中。

    INDIO_BUFFER_HARDWARE表示設備具備硬件緩衝區。

    INDIO_ALL_BUFFER_MODES是上述二者的聯合。

  l  currentmode: 這表示設備實際使用的模式。

  l  dev: 這表示IIO設備所依賴的struct設備(根據Linux設備型號)。

  l  buffer: 這是您的數據緩衝區,在使用觸發緩衝區模式時會推送到用戶空間。 使用iio_triggered_buffer_setup函數啓用觸發緩衝區支持時,它會自動分配並與您的設備關聯。

  l  scan_bytes: 這是捕獲並饋送到緩衝區的字節數。 當從用戶空間使用觸發緩衝區時,緩衝區應至少爲indio-> scan_bytes字節大。

  l  available_scan_masks: 這是容許的位掩碼的可選數組。 使用觸發緩衝器時,能夠啓用通道捕獲並將其饋入IIO緩衝區。 若是您不想容許某些通道啓用,則應僅使用容許的通道填充此數組。 如下是爲加速度計(帶有X,Y和Z通道)提供掃描掩碼的示例:

/*
 * Bitmasks 0x7 (0b111) and 0 (0b000) are allowed.
 * It means one can enable none or all of them.
 * one can't for example enable only channel X and Y
 */

static const unsigned long my_scan_masks[] = {0x7, 0};
indio_dev->available_scan_masks = my_scan_masks;

l  active_scan_mask: 這是啓用通道的位掩碼。 只有來自這些通道的數據能被推入緩衝區。 例如,對於8通道ADC轉換器,若是隻啓用第一個(0),第三個(2)和最後一個(7)通道,則位掩碼將爲0b10000101(0x85)。 active_scan_mask將設置爲0x85。 而後,驅動程序可使用for_each_set_bit宏遍歷每一個設置位,根據通道獲取數據,並填充緩衝區。

l  scan_timestamp: 這告訴咱們是否將捕獲時間戳推入緩衝區。 若是爲true,則將時間戳做爲緩衝區的最後一個元素。 時間戳大8字節(64位)。

l  trig: 這是當前設備觸發器(支持緩衝模式時)。 

l  pollfunc:這是在接收的觸發器上運行的函數。 

l  channels: 這表示通道規範結構,用於描述設備具備的每一個通道。

l  num_channels: 這表示通道中指定的通道數。

l  name: 這表示設備名稱。

l  info: 來自驅動程序的回調和持續信息。

l  setup_ops: 啓用/禁用緩衝區以前和以後調用的回調函數集。 這個結構在include / linux / iio / iio.h中定義,以下所示:

struct iio_buffer_setup_ops {
    int (* preenable) (struct iio_dev *);
    int (* postenable) (struct iio_dev *);
    int (* predisable) (struct iio_dev *);
    int (* postdisable) (struct iio_dev *);
    bool (* validate_scan_mask) (struct iio_dev *indio_dev,
                                 const unsigned long *scan_mask);
};

l  setup_ops: 若是未指定,則IIO內核使用drivers / iio / buffer / industrialio-triggered-buffer.c中定義的缺省iio_triggered_buffer_setup_ops。 

l  chrdev: 這是由IIO核心建立的關聯字符設備。 

用於爲IIO設備分配內存的函數是iio_device_alloc():

struct iio_dev * iio_device_alloc(int sizeof_priv) 
///struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
/* Resource-managed iio_device_alloc()*/
/*Managed iio_device_alloc. iio_dev allocated with this function is automatically freed on driver detach.
If an iio_dev allocated with this function needs to be freed separately, devm_iio_device_free() must be used. */

  dev是爲其分配iio_dev的設備,sizeof_priv是用於爲任何私有結構分配的內存空間。 這樣,傳遞每一個設備(私有)數據結構很是簡單。 若是分配失敗,該函數返回NULL:

 struct iio_dev *indio_dev;
struct my_private_data *data;
indio_dev = iio_device_alloc(sizeof(*data));
if (!indio_dev)
          return -ENOMEM;
/*data is given the address of reserved momory for private data */
data = iio_priv(indio_dev);

 

  在分配IIO設備存儲器以後,下一步是填充不一樣的字段。 完成後,必須使用iio_device_register函數向IIO子系統註冊設備:

 

int iio_device_register(struct iio_dev *indio_dev)
       //devm_iio_device_register(dev, indio_dev)
/* Resource-managed iio_device_register() */

 

  在執行此功能後,設備將準備好接受來自用戶空間的請求。 反向操做(一般在釋放函數中完成)是iio_device_unregister():

 

void iio_device_unregister(struct iio_dev *indio_dev)
// void devm_iio_device_unregister(struct device * dev, struct iio_dev * indio_dev)

  一旦取消註冊,iio_device_alloc分配的內存能夠用iio_device_free釋放:

void iio_device_free(struct iio_dev *iio_dev)
// void devm_iio_device_free(struct device * dev, struct iio_dev * iio_dev)

  給定IIO設備做爲參數,能夠經過如下方式檢索私有數據:

 

 struct my_private_data *the_data = iio_priv(indio_dev);

 

 

iio_info structure:iio_info結構體

  struct iio_info結構用於聲明IIO內核使用的鉤子,以讀取/寫入通道/屬性值:

struct iio_info {
           struct module *driver_module;
            const struct attribute_group *attrs;
            int (*read_raw)(struct iio_dev *indio_dev,
               struct iio_chan_spec const *chan,
               int *val, int *val2, long mask);

            int (*write_raw)(struct iio_dev *indio_dev,

                struct iio_chan_spec const *chan,

                int val, int val2, long mask);
             [...]

};

l  driver_module: 這是用於確保chrdev正確擁有的模塊結構,一般設置爲THIS_MODULE。

l  attrs: 這表示設備屬性。

l  read_raw: 這是用戶讀取設備sysfs文件屬性時的回調運行。 mask參數是一個位掩碼,它容許咱們知道請求了哪一種類型的值。 channel參數讓咱們知道相關的通道。 它能夠是採樣頻率,用於將原始值轉換爲可用值的比例,或原始值自己。

l  write_raw: 這是用於將值寫入設備的回調。 例如,可使用它來設置採樣頻率。

  如下代碼顯示瞭如何設置struct iio_info結構:

static const struct iio_info iio_dummy_info = {
    .driver_module = THIS_MODULE,
    .read_raw = &iio_dummy_read_raw,
    .write_raw = &iio_dummy_write_raw,
[...]

/*
 * Provide device type specific interface functions and
 * constant data. 提供設備類型特定的接口功能和常量數據。
 */
indio_dev->info = &iio_dummy_info;

 

IIO channels:IIO通道

通道表明單條採集線。 例如加速度計具備3個通道(X,Y,Z),由於每一個軸表明單個採集線。 struct iio_chan_spec是表示和描述內核中單個通道的結構:

      

 struct iio_chan_spec {
        enum iio_chan_type type;
        int channel;
        int channel2;
        unsigned long address;
        int scan_index;
        struct {
            charsign;
            u8 realbits;
            u8 storagebits;
            u8 shift;
            u8 repeat;
            enum iio_endian endianness;
        } scan_type;
        long info_mask_separate;
        long info_mask_shared_by_type;
        long info_mask_shared_by_dir;
        long info_mask_shared_by_all;
        const struct iio_event_spec *event_spec;
        unsigned int num_event_specs;
        const struct iio_chan_spec_ext_info *ext_info;
        const char *extend_name;
        const char *datasheet_name;
        unsigned modified:1;
        unsigned indexed:1;
        unsigned output:1;
        unsigned differential:1;

    };

  各個參數意義:

l  type: 這指定了通道的測量類型。 在電壓測量的狀況下,它應該是IIO_VOLTAGE。 對於光傳感器,它是IIO_LIGHT。 對於加速度計,使用IIO_ACCEL。 全部可用類型都在include / uapi / linux / iio / types.h中定義,如enum iio_chan_type。 要爲給定轉換器編寫驅動程序,請查看該文件以查看每一個通道所屬的類型。

l  channel: 這指定.indexed設置爲1時的通道索引。

l  channel2: 這指定.modified設置爲1時的通道修飾。

l  modified: 這指定是否將修飾符應用於此通道屬性名稱。 在這種狀況下,修飾符設置在.channel2中。 (例如,IIO_MOD_X,IIO_MOD_Y,IIO_MOD_Z是關於xyz軸的軸向傳感器的修改器)。 可用修飾符列表在內核IIO頭中定義爲枚舉iio_modifier。 修飾符只會破壞sysfs中的通道屬性名稱,而不是值。

l  indexed: 這指定通道屬性名稱是否具備索引。 若是是,則在.channel字段中指定索引。

l  scan_index and scan_type: 當使用緩衝區觸發器時,這些字段用於標識緩衝區中的元素。 scan_index設置緩衝區內捕獲的通道的位置。 具備較低scan_index的通道將放置在具備較高索引的通道以前。 將.scan_index設置爲-1將阻止通道進行緩衝捕獲(scan_elements目錄中沒有條目)。

  暴露給用戶空間的通道sysfs屬性以位掩碼的形式指定。 根據共享信息,能夠將屬性設置爲如下掩碼之一:

l  info_mask_separate 將屬性標記爲特定於此通

l  info_mask_shared_by_type 將該屬性標記爲由相同類型的全部通道共享。 導出的信息由相同類型的全部通道共享。

l  info_mask_shared_by_dir 將屬性標記爲由同一方向的全部通道共享。 導出的信息由同一方向的全部通道共享。

l  info_mask_shared_by_all 將屬性標記爲全部通道共享,不管其類型或方向如何。 導出的信息由全部渠道共享。 用於枚舉這些屬性的位掩碼都在include / linux / iio / iio.h中定義:

 

enum iio_chan_info_enum {
    IIO_CHAN_INFO_RAW = 0,
    IIO_CHAN_INFO_PROCESSED,
    IIO_CHAN_INFO_SCALE,
    IIO_CHAN_INFO_OFFSET,
    IIO_CHAN_INFO_CALIBSCALE,
    [...]
    IIO_CHAN_INFO_SAMP_FREQ,
    IIO_CHAN_INFO_FREQUENCY,
    IIO_CHAN_INFO_PHASE,
    IIO_CHAN_INFO_HARDWAREGAIN,
    IIO_CHAN_INFO_HYSTERESIS,
    [...]
};

字節序字段應爲如下之一:         

enum iio_endian {
                         IIO_CPU,
                         IIO_BE,
                         IIO_LE,

};

 

Channel attribute naming conventions:通道屬性命名約定 

  屬性的名稱由IIO核心自動生成,具備如下模式:{direction} _ {type} _ {index} _ {modifier} _ {info_mask}:

  l  direction方向對應於屬性方向,根據drivers / iio / industrialio-core.c中的struct iio_direction結構:

static const char * const iio_direction[] = {
   [0] = "in",
   [1] = "out", 
}; 

  l  type對應於通道類型,根據char數組const iio_chan_type_name_spec:

static const char * const iio_chan_type_name_spec[] = {
   [IIO_VOLTAGE] = "voltage",
   [IIO_CURRENT] = "current",
   [IIO_POWER] = "power",
   [IIO_ACCEL] = "accel",
   [...]
   [IIO_UVINDEX] = "uvindex",
   [IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
   [IIO_COUNT] = "count",
   [IIO_INDEX] = "index",
   [IIO_GRAVITY]  = "gravity",
};

l  index 索引模式取決因而否設置了通道.indexed字段。 若是設置,索引將從.channel字段中獲取,以替換{index}模式。

l  modifier 模式取決於通道所設置的.modified字段。 若是設置,修飾符將從.channel2字段中獲取,{modifier}模式將根據char數組struct iio_modifier_names結構替換:

static const char * const iio_modifier_names[] = {
   [IIO_MOD_X] = "x",
   [IIO_MOD_Y] = "y",
   [IIO_MOD_Z] = "z",
   [IIO_MOD_X_AND_Y] = "x&y",
   [IIO_MOD_X_AND_Z] = "x&z",
   [IIO_MOD_Y_AND_Z] = "y&z",
   [...]
   [IIO_MOD_CO2] = "co2",
   [IIO_MOD_VOC] = "voc",
};

l  info_mask取決於char數組iio_chan_info_postfix中的通道信息掩碼,私有或共享索引值:

/* relies on pairs of these shared then separate依賴於這些共享的對,而後分離*/
static const char * const iio_chan_info_postfix[] = {
   [IIO_CHAN_INFO_RAW] = "raw",
   [IIO_CHAN_INFO_PROCESSED] = "input",
   [IIO_CHAN_INFO_SCALE] = "scale",
   [IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
   [...]
   [IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
   [IIO_CHAN_INFO_FREQUENCY] = "frequency",
   [...]
};

 

Distinguishing channels通道區分

當每種通道類型有多個數據通道時,您可能會遇到麻煩。 困境將是:如何識別它們。 有兩種解決方案:索引和修飾符。

使用索引:給定具備一個通道線的ADC器件,不須要索引。通道定義以下:

static const struct iio_chan_spec adc_channels[] = {
                {
                        .type = IIO_VOLTAGE,
                        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),

               },
}

由前面描述的通道產生的屬性名稱將是in_voltage_raw。

/sys/bus/iio/iio:deviceX/in_voltage_raw

如今讓咱們看一下有4個甚至8個通道的轉換器。 咱們如何識別它們? 解決方案是使用索引。 將.indexed字段設置爲1將使用.channel值替換{index}模式來替換通道屬性名稱:

 

            

  static const struct iio_chan_spec adc_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
                .channel = 0,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),

        },

        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
                .channel = 1,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        },
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
                .channel = 2,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        },
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
                .channel = 3,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
        },
}

生成的通道屬性爲:

 /sys/bus/iio/iio:deviceX/in_voltage0_raw
/sys/bus/iio/iio:deviceX/in_voltage1_raw
/sys/bus/iio/iio:deviceX/in_voltage2_raw
/sys/bus/iio/iio:deviceX/in_voltage3_raw

  使用修飾符:給定一個帶有兩個通道的光傳感器 - 一個用於紅外光,一個用於紅外和可見光,沒有索引或修改器,屬性名稱將爲in_intensity_raw。 在這裏使用索引可能容易出錯,由於使用in_intensity0_ir_raw和in_intensity1_ir_raw是沒有意義的。 使用修飾符將有助於提供有意義的屬性名稱。 通道的定義以下:

       

static const struct iio_chan_spec mylight_channels[] = {

        {
                .type = IIO_INTENSITY,
                .modified = 1,
                .channel2 = IIO_MOD_LIGHT_IR,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
                .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
        {
                .type = IIO_INTENSITY,
                .modified = 1,
                .channel2 = IIO_MOD_LIGHT_BOTH,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
                .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
        {
                .type = IIO_LIGHT,
                .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
                .info_mask_shared =BIT(IIO_CHAN_INFO_SAMP_FREQ),

        },
       }

屬性結果:

l  /sys/bus/iio/iio:deviceX/in_intensity_ir_raw 用於測量IR強度的通道

l  /sys/bus/iio/iio:deviceX/in_intensity_both_raw用於測量紅外和可見光的通道

l  /sys/bus/iio/iio:deviceX/in_illuminance_input用於處理後的數據

l  /sys/bus/iio/iio:deviceX/sampling_frequency 用於採樣頻率,由全部人共享

  這也適用於加速度計,咱們將在案例研究中進一步瞭解。 如今,讓咱們總結一下咱們到目前爲止在虛擬IIO驅動程序中討論過的內容。

Putting it all together總結

  讓咱們總結一下迄今爲止咱們在一個簡單的虛擬驅動器中看到的內容,它將暴露出四個電壓通道。 咱們將忽略read()或write()函數:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>


#define FAKE_VOLTAGE_CHANNEL(num)                  \
   {                                               \
         .type = IIO_VOLTAGE,                      \
         .indexed = 1,                             \
         .channel = (num),                         \
         .address = (num),                         \
         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
         .info_mask_shared_by_type =BIT(IIO_CHAN_INFO_SCALE) \

   }


struct my_private_data {
    int foo;
    int bar;
    struct mutex lock;
};

static int fake_read_raw(struct iio_dev *indio_dev,
                   struct iio_chan_spec const *channel, int *val,
                   int *val2, long mask)
{
    return 0;
}

static int fake_write_raw(struct iio_dev *indio_dev,
                   struct iio_chan_spec const *chan,
                   int val, int val2, long mask)
{
    return 0;
}

static const struct iio_chan_spec fake_channels[] = {
   FAKE_VOLTAGE_CHANNEL(0),
   FAKE_VOLTAGE_CHANNEL(1), 
   FAKE_VOLTAGE_CHANNEL(2),
   FAKE_VOLTAGE_CHANNEL(3),

};

static const struct of_device_id iio_dummy_ids[] = {
    { .compatible = "packt,iio-dummy-random", },
    { /* sentinel */ }
};

static const struct iio_info fake_iio_info = {
   .read_raw = fake_read_raw,
   .write_raw        = fake_write_raw,
   .driver_module = THIS_MODULE,
};

static int my_pdrv_probe (struct platform_device *pdev)
{
    struct iio_dev *indio_dev;
    struct my_private_data *data;
   indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));

   if (!indio_dev) {
         dev_err(&pdev->dev, "iio allocation failed!\n");
         return -ENOMEM;
   }

   data = iio_priv(indio_dev);
   mutex_init(&data->lock);
   indio_dev->dev.parent = &pdev->dev;
   indio_dev->info = &fake_iio_info;
   indio_dev->name = KBUILD_MODNAME;
   indio_dev->modes = INDIO_DIRECT_MODE;
   indio_dev->channels = fake_channels;
   indio_dev->num_channels = ARRAY_SIZE(fake_channels);
   indio_dev->available_scan_masks = 0xF;
    iio_device_register(indio_dev);
    platform_set_drvdata(pdev, indio_dev);
    return 0;
}
static void my_pdrv_remove(struct platform_device *pdev)
{
    struct iio_dev *indio_dev = platform_get_drvdata(pdev);
    iio_device_unregister(indio_dev);
}
static struct platform_driver mypdrv = {
    .probe      = my_pdrv_probe,
    .remove     = my_pdrv_remove,
    .driver     = {
        .name     = "iio-dummy-random",
        .of_match_table = of_match_ptr(iio_dummy_ids),  
        .owner    = THIS_MODULE,
    },
};
module_platform_driver(mypdrv);
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_LICENSE("GPL");

  加載上述模塊後, 咱們將有如下輸出, 顯示咱們的設備確實對應於咱們已註冊的平臺設備:

  ~# ls -l /sys/bus/iio/devices/
lrwxrwxrwx 1 root root 0 Jul 31 20:26 iio:device0 -> ../../../devices/platform/iio-dummy-random.0/iio:device0
lrwxrwxrwx 1 root root 0 Jul 31 20:23 iio_sysfs_trigger -> ../../../devices/iio_sysfs_trigger

  下面的列表顯示了此設備的通道及其名稱, 這些通道與咱們在驅動程序中描述的內容徹底對應: 

 ~# ls /sys/bus/iio/devices/iio\:device0/
dev in_voltage2_raw name uevent
in_voltage0_raw in_voltage3_raw power
in_voltage1_raw in_voltage_scale subsystem
~# cat /sys/bus/iio/devices/iio:device0/name
iio_dummy_random
相關文章
相關標籤/搜索