qnx i2c 学习 二
阅读原文时间:2020年10月08日阅读:1

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

qnx i2c structure  --written by jlm

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

  • 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;
}

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

根据上面的表格,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

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

  • 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

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
#include
#include
#include
#include
#include
#include
#include
#include
#include

#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
#include
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include
#include

#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;