qnx i2c 学习 二

时间:2022-10-22 16:32:21

File still Updating.... many errors have been FOUND , need big change 

qnx i2c structure  --written by jlm

qnx i2c 学习 二

MSM8996AU/APQ8096AU has two BLSP blocks. Each block includes six Qualcomm® Universal
Peripheral (QUP) and six UART cores.
Bus Access Module (BAM) is used to move data to/from the peripheral buffers. BAM is a
hardware data mover, rather than a legacy data mover (ADM).
Each BLSP:
■ Is statically connected to a pair of BAM pipes.
■ Consists of 24 pipes for data move operations.
■ Supports BAM and non-BAM based data transfers.

BLSP supports the following protocols:
■ UART with data rates up to 4 Mbps. UART core can be configured as either a UART, SIM, or
IrDA interface.
■ I2C with data rates up to 1 Mbps
■ SPI bus with data rates up to 50 Mbps

在qnx上i2c的代码结构感觉有点乱 要理一理

5个地方

Services and resource managers

A resource manager is a user-level server program that accepts messages from other programs and communicates with hardware .

The resource manager sets up a pathname-space mapping by informing the process manager that it is the one responsible for handling requests at a certain mountpoint.

Core services initialize resource managers for each hardware driver. For example, i2c_service initializes I2C resource manager and spi_service initializes SPI resource manager.

In other words resource manager is the i2c driver
i2c server

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\services\daemons\i2c_service\src\i2cservice_main.c

resource manaer:

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\resources\i2c_drv\i2c_drv.c

hardware drivers:

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cGpioCfg.c

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cPlatBsp.c

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cPlatSvc.c

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\hwdrivers\i2c\common\src\I2cDeviceQup.c

qcore is the core service that establishes clock/power resource nodes for drivers. The qcore
service creates devcfg nodes for BSP drivers. Each BSP driver communicates with qcore over
devcfg nodes to enable power and clock resources. npa_client library provides APIs for drivers
to access devcfg nodes.

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\services\daemons\qcore\src\qcore_baseinit.c

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\services\daemons\qcore\src\qcore_main.c

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\platform\hwdrivers\i2c\devcfg_i2c\src\devcfg_i2c.c

QAL are the client libraries that provide APIs for user applications/services to access hardware
resource managers. QAL facilitates file I/O operations on /dev/ nodes to access hardware.
For example, to access SPI resource manager for an SPI device registered at /dev/spi*, QAL
spi_client provides the following APIs:
■ spi_open(…)
■ spi_write(…)
■ spi_read(…) 
i2c client

Y:\home\gary\work\qnx_ap\3rdparty\AMSS\qal\clients\i2c_client\i2c_client.c

QNX DAL configuration (dalconfig) libraries are SoC and platform-specific hardware configuration
information libraries used by QNX DAL framework. Each BSP hardware driver extracts hardware
configuration from dalconfig at runtime. The configuration information is packed as a shared
library (dalconfig.so) and linked to drivers at runtime. Each driver is initialized after parsing
hardware configuration information from dalconfig library 
QNX builds consist of the following types of configuration files:

■ SoC-specific configurations files at qnx_ap/AMSS/qal/dal/dalconfig/    --->currently not applicable for qnx i2c of this project

■ Board-specific configuration files at qnx_ap/boards/core/dalconfig/mojave_v2_8996/config    --->for i2c configuration, here can configure the i2c slave device

qnx i2c 学习 二

  • i2c service start:

Y:\home\gary\work\qnx_ap\3rdparty\target\hypervisor\qvm\host\startupmgr-host-qvmhost\src\script.c
static const char* i2c_arg [] = {
"i2c_service",
"-e", "6",
"-e", "7",
"-e", "8",
"-e", "2", //jlm add
NULL,
};
 
//create i2c dev from here
static const struct aaction* coreservices [] = {
&syslog,
&mojave_v2_links,
&mojave_v1_links,
&cdp_links,
&pi_links,
&dbg_uart,
&reopen_serdev,
&qcore,
&wdogsafe,
&dumper,
&qcgpio,
&spi,
&i2c,
//Delimit with NULL,
NULL,
};
 
//the &i2c above was defined in below:

Y:\home\gary\work\qnx_ap\3rdparty\target\filesets\launcher_scripts\i2c.c

static const struct aaction i2c = {
.type = TYPE_CMD,
.c = {
.path = "i2c_service",
.arg = i2c_arg//the i2c_arg was defined in above
.secpol_type = "i2c_service_t",
},
};
 
  • How to configure i2c in qnx

  当script的参数传入i2c service_main的时候,首先对传入参数进行解析,走到X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\services\daemons\i2c_service\src\i2cservice_main.c

 int main(int argc, char *argv[]) {

     int                  c;
     uint32_t             enable_mask = ;
     logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR, QCLOG_INFO,
             "main: %s %s", __DATE__, __TIME__);

      )
     {
         switch( c ) {
             case 'v':
                 slog2_set_verbosity ( amss_default_slog2_buffer , SLOG2_DEBUG2 ) ;
                 break;
             case 'e':
                 enable_mask |= (1u << atoi ( optarg ));
                 break;
             case 'U':
                 if(_secpol_in_use()) {
                     if(set_ids_from_arg(optarg) != EOK )
                     {
                         logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR, QCLOG_ERROR,
                         "UID/GID setting failed");
                     return EXIT_FAILURE;
                     }
                 }
                 break;
             default :
                 break;
         }
     }

     if ( ! enable_mask ) {
         logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR, QCLOG_ERROR,
                 "-e mandatory option missing, exiting");
         return EXIT_FAILURE;
     }

     /* QNX IO operation privilege */
     ) == -)
     {
         PROCESS_ERROR_CRITICAL("i2c_service: ThreadCtl Error");
         return EXIT_FAILURE;
     }

     signal(SIGTERM,handle_sigterm);
     // Check if process is running
      < open(DEVICE_NAME, O_RDONLY))
     {
         PROCESS_ERROR_CRITICAL("Process [%s] already running.. exiting.", DEVICE_NAME);
         return EXIT_FAILURE;
     }

     // Run process in background
     Resource_Daemonize();

     if(i2c_service_base_init( enable_mask )!=DAL_SUCCESS)
     {
         PROCESS_ERROR_CRITICAL("i2c_service: i2c_service_core_init failed");
         return EXIT_FAILURE;
     }
     drop_abilities_i2c();
     /* the i2c resource manager main loop is going to run after here */
     if(DAL_SUCCESS != sysctrl_start(DEVICE_NAME)) {
         PROCESS_ERROR_CRITICAL("i2c_service: service_init failed");
         return EXIT_FAILURE;
     }

     // Code should never reach here
     PROCESS_ERROR_CRITICAL("Exiting i2c_service..");
     return EXIT_SUCCESS;
 }
 int i2c_service_base_init( uint32_t enable_mask )
 {
      == i2c_drv_init(enable_mask))
     {
         logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR, QCLOG_ERROR, "i2c_drv_init Failed");
     }

     /* init sysctrl */
     if(DAL_SUCCESS != sysctrl_init())
     {
         logger_log(QCLOG_AMSS_QNP_SERVICES_I2C_SERVICE, QCLOG_AMSS_I2C_SERVICE_MINOR, QCLOG_ERROR, "sysctrl_init failed, errno: %s", strerror(errno));
         return DAL_ERROR;
     }

     return DAL_SUCCESS;
 }

