/******************************************************************************
*                                                                             *
* License Agreement                                                           *
*                                                                             *
* Copyright (c) 2006 Altera Corporation, San Jose, California, USA.           *
* All rights reserved.                                                        *
*                                                                             *
* Permission is hereby granted, free of charge, to any person obtaining a     *
* copy of this software and associated documentation files (the "Software"),  *
* to deal in the Software without restriction, including without limitation   *
* the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
* and/or sell copies of the Software, and to permit persons to whom the       *
* Software is furnished to do so, subject to the following conditions:        *
*                                                                             *
* The above copyright notice and this permission notice shall be included in  *
* all copies or substantial portions of the Software.                         *
*                                                                             *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
* DEALINGS IN THE SOFTWARE.                                                   *
*                                                                             *
* This agreement shall be governed in all respects by the laws of the State   *
* of California and by the laws of the United States of America.              *
*                                                                             *
******************************************************************************/

#include <fcntl.h>
#include <string.h>

#include "sys/alt_irq.h"
#include "sys/ioctl.h"
#include "sys/alt_errno.h"

#include "altera_avalon_uart_regs.h"
#include "altera_avalon_uart.h"


#if !defined(ALT_USE_SMALL_DRIVERS) && !defined(ALTERA_AVALON_UART_SMALL)

/* ----------------------------------------------------------- */
/* ------------------------- FAST DRIVER --------------------- */
/* ----------------------------------------------------------- */

/*
 * To reduce the code footprint of this driver, the ioctl() function is not
 * included by default. If you wish to use the ioctl features provided 
 * below, you can do so by adding the option : -DALTERA_AVALON_UART_USE_IOCTL
 * to CPPFLAGS in the Makefile (or through the Eclipse IDE).
 */

#ifdef ALTERA_AVALON_UART_USE_IOCTL

/*
 * altera_avalon_uart_ioctl() is called by the system ioctl() function to handle
 * ioctl requests for the UART. The only ioctl requests supported are TIOCMGET
 * and TIOCMSET.
 *
 * TIOCMGET returns a termios structure that describes the current device
 * configuration.
 *
 * TIOCMSET sets the device (if possible) to match the requested configuration.
 * The requested configuration is described using a termios structure passed
 * through the input argument "arg".
 */

static int altera_avalon_uart_tiocmget(altera_avalon_uart_state* sp,
  struct termios* term);
static int altera_avalon_uart_tiocmset(altera_avalon_uart_state* sp,
  struct termios* term);

int 
altera_avalon_uart_ioctl(altera_avalon_uart_state* sp, int req, void* arg)
{
  int rc = -ENOTTY;

  switch (req)
  {
  case TIOCMGET:
    rc = altera_avalon_uart_tiocmget(sp, (struct termios*) arg);
    break;
  case TIOCMSET:
    rc = altera_avalon_uart_tiocmset(sp, (struct termios*) arg);
    break;
  default:
    break;
  }
  return rc;
}

/*
 * altera_avalon_uart_tiocmget() is used by altera_avalon_uart_ioctl() to fill
 * in the input termios structure with the current device configuration. 
 *
 * See termios.h for further details on the contents of the termios structure.
 */

static int 
altera_avalon_uart_tiocmget(altera_avalon_uart_state* sp,
  struct termios* term)
{
  memcpy (term, &sp->termios, sizeof (struct termios));
  return 0;
}

/*
 * altera_avalon_uart_tiocmset() is used by altera_avalon_uart_ioctl() to 
 * configure the device according to the settings in the input termios 
 * structure. In practice the only configuration that can be changed is the
 * baud rate, and then only if the hardware is configured to have a writable
 * baud register.
 */

static int 
altera_avalon_uart_tiocmset(altera_avalon_uart_state* sp,
  struct termios* term)
{
  speed_t speed;

  speed = sp->termios.c_ispeed;

  /* Update the settings if the hardware supports it */

  if (!(sp->flags & ALT_AVALON_UART_FB))
  {
    sp->termios.c_ispeed = sp->termios.c_ospeed = term->c_ispeed;
  }
  /* 
   * If the request was for an unsupported setting, return an error.
   */

  if (memcmp(term, &sp->termios, sizeof (struct termios)))
  {
    sp->termios.c_ispeed = sp->termios.c_ospeed = speed;
    return -EIO;
  }

  /*
   * Otherwise, update the hardware.
   */
  
  IOWR_ALTERA_AVALON_UART_DIVISOR(sp->base, 
    ((sp->freq/sp->termios.c_ispeed) - 1));

  return 0;
}

#endif /* ALTERA_AVALON_UART_USE_IOCTL */

#endif /* fast driver */
