This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/PROCESSOR-SDK-AM335X: Ioctl message error

Part Number: PROCESSOR-SDK-AM335X

Tool/software: Linux

We are updating from an ARM embedded Ubuntu 14.04 (Kernel 3.14) to ARM embedded Ubuntu 16.04. On the first platform we are accessing a chip using SPIDEV without a problem. On the Ubuntu 16.04 (Kernel 4.9.59) platform I am getting an EINVAL error following a ioctl SPI_IOC_MESSAGE. The kernel is from TI's SDK 4.02.00.09.

The code calling ioctl is as follows:
 SpiComm_t::Transfer(int i4Length) {   
   int ret = -1;

   m_tr.len = i4Length;

   ret = ioctl(m_fd, SPI_IOC_MESSAGE(1), &m_tr); 
   if (ret )   {
     printf("SPI IOCTL error %s\n", strerror(errno));   }

  return ret; 
}

SpiComm_t::SpiComm_t( uint32_t w4Bus,
                      uint32_t w4ChipSelect ) :
    m_fd(-1),
    m_b0IsInitialized(false),
    m_w4Bus(w4Bus),
    m_w4ChipSelect(w4ChipSelect)
{

  m_tr.tx_buf = (unsigned long)m_c1BufTx;
  m_tr.rx_buf = (unsigned long)m_c1BufRx;

  m_tr.delay_usecs   = SX_1276_SPI_DELAY;
  m_tr.speed_hz      = SX_1276_SPI_SPEED;
  m_tr.bits_per_word = SX_1276_SPI_BITS;
}

m_tr and m_c1BufTx are defined as:
  spi_ioc_transfer m_tr;

  uint8_t m_c1BufTx[0xff+1];
  uint8_t m_c1BufRx[0xff+1];



The code that calls the transfer function is:

  // Reset memory (Optional...  Helps diagnose failures to read.)
  memset(m_c1BufTx, 0xFF, sizeof(m_c1BufTx));

  // Put address
  m_c1BufTx[0] =  address;

  // Reset memory (optional...)
  memset(m_c1BufRx, 0xFF, sizeof(m_c1BufRx));

  // Invoke ioctl transaction
  int result = Transfer(size+1);

We are using Kernel 4.9.59 from TI SDK 4.0. I have traced the EINVAL to the spidev.c driver but cannot make sense of why I am getting the error.

spidev.c code is:

tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0)
    return ERR_PTR(-EINVAL);
*n_ioc = tmp / sizeof(struct spi_ioc_transfer);
if (*n_ioc == 0)
    return NULL;

Any help would be greatly appreciated.
  • Some progress on the problem above. Zeroing out the spi_ioc_transfer no longer produces an EINVAL error, instead I am getting an EBUSY error. I am guessing that either cs_change or pad in the structure was causing the EINVAL error.

    Still need to investigate more as I should not be getting the EBUSY error on every SPI_IOC_MESSAGE.

  • The EBUSY is not an error from the call.  The SPI_IOC_MESSAGE ioctl call returns the length of the message returned. So in this case it is not an indication of an error. The EBUSY I am seeing is from a previous call. The corrected code is now:

      errno = 0;
      ret = ioctl(m_fd, SPI_IOC_MESSAGE(1), &m_tr);
      // NOTE this ioctl returns the lenght of the answer not an indication of setting errno
      // Check errno instead
      if (errno != 0)
      {
         printf("SPI IOCTL ret(%d)error(%d) %s\n", ret, errno, strerror(errno));
      }
    

  • Thank you for sharing the solution.