然后调用X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\resources\i2c_drv\i2c_drv.c

 /******************************************************************************/
 /***************************** startup and config  ****************************/
 /******************************************************************************/

 int i2c_drv_init(uint32_t enable_mask)
 {
     int i;
     ;
     pthread_t threadID;

     logger_log(QCLOG_AMSS_CORE, QCLOG_AMSS_QNP_PLATFORM_I2C_DRV, QCLOG_INFO,
             "I2C RM starting up (enable_mask=0x%x)\n", enable_mask);

     devs = calloc(MAX_NUM_I2C_DEVS, sizeof(i2c_dev_t));
     if(devs == NULL)
         ;

     // create devices , if specified via command line
     ; i <= MAX_NUM_I2C_DEVS; i++)
     {
         //Is this device enabled ?
         if ( enable_mask & (1U << i)) {
             logger_log(QCLOG_AMSS_CORE, QCLOG_AMSS_QNP_PLATFORM_I2C_DRV, QCLOG_INFO,
                     "Initializing device 0x%x (i2c%d)" ,  DeviceID[i] , i ) ;

             devs[idx].DALDeviceID = DeviceID[i]; //if i2c8 =DALDEVICEID_I2C_DEVICE_8  i=7
             devs[idx].index = idx; //idx =2  -e 6,-e 7, -e 8,
             devs[idx].timer_created = ;
             devs[idx].bus_active = ;
             I2CDEV_Init(DeviceID[i], &devs[idx].ahI2cDev);
             snprintf(devs[idx].devname, MAX_NUM_DEVNAME, "/dev/i2c%d", i);
             pthread_create(&threadID, NULL, (void *) &device_main, (void *)&devs[idx]);
             pthread_setname_np(threadID,devs[idx].devname);
             idx++;
         }
     }

     ;
 }

先跳到函数I2CDEV_Init中X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\hwdrivers\i2c\common\src\I2cDeviceQup.c

 /** @brief Initializes the device.

     This Function Initializes the device and creates the
     necessary data structures to support other calls into the
     device.

     @param[in] uPlatDevId    Platform Device ID.
     @param[inout] phDev         Pointer to device handle.

     @return          int32 .
   */
 int32
 I2CDEV_Init
 (
    uint32                              uPlatDevId,
    I2CDEV_HANDLE                       *phDev
 )
 {
    int32                               res = I2C_RES_SUCCESS;
    I2CDEVQUP_Device                    *pDev = NULL;
    uint32                               uWhileOnce = ;

   //search if the dev exists in the dev list
    pDev = I2CDEVQUP_SearchDevice(uPlatDevId);
    if ( NULL != pDev ) {
       *phDev = pDev;
       return I2C_RES_SUCCESS;
    }

    res = (int32)I2CSYS_Malloc((void **)&pDev, sizeof(I2CDEVQUP_Device));
    if ( I2C_RES_SUCCESS != res )  {
       return res;
    }
    res = I2CSYS_Memset(pDev, , sizeof(I2CDEVQUP_Device));
    if ( I2C_RES_SUCCESS != res )  {
       I2CSYS_Free(pDev);
       return res;
    }

    pDev->uPlatDevId = uPlatDevId;
    pDev->devInitState = I2CDEVQUP_InitState_Uninitialized;

    do {
       res = (int32)I2CPLATDEV_InitTarget(uPlatDevId, &pDev->hDevTgt);//the uPlatDevId =DALDEVICEID_I2C_DEVICE_8 0x020000C7
       if ( I2C_RES_SUCCESS != res ) {
          break;
       }
       pDev->devInitState |= I2CDEVQUP_InitState_TargetInit_Done;

       res = (int32)I2CPLATDEV_ReadProperties(pDev->hDevTgt, &pDev->devProps);
       if ( I2C_RES_SUCCESS != res ) {
          break;
       }
       pDev->seqInfo.outSeqInfo.pSeq      = &pDev->seqInfo;
       pDev->seqInfo.inSeqInfo.pSeq       = &pDev->seqInfo;

       if ( pDev->devProps.bBamAvailable ) {
          /* allocate bam buffer. */
          pDev->seqInfo.physMem.uSize = *BAM_TMPBUFF_MAX;// input+output
          res = I2CSYS_PhysMemAlloc(&pDev->seqInfo.physMem);
          if (I2C_RES_SUCCESS != res) {
             break;
          }

          if ( !I2cCacheCtrlInited ) {
         res = cache_init(, &I2cCacheCtrl, NULL);
             if (I2C_RES_SUCCESS != res) {
           break;
         }
         I2cCacheCtrlInited = ;
          }
          pDev->devInitState |= I2CDEVQUP_InitState_PhysMemAlloc_Done;
          /* use top half for output and bottom half for input. */
          pDev->seqInfo.outSeqInfo.aOutBamBuff =
                      pDev->seqInfo.physMem.pVirtAddress;
          pDev->seqInfo.inSeqInfo.aInBamBuff =
               &pDev->seqInfo.outSeqInfo.aOutBamBuff[BAM_TMPBUFF_MAX];
       }

       if ( pDev->devProps.bInterruptBased ) {
          res = (int32)I2CSYS_CreateEvent(&pDev->hQupEvt);
          if ( I2C_RES_SUCCESS != res ) {
             break;
          }
          pDev->devInitState |= I2CDEVQUP_InitState_Events_Done;
       }

       res = I2CSYS_CreateCriticalSection(&pDev->hOperationSync);
       if ( I2C_RES_SUCCESS != res ) {
          break;
       }
       pDev->devInitState |= I2CDEVQUP_InitState_CritSectionCreate_Done;

       pDev->clntCfg.uBusFreqKhz = I2CDEVQUP_DEFAULT_BUS_FREQ_KHZ;
       pDev->clntCfg.uByteTransferTimeoutUs =
          I2CDEVQUP_DEFAULT_BYTE_TRANSFER_TIMEOUT_US;
       pDev->devInitState |= I2CDEVQUP_InitState_DeviceInit_Done;
       pDev->devPowerState = I2CDEV_POWER_STATE_0;
       /* Init device logging. */
       I2cLog_Init((uint32)pDev->uPlatDevId, &pDev->pDevLog);
       I2cLog_AssociateBlockAddress(pDev->pDevLog, (uint64)pDev->devProps.virtBlockAddr);

       I2CDEVQUP_LinkDevice(pDev);

       *phDev = pDev;
    } while ( uWhileOnce );

    if ( I2C_RES_SUCCESS != res ) { /* in case of error undo initialization. */
       I2CDEV_DeInit(pDev);
    }

    return res;
 }


