static int ft80x_ioctl()

in drivers/lcd/ft80x.c [630:1147]


static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct inode *inode;
  FAR struct ft80x_dev_s *priv;
  int ret;

  inode = filep->f_inode;
  DEBUGASSERT(inode->i_private != NULL);
  priv  = inode->i_private;

  lcdinfo("cmd: %d arg: %lu\n", cmd, arg);

  /* Get exclusive access to the device structures */

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      return ret;
    }

  /* Handle built-in ioctl commands */

  switch (cmd)
    {
      /* FT80X_IOC_CREATEDL:
       *   Description:  Write a display list to the FT80x display list
       *                 memory
       *   Description:  Write a display list to the FT80x display list
       *                 memory starting at offset zero.  This may or may
       *                 not be the entire display list.  Display lists may
       *                 be created incrementally, starting with
       *                 FT80X_IOC_CREATEDL and finishing the display list
       *                 using FT80XIO_APPENDDL
       *   Argument:     A reference to a display list structure instance.
       *                 See struct ft80x_displaylist_s.
       *   Returns:      None
       */

      case FT80X_IOC_CREATEDL:

        /* Set the file position to zero and fall through to "append" the new
         * display list data at offset 0.
         */

        filep->f_pos = 0;

        /* FALLTHROUGH */

      /* FT80X_IOC_APPENDDL:
       *   Description:  Write additional display list entries to the FT80x
       *                 display list memory at the current display list
       *                 offset.  This IOCTL command permits display lists
       *                 to be completed incrementally, starting with
       *                 FT80X_IOC_CREATEDL and finishing the display list
       *                 using FT80XIO_APPENDDL.
       *   Argument:     A reference to a display list structure instance.
       *                 See struct ft80x_displaylist_s.
       *   Returns:      None
       */

      case FT80X_IOC_APPENDDL:
        {
          FAR struct ft80x_displaylist_s *dl =
            (FAR struct ft80x_displaylist_s *)((uintptr_t)arg);

          if (dl == NULL || ((uintptr_t)&dl->cmd & 3) != 0 ||
              (dl->dlsize & 3) != 0 ||
              dl->dlsize + filep->f_pos > FT80X_RAM_DL_SIZE)
            {
              ret = -EINVAL;
            }
          else
            {
              /* Check if there is a display list.  It might be useful for
               * the application to issue FT80X_IOC_CREATEDL with no data in
               * order to initialize the display list, then form all of the
               * list entries with FT80X_IOC_APPENDDL.
               */

              if (dl->dlsize > 0)
                {
                  /* This IOCTL command simply copies the display list
                   * provided into the FT80x display list memory.
                   */

                  ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos,
                                     &dl->cmd, dl->dlsize);
                  filep->f_pos += dl->dlsize;
                }

              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_GETRAMDL:
       *   Description:  Read a 32-bit value from the display list.
       *   Argument:     A reference to an instance of struct ft80x_relmem_s.
       *   Returns:      The 32-bit value read from the display list.
       */

      case FT80X_IOC_GETRAMDL:
        {
          FAR struct ft80x_relmem_s *ramdl =
            (FAR struct ft80x_relmem_s *)((uintptr_t)arg);

          if (ramdl == NULL || ((uintptr_t)ramdl->offset & 3) != 0 ||
              ramdl->offset >= FT80X_RAM_DL_SIZE)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_read_memory(priv, FT80X_RAM_DL + ramdl->offset,
                                ramdl->value, ramdl->nbytes);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTRAMG
       *   Description:  Write byte data to FT80x graphics memory (RAM_G)
       *   Argument:     A reference to an instance of struct ft80x_relmem_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTRAMG:
        {
          FAR struct ft80x_relmem_s *ramg =
            (FAR struct ft80x_relmem_s *)((uintptr_t)arg);

          if (ramg == NULL ||
             (ramg->offset + ramg->nbytes) >= FT80X_RAM_G_SIZE)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_memory(priv, FT80X_RAM_G + ramg->offset,
                                 ramg->value, ramg->nbytes);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTRAMCMD
       *   Description:  Write 32-bit aligned data to FT80x FIFO (RAM_CMD)
       *   Argument:     A reference to an instance of struct ft80x_relmem_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTRAMCMD:
        {
          FAR struct ft80x_relmem_s *ramcmd =
            (FAR struct ft80x_relmem_s *)((uintptr_t)arg);

          if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_memory(priv, FT80X_RAM_CMD + ramcmd->offset,
                                ramcmd->value, ramcmd->nbytes);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_GETREG8:
       *   Description:  Read an 8-bit register value from the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      The 8-bit value read from the register.
       */

      case FT80X_IOC_GETREG8:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              reg->value.u8 = ft80x_read_byte(priv, reg->addr);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_GETREG16:
       *   Description:  Read a 16-bit register value from the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      The 16-bit value read from the register.
       */

      case FT80X_IOC_GETREG16:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              reg->value.u16 = ft80x_read_hword(priv, reg->addr);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_GETREG32:
       *   Description:  Read a 32-bit register value from the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      The 32-bit value read from the register.
       */

      case FT80X_IOC_GETREG32:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              reg->value.u32 = ft80x_read_word(priv, reg->addr);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_GETREGS:
       *   Description:  Read multiple 32-bit register values from the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_registers_s.
       *   Returns:      The 32-bit values read from the consecutive
       *                 registers .
       */

      case FT80X_IOC_GETREGS:
        {
          FAR struct ft80x_registers_s *regs =
            (FAR struct ft80x_registers_s *)((uintptr_t)arg);

          if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_read_memory(priv, regs->addr, regs->value,
                                (size_t)regs->nregs << 2);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTREG8:
       *   Description:  Write an 8-bit register value to the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTREG8:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_byte(priv, reg->addr, reg->value.u8);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTREG16:
       *   Description:  Write a 16-bit  register value to the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTREG16:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_hword(priv, reg->addr, reg->value.u16);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTREG32:
       *   Description:  Write a 32-bit  register value to the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_register_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTREG32:
        {
          FAR struct ft80x_register_s *reg =
            (FAR struct ft80x_register_s *)((uintptr_t)arg);

          if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_word(priv, reg->addr, reg->value.u32);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_PUTREGS:
       *   Description:  Write multiple 32-bit register values to the FT80x.
       *   Argument:     A reference to an instance of struct
       *                 ft80x_registers_s.
       *   Returns:      None.
       */

      case FT80X_IOC_PUTREGS:
        {
          FAR struct ft80x_registers_s *regs =
            (FAR struct ft80x_registers_s *)((uintptr_t)arg);

          if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0)
            {
              ret = -EINVAL;
            }
          else
            {
              ft80x_write_memory(priv, regs->addr, regs->value,
                                 (size_t)regs->nregs << 2);
              ret = OK;
            }
        }
        break;

      /* FT80X_IOC_EVENTNOTIFY:
       *   Description:  Setup to receive a signal when an event occurs.
       *   Argument:     A reference to an instance of struct ft80x_notify_s.
       *   Returns:      None
       */

      case FT80X_IOC_EVENTNOTIFY:
        {
          FAR struct ft80x_notify_s *notify =
            (FAR struct ft80x_notify_s *)((uintptr_t)arg);

          if (notify == NULL || notify->pid < 0 ||
              (unsigned int)notify->id >= FT80X_INT_NEVENTS)
            {
              ret = -EINVAL;
            }
          else
            {
              FAR struct ft80x_eventinfo_s *info = &priv->notify[notify->id];
              uint32_t regval;

              /* Are we enabling or disabling */

              if (notify->enable)
                {
                  /* Make sure that arguments are valid for the enable */

                  if (notify->pid == 0)
                    {
                      ret = -EINVAL;
                    }
                  else
                    {
                      /* Setup the new notification information */

                      info->event  = notify->event;
                      info->pid    = notify->pid;
                      info->enable = true;

                      /* Enable interrupts associated with the event */

                      regval  = ft80x_read_word(priv, FT80X_REG_INT_MASK);
                      regval |= (1 << notify->id);
                      ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);
                      ret = OK;
                    }
                }
              else
                {
                  /* Disable the notification */

                  info->pid    = 0;
                  info->enable = false;

                  /* Disable interrupts associated with the event */

                  regval  = ft80x_read_word(priv, FT80X_REG_INT_MASK);
                  regval &= ~(1 << notify->id);
                  ft80x_write_word(priv, FT80X_REG_INT_MASK, regval);

                  /* Cancel any pending notification */

                  nxsig_cancel_notification(&info->work);
                  ret = OK;
                }
            }
        }
        break;

       /* FT80X_IOC_FADE:
        *   Description:  Change the backlight intensity with a controllable
        *                 fade.
        *   Argument:     A reference to an instance of struct ft80x_fade_s.
        *   Returns:      None.
        */

       case FT80X_IOC_FADE:
        {
          FAR const struct ft80x_fade_s *fade =
            (FAR const struct ft80x_fade_s *)((uintptr_t)arg);

          if (fade == NULL || fade->duty > 100 ||
              fade->delay < MIN_FADE_DELAY || fade->delay > MAX_FADE_DELAY)
            {
              ret = -EINVAL;
            }
          else
            {
              ret = ft80x_fade(priv, fade);
            }
        }
        break;

       /* FT80X_IOC_AUDIO:
        *   Description:  Enable/disable an external audio amplifier.
        *   Argument:     0=disable; 1=enable.
        *   Returns:      None.
        */

       case FT80X_IOC_AUDIO:
        {
#if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN)
          /* Amplifier is controlled by an MCU GPIO pin */

          DEBUGASSERT(priv->lower->attach != NULL &&
                      priv->lower->audio != NULL);
          DEBUGASSERT(arg == 0 || arg == 1);

          priv->lower->audio(priv->lower, (arg != 0));
          ret = OK;

#elif defined(CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN)
          /* Amplifier is controlled by an FT80x GPIO pin */

          uint8_t regval8;

          DEBUGASSERT(arg == 0 || arg == 1);

          regval8  = ft80x_read_byte(priv, FT80X_REG_GPIO);

          /* Active low logic assumed */

          if (arg == 0)
            {
              regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
            }
          else
            {
              regval8 &= ~(1 << CONFIG_LCD_FT80X_AUDIO_GPIO);
            }

          ft80x_write_byte(priv, FT80X_REG_GPIO, regval8);
          ret = OK;

#else
          /* Amplifier is not controllable. */

          DEBUGASSERT(arg == 0 || arg == 1);
          return OK;
#endif
        }
        break;

      /* Unrecognized IOCTL command */

      default:
        lcderr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg);
        ret = -ENOTTY;
        break;
    }

  nxmutex_unlock(&priv->lock);
  return ret;
}