跳转到X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cPlatSvc.c

 /**
     This Function initializes target support structures and subsystems.

     @param[in]  uPlatDevId  Platform specific device identifier.
     @param[out] phPlat      Pointer to platform handle.

     @return             I2C_RES_SUCCESS is successful, otherwise
                         I2CPLATSVC_Error.
   */
 int32
 I2CPLATDEV_InitTarget
 (
    uint32            uPlatDevId,
    I2CPLATDEV_HANDLE *phPlat
 )
 {
    I2CPLATDEV_TargetCfgType       *pDev;
    int32                           res;

    res = I2CSYS_Malloc((void **)&pDev, sizeof(I2CPLATDEV_TargetCfgType));
    if (I2C_RES_SUCCESS != res) {
       return res;
    }

    res = I2CSYS_Memset(pDev, , sizeof(I2CPLATDEV_TargetCfgType));
    if ( I2C_RES_SUCCESS != res ) {
       I2CSYS_Free(pDev);
       return res;
    }
    pDev->initState = I2CPLATDEV_TGT_INIT_NOT_DONE;

    do
    {
       res = I2CPLATDEV_ReadPlatConfig(uPlatDevId, &pDev->platProps);//define DALDEVICEID_I2C_DEVICE_8 0x020000C7
       if ( I2C_RES_SUCCESS != res ) {
          break;
       }

       if ( !_secpol_in_use ( ) ) {
           ,
                                      (PROCMGR_AID_IO        | PROCMGR_AOP_ALLOW | PROCMGR_ADN_NONROOT),
                                      (PROCMGR_AID_INTERRUPT | PROCMGR_AOP_ALLOW | PROCMGR_ADN_NONROOT),
                                      (PROCMGR_AID_MEM_PHYS  | PROCMGR_AOP_ALLOW | PROCMGR_ADN_NONROOT),
                                      PROCMGR_AID_EOL))
           {
              res = I2CPLATSVC_ERROR_FAILED_ABILITIES;
              break;
           }
       }

        == ThreadCtl(_NTO_TCTL_IO, )) {
          res = I2CPLATSVC_ERROR_FAILED_THREAD_CTRL;
          break;
       }

       res = I2CPLATDEV_InitHwio(pDev);
       if ( I2C_RES_SUCCESS != res ) {
          break;
       }
       res = I2CPLATDEV_NpaInit(pDev);
       if(I2C_RES_SUCCESS != res)
       {
          break;
       }

       pDev->uPlatDevId = uPlatDevId;
       *phPlat = (I2CPLATDEV_HANDLE) pDev;
       res = I2C_RES_SUCCESS;
     }  );

    if ( I2C_RES_SUCCESS != res ) {
       I2CPLATDEV_DeInitTarget(pDev);
    }
    return res;
 }

先根据传进来的地址去进行匹配X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cPlatBsp.c

i2c_8996_bsp里面包含了中断号,dev name resourceName, 地址,block size,还有resource name, 这个是和qcore 那边的devcfg_i2c.c 对应的

 /*-------------------------------------------------------------------------
  * Global vars
  * ----------------------------------------------------------------------*/
 I2CPLATDEV_PlatPropertiesType i2c_8996_bsp[] =
 {
    {                          // device 1
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C1_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c1",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/1",        //    resourceName
       "I2C_CORE_1",           //    coreName
       (uint8 *)0x7575000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 2
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C2_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c2",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/2",        //    resourceName
       "I2C_CORE_2",           //    coreName
       (uint8 *)0x7576000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 3
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C3_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c3",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/3",        //    resourceName
       "I2C_CORE_3",           //    coreName
       (uint8 *)0x7577000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 4
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C4_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c4",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/4",        //    resourceName
       "I2C_CORE_4",           //    coreName
       (uint8 *)0x7578000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 5
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C5_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c5",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/5",        //    resourceName
       "I2C_CORE_5",           //    coreName
       (uint8 *)0x7579000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 6
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C6_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c6",            //    pDevName;
       "/dev/bam0",            //    pBamName
       "/devcfg/i2c/6",        //    resourceName
       "I2C_CORE_6",           //    coreName
       (uint8 *)0x757A000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize

       ,                      //    bBamEnabled;
       (uint8 *)BAM1_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM1_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 7
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C7_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c7",            //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/7",        //    resourceName
       "I2C_CORE_7",           //    coreName
       (uint8 *)0x75B5000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 8
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C8_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c8",            //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/8",        //    resourceName
       "I2C_CORE_8",           //    coreName
       (uint8 *)0x75B6000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 9
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C9_CLOCK_RATE_KHZ,    //    uI2cSrcClkKhz;
       "/dev/i2c9",            //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/9",        //    resourceName
       "I2C_CORE_9",           //    coreName
       (uint8 *)0x75B7000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 10
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C10_CLOCK_RATE_KHZ,   //    uI2cSrcClkKhz;
       "/dev/i2c10",           //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/10",       //    resourceName
       "I2C_CORE_10",          //    coreName
       (uint8 *)0x75B8000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 11
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C11_CLOCK_RATE_KHZ,   //    uI2cSrcClkKhz;
       "/dev/i2c11",           //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/11",       //    resourceName
       "I2C_CORE_11",          //    coreName
       (uint8 *)0x75B9000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
    {                          // device 12
       ,                      //    bInterruptBased;
       ,                      //    bDisablePm;
       ,                    //    uInterruptId;
       HAL_QGIC_TRIGGER_LEVEL, //    uIrqTriggerCfg;
       I2C12_CLOCK_RATE_KHZ,   //    uI2cSrcClkKhz;
       "/dev/i2c12",           //    pDevName;
       "/dev/bam1",            //    pBamName
       "/devcfg/i2c/12",       //    resourceName
       "I2C_CORE_12",          //    coreName
       (uint8 *)0x75BA000,              //    uBlkPhysAddr;
       0x1000,                 //    uBlkSize;

       ,                      //    bBamEnabled;
       (uint8 *)BAM2_BLOCK_ADDRESS,     //    uBamPhysAddr;
       BAM2_IRQ,               //    uBamIrqId;
       BAM_THRESHOLD,          //    uBamThreshold;
       ,                     //    uBamInPipeId;
                             //    uBamOutPipeId;
    },
 };

 /** @brief Gets device-specific configuration settings.

     @param[in]  uPlatDevId  Platform device ID.
     @param[out] pDev        Pointer to platform device
           structure.

     @return             I2CPLATSVC_Error type: I2C_RES_SUCCESS if successful, otherwise
                         error.
   */
 int32
 I2CPLATDEV_ReadPlatConfig
 (
    uint32                         uPlatDevId,
    I2CPLATDEV_PlatPropertiesType  *pDev
 )
 {
    int dev_id_idx;

    switch(uPlatDevId) {
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ;  break;
       ; break;
       ; break;
       default: return I2CBSP_INVALID_PLAT_ID;
    }

    if ( dev_id_idx > (sizeof(i2c_8996_bsp)/sizeof(I2CPLATDEV_PlatPropertiesType)) ) {
       return I2CBSP_INVALID_PLAT_ID;
    }

    // copy element into location
    *pDev = i2c_8996_bsp[dev_id_idx];
    return I2CBSP_SUCCESS;
 }

Note:

according to the datasheet the IRQ defined above is not the same as described below, due to the reason that : interrupt number 0~31 was reserved by the system so, need to +32 to get the actual interrput numer

like 95+32=127 for device 1and for device 8 (gpio6/7) 102+32=134  (match the number)

you can refer to https://blog.csdn.net/phenix_lord/article/details/45116259 as reference

然后去init hw 和创建npa client X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\hwdrivers\i2c\platsvc_i2c\src\I2cPlatSvc.c

 /** @brief Initializes the clocks for the qup core.

     @param[in] pDev     Pointer to platform device structure.

     @return             I2C_RES_SUCCESS is successful, otherwise
                         I2CPLATSVC_Error.
   */
 int32
 I2CPLATDEV_NpaInit
 (
    I2CPLATDEV_TargetCfgType *pDev
 )
 {

    const char* resources [] = { pDev->platProps.resourceName };
    npa_resources_available_waitfor (  , resources ) ;

    /*Create a npa handle for the i2c core*/
    pDev->npaRes.npaHandle = npa_create_sync_client(pDev->platProps.resourceName,
                                                    pDev->platProps.coreName,
                                                    NPA_CLIENT_REQUIRED);

    if (NULL == pDev->npaRes.npaHandle) {
       return I2CPLATSVC_ERROR_FAILED_TO_SYNC_CLIENT;
    }

 #if 0
    do not issue Initialize request here... this would configure gpios
    for i2c ports that may never be used... instead wait for open.

    npa_issue_required_request(pDev->npaRes.npaHandle,
                               I2C_DEVCFG_STATE_INITIALIZE);
 #endif

   return I2C_RES_SUCCESS;
 }

qnx i2c 学习 二

So if we want to add or remove or change the device name , modified the file above

 

另外一条线就是qcore

X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\services\daemons\qcore\src\qcore_baseinit.c

int qcore_base_init( uint32 initFlags )
{
    /* Init Dalsys */
...

    logger_log(QCLOG_AMSS_CORE, QCLOG_AMSS_QCORE_BASEINIT, QCLOG_INFO, "i2c_devcfg_init()");
    i2c_devcfg_init ( NULL  ) ;

...
}
 跳转到X:\qnx_poc\qnx_workspace\hqx1.1-8.1-qnx\3rdparty\AMSS\platform\hwdrivers\i2c\devcfg_i2c\src\devcfg_i2c.c
 /* Initialization function.*/
 int i2c_devcfg_init( const char * cmdline )
 {
    int i;

    ; i < BLSP_NUM; i++) {
       npa_resource_available_cb(blsp[i].resource_name, uart_init_cb,
               &blsp[i].blsp_instance);
    }

    npa_define_node(&i2c_node, NULL,NULL);

    ;
 }

i2c_node 定义

static npa_node_definition i2c_node =
{
   "/node/devcfg/i2c",      // Node name - used when making dependency requests
   i2c_npa_fcn,             // Node Driver Function - From code above
   NPA_NODE_DEFAULT,        // Attributes
   NULL,                    // User Data - In case you need Node specific data
   NPA_EMPTY_ARRAY,         // Node Dependencies - From code above
   NPA_ARRAY(i2c_resource)  // Node Resources - From code above
};

以device_8 为例子

里面定义了i2c data的pin, clk的pin, gpio funciton,

       {
          DALDEVICEID_I2C_DEVICE_8,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup2_i2c_apps_clk",
          ,
          ,
          ,                      //    data_gpio_number
          ,                      //    data_gpio_function
          ,                      //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

   {
       "/devcfg/i2c/8",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

查找pin assignment

qnx i2c 学习 二

根据上面的表格,pin的funciton就是3

下面是所有的i2c 的definition

 static i2c_npa_info i2c_usr_info[I2C_NUM_DEVICES] =
 {

       {
          DALDEVICEID_I2C_DEVICE_1,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup1_i2c_apps_clk",
          ,
          ,
          ,                      //    data_gpio_number
          ,                      //    data_gpio_function
          ,                      //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_2,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup2_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_3,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup3_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_4,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup4_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_5,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup5_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_6,
          "gcc_blsp1_ahb_clk",
          "gcc_blsp1_qup6_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_7,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup1_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_8,    //# define DALDEVICEID_I2C_DEVICE_8 0x020000C7

          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup2_i2c_apps_clk",
          ,
          ,
          ,                      //    data_gpio_number
          ,                      //    data_gpio_function
          ,                      //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_9,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup3_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_10,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup4_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_11,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup5_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },

       {
          DALDEVICEID_I2C_DEVICE_12,
          "gcc_blsp2_ahb_clk",
          "gcc_blsp2_qup6_i2c_apps_clk",
          ,
          ,
          ,                     //    data_gpio_number
          ,                      //    data_gpio_function
          ,                     //    clk_gpio_number
          ,                      //    clk_gpio_function
          I2C_DEVCFG_STATE_DEINITIALIZE
       },
 };

 /*Each resource is tied to a single node*/
 static npa_resource_definition i2c_resource[] =
 {
    {
       "/devcfg/i2c/1",                         /*Resource Name*/
       "I2C State",                              /* Resource Units - Informational only*/
       I2C_DEVCFG_STATE_ON,          /* Resource Max*/
       &npa_max_plugin,                   /* Define how clients are aggregated*/
                                                       /* We are using a predefined aggregation*/
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,     /* Default resource behavior*/
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/2",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/3",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/4",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/5",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/6",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/7",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/8",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/9",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/10",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/11",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },

    {
       "/devcfg/i2c/12",
       "I2C State",
       I2C_DEVCFG_STATE_ON,
       &npa_max_plugin,
       NPA_RESOURCE_DEFAULT|NPA_RESOURCE_INTERPROCESS_ACCESS_ALLOWED,
       &i2c_usr_info[],
       i2c_npa_query_fcn,
       NULL
    },
 };

i2c definition

也就是说一部分是放在了qcore的devcfg_i2c.c中,一部风是在 resource manager里面去定义,

创建npa node的时候,会去调用 /devcfg/i2c/8 去创建

  • How to add slave in qnx

For this section I need to verify and todo further study 

Not like pure android platform, the qnx will define the slave node in the xml file

for example:

the ti_uh949q bridge should be attached to the i2c8 , search the i2c8 and found

qnx i2c 学习 二

for example the bridge attached under i2c8 and the slave address is 0x0c

qnx i2c 学习 二

  • How to add new i2c

For this section, please see section i2c_service_start

新增加一个i2c1 发现改了 script.c之后还是不能创建,创建i2c1 就core dump, 发现时下面的原因,在\\192.168.242.128\share\home\jinluming\work\qnx_spi\hqx1.1-8.1-qnx\3rdparty\target\filesets\secpol\i2c.txt 中

没有定义i2c1 的中断

blsp2_qup_irq_0,blsp1_qup_irq_5,blsp2_qup_irq_1所以会崩溃改为或者增加一个blsp1_qup_irq_0 -->对应i2c1 就可以了spi估计也一样 要特别注意
# === Rules for type i2c_service_t ==========
allow i2c_service_t self:ability {
    nonroot
    setuid:I2C_SERVICE_UID
    setgid:I2C_SERVICE_GID,QCORE_GID
    #TODO: Interrupt is handled/attached during every write/read. Hence ability is not dropped
    interruptevent:blsp2_qup_irq_0,blsp1_qup_irq_5,blsp2_qup_irq_1
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP1_BLSP.QUP5_DD_4K
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP2_BLSP.QUP0_DD_4K
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP2_BLSP.QUP1_DD_4K
    mem_phys:__DMA_POOL_START__-__DMA_POOL_END__
    iofunc/exec
    io:
    spawn
    public_channel
    xthread_threadctl
    pathspace
    channel_connect
    mem_peer
    mem_special
    keydata
    rlimit
};

allow i2c_service_t self:ability {
    nonroot
    unlock
    map_fixed
    prot_exec
    prot_write_and_exec
};

allow_attach i2c_service_t {

    /dev/i2c*
    /dev/i2c_service
    /dev/npa
    /dev/pmem/i2c_service
};

allow i2c_service_t {
    qcore_t
    slogger2_t
    smmu_service_t
    bmetrics_t
}:channel connect;
  • the call sequence of probe/remove

use the i2cdbgr as the example:

the i2cdbgr will call function   i2c_combined_writeread to read the i2c register

Y:\home\jinluming\work\qnx_ap\3rdparty\AMSS\qal\clients\i2c_client\i2c_client.c

 int i2c_combined_writeread(int fd, void * wbuff, uint32_t wlen, void* rbuff, uint32_t rlen )
 {
    ;
     i2c_sendrecv_t msg;
     iov_t wiov[];
     iov_t riov[];

     ){
         ;
     }
     printf("jlm i2c client i2c_combined_writeread\n");
     logger_log(QCLOG_AMSS_QNP_QAL_I2C_CLIENT, __LINE__, QCLOG_ERROR, "jlm i2c_combined_writeread");

     msg.send_len = wlen;
     msg.recv_len = rlen;
     msg.stop = ;        // always stop condition
     msg.slave.addr = ;       // use current slave

     SETIOV(wiov+, &msg, sizeof(msg));
     SETIOV(wiov+, wbuff, wlen);
     SETIOV(riov+, &msg, sizeof(msg));
     SETIOV(riov+, rbuff, rlen);

     , , wiov, riov, &retval)!=) {
         ;
     }

     return retval;
 }

 i2c_combined_writeread

The i2c_client provides the APIs for the applications to call, in the function it will call

if(devctlv(fd, DCMD_I2C_SENDRECV, 2, 2, wiov, riov, &retval)!=0) {
        return -1;
    }

The cmd DCMD_I2C_SENDRECV  will be transfered to file i2c_drv.c 

in the function int i2c_drv_init(uint32_t enable_mask)   it will first configure the i2c hw according to the configuration by invoking the function I2CDEV_Init(DeviceID[i], &devs[idx].ahI2cDev); and then create maximum 12 thread to monitor the device cmd in the function int device_main(i2c_dev_t * dev)

check below:

/*
* intialize the connect functions and I/O functions tables to
* their defaults by calling iofunc_func_init().
*
* connect_funcs, and io_funcs variables are already declared.
*
*/
iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,
_RESMGR_IO_NFUNCS, &io_funcs);
/* over-ride the connect_funcs handler for open with our io_open,
* and over-ride the io_funcs handlers for read and write with our
* io_read and io_write handlers
*/
connect_funcs.open = io_open;
io_funcs.devctl = io_devctl;
io_funcs.acl = io_acl;

the function io_devctl will act accordingly.

 static int io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, iofunc_ocb_t  *ocb_t)
 {
     int status;

 #ifdef PUBLIC_FEATURE_RIM_ALL
     int n;
 #else
     uint32_t n;
 #endif

     uint32_t * busSpd;
     i2c_addr_t * addrdata;
     unsigned char *buf;
     void * inputPtr;

     i2c_recv_t* rheader;
     i2c_send_t* wheader;
     i2c_masterhdr_t* mheader;
     i2c_sendrecv_t * wrheader;
     i2c_ocb_t * ocb = (i2c_ocb_t *)ocb_t;

 #ifdef PUBLIC_FEATURE_RIM_ALL

     /*
      * Validate access permission:
      * Check the I2C device was opened with both read and write permission (i.e. O_RDWR).
      */
     if ((ctp == NULL) || (msg == NULL) || (ocb == NULL)) {
         return EINVAL;
     }

     if ((ocb->hdr.ioflag & _IO_FLAG_RD) != _IO_FLAG_RD) {
         return EPERM;
     }

     if ((ocb->hdr.ioflag & _IO_FLAG_WR) != _IO_FLAG_WR) {
         return EPERM;
     }

 #endif

     status = iofunc_devctl_default(ctp, msg, (iofunc_ocb_t *)ocb);
     if (status != _RESMGR_DEFAULT)
         return status;

     //Perform a task based on DCMD value
     switch (msg->i.dcmd) {
         case DCMD_I2C_SET_SLAVE_ADDR:
             if (msg->i.nbytes != sizeof(i2c_addr_t))
                 return EINVAL;

             addrdata = _DEVCTL_DATA(msg->i);
             status = i2clib_set_slave_addr(ocb->handle, addrdata->addr, addrdata->fmt);
             if(status != DAL_SUCCESS)
             {
                 return EINVAL;
             }
             msg->o.ret_val=;
             return _RESMGR_PTR(ctp, msg, sizeof(msg->o));
             break;

         case DCMD_I2C_SET_BUS_SPEED:
             if (msg->i.nbytes != sizeof(uint32_t))
                 return EINVAL;

             busSpd = _DEVCTL_DATA(msg->i);
             msg->o.ret_val=i2clib_set_bus_speed(ocb->handle, *busSpd, busSpd);
             return _RESMGR_PTR(ctp, msg, sizeof(msg->o));
             break;

         case DCMD_I2C_MASTER_SEND:
             inputPtr = _DEVCTL_DATA(msg->i);
             mheader = inputPtr;
             buf = inputPtr + (sizeof(i2c_masterhdr_t));

             //clears the mem buffer
             memset(&msg->o, , sizeof(msg->o));
             // num bytes actually written
             msg->o.ret_val = i2clib_write(ocb->handle, buf, mheader->len);
             msg->o.nbytes = ;
 #ifdef PUBLIC_FEATURE_RIM_ALL
             )
             {
                 return EIO;
             }
 #endif
             SETIOV(&ctp->iov[], msg, sizeof(msg->o));
             );

         case DCMD_I2C_SEND:
             inputPtr = _DEVCTL_DATA(msg->i);
             wheader = inputPtr;
             buf = inputPtr + (sizeof(i2c_send_t));

             )
                 return EINVAL;

             //clears the mem buffer
             memset(&msg->o, , sizeof(msg->o));
             // num bytes actually written
             msg->o.ret_val = i2clib_write(ocb->handle, buf, wheader->len);
             msg->o.nbytes = ;

 #ifdef PUBLIC_FEATURE_RIM_ALL
             )
             {
                 return EIO;
             }
 #endif
             SETIOV(&ctp->iov[], msg, sizeof(msg->o));
             );

         case DCMD_I2C_MASTER_RECV:
             inputPtr = _DEVCTL_DATA(msg->i);
             mheader = inputPtr;

             // num bytes actually written
             n = i2clib_read(ocb->handle, ocb->xbuf, mheader->len);
             memset(&msg->o, , sizeof(msg->o));
             msg->o.ret_val = n;
             )
             {
                 msg->o.nbytes = sizeof(*mheader)+n;
                 SETIOV(ctp->iov, &msg->o, sizeof(*msg)+sizeof(*mheader));
                 SETIOV(ctp->iov+, ocb->xbuf, n);
             }
             else
             {
 #ifdef PUBLIC_FEATURE_RIM_ALL
                 return EIO;
 #else
                 msg->o.nbytes = sizeof(*mheader);
                 SETIOV(ctp->iov, &msg->o, sizeof(*msg)+sizeof(*mheader));
                 SETIOV(ctp->iov+, ocb->xbuf, );
 #endif
             }
             );

         case DCMD_I2C_RECV:
             inputPtr = _DEVCTL_DATA(msg->i);
             rheader = inputPtr;

             )
                 return EINVAL;

             // num bytes actually written
             n = i2clib_read(ocb->handle, ocb->xbuf, rheader->len);
             memset(&msg->o, , sizeof(msg->o));
             msg->o.ret_val = n;
             )
             {
                 msg->o.nbytes = sizeof(*rheader)+n;
                 SETIOV(ctp->iov, &msg->o, sizeof(*msg)+sizeof(*rheader));
                 SETIOV(ctp->iov+, ocb->xbuf, n);
             }
             else
             {
 #ifdef PUBLIC_FEATURE_RIM_ALL
                 return EIO;
 #else
                 msg->o.nbytes = sizeof(*rheader);
                 SETIOV(ctp->iov, &msg->o, sizeof(*msg)+sizeof(*rheader));
                 SETIOV(ctp->iov+, ocb->xbuf, );
 #endif
             }
             );

         case DCMD_I2C_SENDRECV:
             inputPtr = _DEVCTL_DATA(msg->i);
             wrheader = inputPtr;
             printf("jlm i2c_drv DCMD_I2C_SENDRECV\n");
             logger_log(QCLOG_AMSS_CORE, QCLOG_AMSS_QNP_PLATFORM_I2C_DRV, QCLOG_ERROR,"jlm DCMD_I2C_SENDRECV %s\n");

             if(wrheader->slave.addr)   // specifying/changing slave?
             {
                 )
                     return EINVAL;
             }

             buf = inputPtr + (sizeof(i2c_sendrecv_t));

             n = i2clib_combined_writeread(ocb->handle, buf, wrheader->send_len, ocb->xbuf, wrheader->recv_len);
             memset(&msg->o, , sizeof(msg->o));

             msg->o.ret_val = n;
             )
             {
                 msg->o.nbytes = sizeof(*wrheader)+n;
                 SETIOV(ctp->iov, &msg->o, sizeof(msg->o)+sizeof(*wrheader));
                 SETIOV(ctp->iov+, ocb->xbuf, n);
             }
             else
             {
 #ifdef PUBLIC_FEATURE_RIM_ALL
                 return EIO;
 #else
                 msg->o.nbytes = sizeof(*wrheader);
                 SETIOV(ctp->iov, &msg->o, sizeof(msg->o)+sizeof(*wrheader));
                 SETIOV(ctp->iov+, ocb->xbuf, );
 #endif
             }
             );

         case DCMD_I2C_LOCK:
             memset(&msg->o, , sizeof(msg->o));
             msg->o.ret_val = i2clib_bus_lock(ocb->handle);
             return _RESMGR_PTR(ctp, msg, sizeof(msg->o));

         case DCMD_I2C_UNLOCK:
             memset(&msg->o, , sizeof(msg->o));
             msg->o.ret_val = i2clib_bus_unlock(ocb->handle);
             return _RESMGR_PTR(ctp, msg, sizeof(msg->o));

         case DCMD_I2C_DRIVER_INFO:
             if (msg->i.nbytes != sizeof(i2c_driver_info_t))
                 return EINVAL;
             break;

         default:
             return ENOSYS; // The device doesn't support the dcmd command.
     }
     return ENOSYS;
 }

 io_devctl

New info will coming soon....

  • How to test/verify i2c

currently we could use i2cdbgr to test/very the i2c . BUT I dont like this tool I am re-coding this test tool , I prefer to do like i2c-tools

qnx i2c 学习 二

i2ctool first version:

 %C : Application to perform i2c read / write /detect /dump /scan
 Author: gary
 Usage: i2ctool fd slaveAddr  read reg [count]
        i2ctool fd slaveAddr write reg val
        i2ctool detect dump $fd
        i2ctool detect
        i2ctool detect loop $fd
 where fd is of form "/dev/i2cX".

 The i2ctool uses -bit addressing, -bit data to read or write from
 /dev/i2cX (fd) using i2c_client.h using default frequency.

 Examples:

 //read
 . i2ctool $fd $slaveAddr read  $reg [$val]
 //write
 . i2ctool $fd $slaveAddr write $reg  $val
 //dump all the registers for device $fd and slaveaddr
 . i2ctool detect dump $fd
 //list all the i2c device that currently created
 . i2ctool detect
 //scan for the i2c device if it has the slaves or not
 . i2ctool detect loop $fd     

 i2ctool usage
 /* =========================================================================

 @file    i2ctool.c
 @brief   Application, R/W i2c devices using 8-bit address/data, default freq.

 Copyright (c) 2013 by QUALCOMM Technologies Incorporated.  All Rights Reserved.

 $Header$

 ============================================================================ */

 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/neutrino.h>
 #include <hw/inout.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <amss/i2c_client.h>

 #define IDX_DEV_FD     1
 #define IDX_SLAVE_ADDR 2
 #define IDX_OP         3
 #define IDX_REG        4
 #define IDX_VAL        5  /* write: value to write, read: optional no. of consecutive registers to read */

 #define IDX_DETECT 1
 #define IDX_DETECT_SUBCMD 2
 #define IDX_DETECT_FD 3
 //
 // Command line:
 // 1. i2ctool $fd $slaveAddr read  $reg [$val]  6
 // 2. i2ctool $fd $slaveAddr write $reg  $val   6
 // 3. i2ctool detect dump $fd   dump all the registers for device $fd and slaveaddr 4
 // 4. i2ctool detect    list all the i2c device that currently created  2
 // 5. i2ctool detect loop $fd     scan for the i2c device if it has the slaves or not 3

 //detect
 #define I2C_MAX_COUNT 12
 #define INT2CHAR(x) (x - '0')
 #define PATH_LEN 10
 #define I2C_ADDR_FIRST 0x01
 #define I2C_ADDR_LAST 0xff
 #define I2C_ADDR_MAX 0xff
 int main(int argc, char *argv[])
 {
     ;
     int error = EXIT_SUCCESS;

      != argc) && ( != argc) && ( != argc))
     {
         fprintf(stderr, ]);
         error = EXIT_FAILURE;
     }
      != argc))
     {
         fprintf(stderr, ]);
         error = EXIT_FAILURE;
     }
     else if(!strcmp(argv[IDX_DETECT], "detect"))
     {
         fprintf(stderr, "detect\n");
         error = EXIT_FAILURE;
          == argc)
         {
             char i2c_path[PATH_LEN];
             char *i2c_dev_path = "/dev/i2c%d";
             ; i < I2C_MAX_COUNT; i++)
             {
                 memset(i2c_path, , sizeof(char)*PATH_LEN);
                 snprintf(i2c_path, PATH_LEN, i2c_dev_path, i);

                  == (fd = i2c_open(i2c_path)))
                 {
                     error = EXIT_FAILURE;
                 }
                 else
                 {
                     i2c_close(fd);
                     fprintf(stderr," %s\n",i2c_path);
                 }
             }
         }
         //
          == (fd = i2c_open(argv[IDX_DETECT_FD])))
         {
             fprintf(stderr, ], argv[IDX_DETECT_FD]);
             error = EXIT_FAILURE;
         }
          == argc)
         {
             if(!strcmp(argv[IDX_DETECT_SUBCMD], "loop"))
             {
                 fprintf(stderr, "ready to scan\n");
                 fprintf(stderr,"     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
                 ; i < ; i += )
                 {
                     fprintf(stderr,"%02x: ", i);
                     ; j < ; j++)
                     {
                         if( ((i+j) < I2C_ADDR_FIRST) || ((i+j) > I2C_ADDR_LAST))
                         {
                             fprintf(stderr,"   ");
                             continue ;
                         }
                         //slave address is i+j
                          != i2c_set_slave_addr(fd, i+j, ))
                         {
                             fprintf(stderr,"UU ");
                             continue;
                         }
                         else
                         {
                             fprintf(stderr,"-- ");
                         }

                     }
                     fprintf(stderr,"\n");

                 }

             }
             else if (!strcmp(argv[IDX_DETECT_SUBCMD], "dump"))
             {
                 unsigned ;
                 //int  count = 0xff;
                 fprintf(stderr, "ready to dump\n");
                 fprintf(stderr,"     0   1   2   3   4   5   6   7   8   9   a   b  c   d   e   f\n");
                 ;
                 ; i < I2C_ADDR_MAX; i+=)
                 {
                     fprintf(stderr,"0x%02x: ", i);
                      ; j < ; j++)
                     {
                         reg = i+j;
                         if(reg < I2C_ADDR_FIRST || reg > I2C_ADDR_LAST)
                         {
                             fprintf(stderr,"   ");
                             continue;
                         }
                          != i2c_combined_writeread(fd, &reg, , &data, ))
                         {
                             if (isgraph(data))
                             {
                                 fprintf(stderr, "%02X ", data);
                             }
                             else
                             {
                                 fprintf(stderr, "%02X ", data);
                             }
                         }
                         else
                         {
                             fprintf(stderr,"-- ");
                         }

                     }
                     fprintf(stderr,"\n");

                 }

             }
             else
             {
                 // this can't happen
                 fprintf(stderr, ], argv[IDX_OP]);
                 error = EXIT_FAILURE;
             }

             i2c_close(fd);                           

         }
     }
      == (fd = i2c_open(argv[IDX_DEV_FD])))
     {
         fprintf(stderr, ], argv[IDX_DEV_FD]);
         error = EXIT_FAILURE;
     }
     //read write
     else
     {
         //#if 1
         );
         );

          == i2c_set_slave_addr(fd, slaveAddr, ))
         {
             fprintf(stderr, ]);
             error = EXIT_FAILURE;
         }

         if (EXIT_SUCCESS == error)
         {
             if (!strcmp(argv[IDX_OP], "write"))
             {
                 unsigned ];
                 writedata[] = reg;
                 writedata[] = strtol(argv[IDX_VAL], NULL, );
                 error =  i2c_write(fd, writedata, );
                 ) || /*wrote zero bytes...*/
                         error == -  /*Driver error*/)
                 {
                     fprintf(stderr, "%s: i2c_write(%s = %d, data[2] = 0x%02x,0x%02x, 2) failed\n",
                             argv[], argv[IDX_DEV_FD], fd, writedata[], writedata[]);
                     error = EXIT_FAILURE;
                 }
                 else
                 {
                     fprintf(stderr, ], writedata[]);
                 }
             }
             else if (!strcmp(argv[IDX_OP], "read"))
             {
                 unsigned ;
                 ;
                 int  i;

                  == argc)
                 {
                     count = strtol(argv[IDX_VAL], NULL, );
                 }

                 ; i<count; i++, reg++)
                 {
                      == i2c_combined_writeread(fd, &reg, , &data, ))
                     {
                         fprintf(stderr, "%s: i2c_combined_writeread(%s = %d, slaveAddr = 0x%02x, 1, &data, 1) failed\n",
                                 argv[], argv[IDX_DEV_FD], fd, slaveAddr);
                         error = EXIT_FAILURE;
                     }
                     else
                     {
                         if (isgraph(data))
                         {
                             fprintf(stderr, "0x%02x -> 0x%02X ('%c')\n", reg, data, data);
                         }
                         else
                         {
                             fprintf(stderr, "0x%02x -> 0x%02X\n", reg, data);
                         }
                     }
                 }
             }
             else
             {
                 // this can't happen
                 fprintf(stderr, ], argv[IDX_OP]);
                 error = EXIT_FAILURE;
             }
         }

         i2c_close(fd);
     }
     return error;
 }

 i2c tool

it can work like i2ctool that we farmiliar with, in qnx, it is very strange that all the input parameters need a condition to handle otherwise it will cor dump, I spend some time on why it will core dump, but failed, this could be a further task.

  • How to create i2c_client

i2c_client Provides APIs for user applications to communicate to I2C device nodes(/dev/i2c*).

 /**===========================================================================

   @file i2c_client.c

   @copyright
             Copyright (c) 2010-2013 QUALCOMM Technologies Incorporated.
             All rights reserved. Licensed Material - Restricted Use.
             Qualcomm Confidential and Proprietary.

 ===========================================================================*/

 /*===========================================================================

                            EDIT HISTORY FOR FILE

 $Header$

 when       who      what, where, why
 --------   ---      ----------------------------------------------------------
 02/01/13   jsanpedr Switched slog to logger_log macro
 09/08/12   rohitn   Close fd on exec to reduce IO_DUP messages to QNX memmgr
 ===========================================================================*/

 /*=========================================================================
       Include Files
 ==========================================================================*/
 #include <stdlib.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include "i2c_client.h"
 #include "logger_utils.h"

 #define LOG(sev, format, ...) \
         logger_log(QCLOG_AMSS_QNP_QAL_I2C_CLIENT, , sev, format, ##__VA_ARGS__)
 #define LOGE(format, ...) LOG(QCLOG_ERROR, format, ##__VA_ARGS__)

 /*=========================================================================
       Functions
 ==========================================================================*/
 int i2c_open(void* devname){
     int fd;
     fd = open (devname, O_RDWR|O_CLOEXEC);
     ) {
         LOGE("Can't open device %s for RDONLY, errno %d", (char*)devname, errno);
     }
     return fd;
 }

 void i2c_close(int fd){
    ) {
       close(fd);
    }
 }

 int i2c_set_slave_addr(int fd, uint32_t addr, uint32_t fmt){
     ;
     i2c_addr_t msg;

     msg.addr = addr;
     msg.fmt = fmt;

     ){
         ;
     }

     ){
         ;
     }

     return retval;
 }

 int i2c_set_bus_speed(int fd, uint32_t speed, uint32_t *ospeed){
     ;
     uint32_t msg = speed;

     ){
         ;
     }

     ){
         ;
     }

     return retval;
 }

 int i2c_bus_lock(int fd){
     ;

     ){
         ;
     }

     , &retval)!=) {
         ;
     }

     return retval;
 }

 int i2c_bus_unlock(int fd){

     ;

     ){
         ;
     }

     , &retval)!=){
         ;
     }

     return retval;

 }

 int i2c_driver_info(int fd, i2c_driver_info_t *info){

     ){
         ;
     }

     ){
         ;
     }

     ;
 }

 int i2c_read(int fd, void *buf, uint32_t len) {
    ;
     i2c_masterhdr_t  msg;
     iov_t wiov[];
     iov_t riov[];

     ){
         logger_log(QCLOG_AMSS_QNP_QAL_I2C_CLIENT, __LINE__, QCLOG_ERROR, "Device not yet opened");
         ;
     }

     msg.len = len;
     msg.stop = ;  // always generate stop per bus transaction

     SETIOV(wiov+, &msg, sizeof(i2c_masterhdr_t));
     SETIOV(riov+, &msg, sizeof(i2c_masterhdr_t));
     SETIOV(riov+, buf, len);
     , , wiov, riov , &retval)!=){
         ;
     }

     return retval;
 }

 int i2c_write(int fd, void *buf, uint32_t len){
    ;
     iov_t iov[];
     i2c_masterhdr_t msg;

     ){
         logger_log(QCLOG_AMSS_QNP_QAL_I2C_CLIENT, __LINE__, QCLOG_ERROR, "Device not yet opened");
         ;
     }

     msg.len = len;
     msg.stop = ;

     SETIOV(iov+, &msg, sizeof(i2c_masterhdr_t));
     SETIOV(iov+, buf, len);
     , , iov, NULL , &retval)!=) {
         ;
     }

     return retval;
 }

 int i2c_combined_writeread(int fd, void * wbuff, uint32_t wlen, void* rbuff, uint32_t rlen )
 {
    ;
     i2c_sendrecv_t msg;
     iov_t wiov[];
     iov_t riov[];

     ){
         ;
     }

     msg.send_len = wlen;
     msg.recv_len = rlen;
     msg.stop = ;        // always stop condition
     msg.slave.addr = ;       // use current slave

     SETIOV(wiov+, &msg, sizeof(msg));
     SETIOV(wiov+, wbuff, wlen);
     SETIOV(riov+, &msg, sizeof(msg));
     SETIOV(riov+, rbuff, rlen);

     , , wiov, riov, &retval)!=) {
         ;
     }

     return retval;
 }

 i2c_client

for example: i2cdbgr will use these apis

 /* =========================================================================

 @file    i2cdbgr.c
 @brief   Application, R/W i2c devices using 8-bit address/data, default freq.

 Copyright (c) 2013 by QUALCOMM Technologies Incorporated.  All Rights Reserved.

 $Header$

 ============================================================================ */

 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/neutrino.h>
 #include <hw/inout.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <amss/i2c_client.h>

 #define IDX_DEV_FD     1
 #define IDX_SLAVE_ADDR 2
 #define IDX_OP         3
 #define IDX_REG        4
 #define IDX_VAL        5  /* write: value to write, read: optional no. of consecutive registers to read */

 //
 // Command line:
 // 1. i2cdbgr $fd $slaveAddr read  $reg [$val]
 // 2. i2cdbgr $fd $slaveAddr write $reg  $val
 //
 int main(int argc, char *argv[])
 {
     ;
     int error = EXIT_SUCCESS;

      != argc) && ( != argc) )
     {
         fprintf(stderr, ]);
         error = EXIT_FAILURE;
     }
      != argc))
     {
         fprintf(stderr, ]);
         error = EXIT_FAILURE;
     }
      == (fd = i2c_open(argv[IDX_DEV_FD])))
     {
         fprintf(stderr, ], argv[IDX_DEV_FD]);
         error = EXIT_FAILURE;
     }
     else
     {
         );
         );

          == i2c_set_slave_addr(fd, slaveAddr, ))
         {
             fprintf(stderr, ]);
             error = EXIT_FAILURE;
         }

         if (EXIT_SUCCESS == error)
         {
             if (!strcmp(argv[IDX_OP], "write"))
             {
                 unsigned ];
                 writedata[] = reg;
                 writedata[] = strtol(argv[IDX_VAL], NULL, );
                 error =  i2c_write(fd, writedata, );
                 ) || /*wrote zero bytes...*/
                         error == -  /*Driver error*/)
                 {
                     fprintf(stderr, "%s: i2c_write(%s = %d, data[2] = 0x%02x,0x%02x, 2) failed\n",
                             argv[], argv[IDX_DEV_FD], fd, writedata[], writedata[]);
                     error = EXIT_FAILURE;
                 }
                 else
                 {
                     fprintf(stderr, ], writedata[]);
                 }
             }
             else if (!strcmp(argv[IDX_OP], "read"))
             {
                 unsigned ;
                 ;
                 int  i;

                  == argc)
                 {
                     count = strtol(argv[IDX_VAL], NULL, );
                 }

                 ; i<count; i++, reg++)
                 {
                      == i2c_combined_writeread(fd, &reg, , &data, ))
                     {
                         fprintf(stderr, "%s: i2c_combined_writeread(%s = %d, slaveAddr = 0x%02x, 1, &data, 1) failed\n",
                                 argv[], argv[IDX_DEV_FD], fd, slaveAddr);
                         error = EXIT_FAILURE;
                     }
                     else
                     {
                         if (isgraph(data))
                         {
                             fprintf(stderr, "0x%02x -> 0x%02X ('%c')\n", reg, data, data);
                         }
                         else
                         {
                             fprintf(stderr, "0x%02x -> 0x%02X\n", reg, data);
                         }
                     }
                 }
             }
             else
             {
                 // this can't happen
                 fprintf(stderr, ], argv[IDX_OP]);
                 error = EXIT_FAILURE;
             }
         }

         i2c_close(fd);
     }
     return error;
 }

 i2cdbgr

# === Rules for type i2c_service_t ==========
allow i2c_service_t self:ability {
    nonroot
    setuid:I2C_SERVICE_UID
    setgid:I2C_SERVICE_GID,QCORE_GID
    #TODO: Interrupt is handled/attached during every write/read. Hence ability is not dropped
    interruptevent:blsp2_qup_irq_0,blsp1_qup_irq_5,blsp2_qup_irq_1
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP1_BLSP.QUP5_DD_4K
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP2_BLSP.QUP0_DD_4K
    mem_phys:PERIPH_SS.PERIPH_SS_BLSP2_BLSP.QUP1_DD_4K
    mem_phys:__DMA_POOL_START__-__DMA_POOL_END__
    iofunc/exec
    io:0
    spawn
    public_channel
    xthread_threadctl
    pathspace
    channel_connect
    mem_peer
    mem_special
    keydata
    rlimit
};

allow i2c_service_t self:ability {
    nonroot
    unlock
    map_fixed
    prot_exec
    prot_write_and_exec
};

allow_attach i2c_service_t {

/dev/i2c*
    /dev/i2c_service
    /dev/npa
    /dev/pmem/i2c_service
};

allow i2c_service_t {
    qcore_t
    slogger2_t
    smmu_service_t
    bmetrics_t
}:channel connect;