/*
 *  linux/drivers/char/at91_serial.c
 *
 *  Driver for Atmel AT91RM9200 Serial ports
 *
 *  Copyright (c) Rick Bronson
 *
 *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
 *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>#include <asm/arch/AT91RM9200_USART.h>
#include <asm/arch/pio.h>/*
 * This is a temporary structure for registering these
 * functions; it is intended to be discarded after boot.
 */
struct uart_port;
struct uart_info;
struct at91_port_fns {
 void (*set_mctrl)(struct uart_port *, u_int);
 u_int (*get_mctrl)(struct uart_port *);
 void (*enable_ms)(struct uart_port *);
 void (*pm)(struct uart_port *, u_int, u_int);
 int (*set_wake)(struct uart_port *, u_int);
 int (*open)(struct uart_port *, struct uart_info *);
 void (*close)(struct uart_port *, struct uart_info *);
};#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif#include <linux/serial_core.h>#define SERIAL_AT91_MAJOR TTY_MAJOR
#define CALLOUT_AT91_MAJOR TTYAUX_MAJOR
#define MINOR_START  64#define AT91C_VA_BASE_DBGU ((unsigned long) 
&(AT91_SYS->DBGU_CR))
#define AT91_ISR_PASS_LIMIT 256#define UART_PUT_CR(port,v) 
((AT91PS_USART)(port)->membase)->US_CR = v
#define UART_GET_MR(port) ((AT91PS_USART)(port)->membase)->US_MR
#define UART_PUT_MR(port,v) ((AT91PS_USART)(port)->membase)->US_MR = v
#define UART_PUT_IER(port,v) ((AT91PS_USART)(port)->membase)->US_IER = v
#define UART_PUT_IDR(port,v) ((AT91PS_USART)(port)->membase)->US_IDR = v
#define UART_GET_IMR(port) ((AT91PS_USART)(port)->membase)->US_IMR
#define UART_GET_CSR(port) ((AT91PS_USART)(port)->membase)->US_CSR
#define UART_GET_CHAR(port) ((AT91PS_USART)(port)->membase)->US_RHR
#define UART_PUT_CHAR(port,v) ((AT91PS_USART)(port)->membase)->US_THR = v
#define UART_GET_BRGR(port) ((AT91PS_USART)(port)->membase)->US_BRGR
#define UART_PUT_BRGR(port,v) ((AT91PS_USART)(port)->membase)->US_BRGR = v// 
#define UART_GET_CR(port) ((AT91PS_USART)(port)->membase)->US_CR  // is 
write-onlystatic struct tty_driver normal, callout;
static struct tty_struct *at91_table[AT91C_NR_UART];
static struct termios *at91_termios[AT91C_NR_UART], 
*at91_termios_locked[AT91C_NR_UART];
static int (*at91_open)(struct uart_port *, struct uart_info *);
static void (*at91_close)(struct uart_port *, struct uart_info *);#ifdef 
SUPPORT_SYSRQ
static struct console at91_console;
#endif/*
 * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
 */
static u_int at91_tx_empty(struct uart_port *port)
{
 return UART_GET_CSR(port) & AT91C_US_TXEMPTY ? TIOCSER_TEMT : 0;
}/*
 * Set state of the modem control output lines
 */
static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
{
 unsigned int control = 0; if (mctrl & TIOCM_RTS)
  control |= AT91C_US_RTSEN;
 else
  control |= AT91C_US_RTSDIS; if (mctrl & TIOCM_DTR)
  control |= AT91C_US_DTREN;
 else
  control |=  AT91C_US_DTRDIS; UART_PUT_CR(port,control);
}/*
 * Get state of the modem control input lines
 */
static u_int at91_get_mctrl(struct uart_port *port)
{
 unsigned int status, ret = 0; status = UART_GET_CSR(port);
 if (status & AT91C_US_DCD)
  ret |= TIOCM_CD;
 if (status & AT91C_US_CTS)
  ret |= TIOCM_CTS;
 if (status & AT91C_US_DSR)
  ret |= TIOCM_DSR;
 if (status & AT91C_US_RI)
  ret |= TIOCM_RI; return ret;
}/*
 * Stop transmitting.
 */
static void at91_stop_tx(struct uart_port *port, u_int from_tty)
{
 UART_PUT_IDR(port, AT91C_US_TXRDY);
 port->read_status_mask &= ~AT91C_US_TXRDY;
}/*
 * Start transmitting.
 */
static void at91_start_tx(struct uart_port *port, u_int nonempty, u_int 
from_tty)
{
 if (nonempty) {
  unsigned long flags;  local_irq_save(flags);
  port->read_status_mask |= AT91C_US_TXRDY;
  UART_PUT_IER(port, AT91C_US_TXRDY);
  local_irq_restore(flags);
 }
}/*
 * Stop receiving - port is in process of being closed.
 */
static void at91_stop_rx(struct uart_port *port)
{
 UART_PUT_IDR(port, AT91C_US_RXRDY);
}/*
 * Enable modem status interrupts
 */
static void at91_enable_ms(struct uart_port *port)
{
 UART_PUT_IER(port, AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | 
AT91C_US_CTSIC);
}/*
 * Control the transmission of a break signal
 */
static void at91_break_ctl(struct uart_port *port, int break_state)
{
 if (break_state != 0)
  UART_PUT_CR(port, AT91C_US_STTBRK); /* start break */
 else
  UART_PUT_CR(port, AT91C_US_STPBRK); /* stop break */
}/*
 * Characters received (called from interrupt handler)
 */
static void at91_rx_chars(struct uart_info *info, struct pt_regs *regs)
{
 struct tty_struct *tty = info->tty;
 struct uart_port *port = info->port;
 unsigned int status, ch, flg, ignored = 0; status = UART_GET_CSR(port);
 while (status & (AT91C_US_RXRDY)) {
  ch = UART_GET_CHAR(port);  if (tty->flip.count >= TTY_FLIPBUF_SIZE)
   goto ignore_char;
  port->icount.rx++;  flg = TTY_NORMAL;  /*
   * note that the error handling code is
   * out of the main execution path
   */
  if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE))
   goto handle_error;  if (uart_handle_sysrq_char(info, ch, regs))
   goto ignore_char; error_return:
  *tty->flip.flag_buf_ptr++ = flg;
  *tty->flip.char_buf_ptr++ = ch;
  tty->flip.count++;
 ignore_char:
  status = UART_GET_CSR(port);
 }
out:
 tty_flip_buffer_push(tty);
 return;handle_error:
 if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE))
  UART_PUT_CR(port, AT91C_US_RSTSTA);  /* clear error */
 if (status & (AT91C_US_PARE))
  port->icount.parity++;
 else if (status & (AT91C_US_FRAME))
  port->icount.frame++;
 if (status & (AT91C_US_OVRE))
  port->icount.overrun++; if (status & port->ignore_status_mask) {
  if (++ignored > 100)
   goto out;
  goto ignore_char;
 } status &= port->read_status_mask; UART_PUT_CR(port, AT91C_US_RSTSTA);  /* 
clear error */
 if (status & AT91C_US_PARE)
  flg = TTY_PARITY;
 else if (status & AT91C_US_FRAME)
  flg = TTY_FRAME; if (status & AT91C_US_OVRE) {
  /*
   * overrun does *not* affect the character
   * we read from the FIFO
   */
  *tty->flip.flag_buf_ptr++ = flg;
  *tty->flip.char_buf_ptr++ = ch;
  tty->flip.count++;
  if (tty->flip.count >= TTY_FLIPBUF_SIZE)
   goto ignore_char;
  ch = 0;
  flg = TTY_OVERRUN;
 }
#ifdef SUPPORT_SYSRQ
 info->sysrq = 0;
#endif
 goto error_return;
}/*
 * Transmit characters (called from interrupt handler)
 */
static void at91_tx_chars(struct uart_info *info)
{
 struct uart_port *port = info->port; if (port->x_char) {
  UART_PUT_CHAR(port, port->x_char);
  port->icount.tx++;
  port->x_char = 0;
  return;
 }
 if (info->xmit.head == info->xmit.tail
     || info->tty->stopped
     || info->tty->hw_stopped) {
  at91_stop_tx(info->port, 0);
  return;
 } while (UART_GET_CSR(port) & AT91C_US_TXRDY) {
  UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
  info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
  port->icount.tx++;
  if (info->xmit.head == info->xmit.tail)
   break;
 } if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < 
WAKEUP_CHARS)
  uart_event(info, EVT_WRITE_WAKEUP); if (info->xmit.head == info->xmit.tail)
  at91_stop_tx(info->port, 0);
}/*
 * Interrupt handler
 */
static void at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
 struct uart_info *info = dev_id;
 struct uart_port *port = info->port;
 unsigned int status, pending, pass_counter = 0; status = UART_GET_CSR(port);
 pending = status & port->read_status_mask;
 if (pending) {
  do {
   if (pending & AT91C_US_RXRDY)
    at91_rx_chars(info, regs);   /* Clear the relevent break bits */
   if (pending & AT91C_US_RXBRK) {
    UART_PUT_CR(port, AT91C_US_RSTSTA);
    port->icount.brk++;
#ifdef SUPPORT_SYSRQ
    if (port->line == at91_console.index && !info->sysrq) {
     info->sysrq = jiffies + HZ*5;
    }
#endif
   }   // TODO: All reads to CSR will clear these interrupts!
   if (pending & AT91C_US_RIIC) port->icount.rng++;
   if (pending & AT91C_US_DSRIC) port->icount.dsr++;
   if (pending & AT91C_US_DCDIC) {
    port->icount.dcd++;
    uart_handle_dcd_change(info, status & AT91C_US_DCD);
   }
   if (pending & AT91C_US_CTSIC) {
    port->icount.cts++;
    uart_handle_cts_change(info, status & AT91C_US_CTS);
   }
   if (pending & (AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | 
AT91C_US_CTSIC))
    wake_up_interruptible(&info->delta_msr_wait);   if (pending & 
AT91C_US_TXRDY)
    at91_tx_chars(info);
   if (pass_counter++ > AT91_ISR_PASS_LIMIT)
    break;   status = UART_GET_CSR(port);
   pending = status & port->read_status_mask;
  } while (pending);
 }
}/*
 * Perform initialization and enable port for reception
 */
static int at91_startup(struct uart_port *port, struct uart_info *info)
{
 int retval; /*
  * Allocate the IRQ
  */
 retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", info);
 if (retval) {
  printk("at91_serial: at91_startup - Can't get irq\n");
  return retval;
 }
 /*
  * If there is a specific "open" function (to register
  * control line interrupts)
  */
 if (at91_open) {
  retval = at91_open(port, info);
  if (retval) {
   free_irq(port->irq, info);
   return retval;
  }
 } /* Enable peripheral clock if required */
 if (port->irq != AT91C_ID_SYS)
  AT91_SYS->PMC_PCER = 1 << port->irq; port->read_status_mask = AT91C_US_RXRDY 
| AT91C_US_TXRDY | AT91C_US_OVRE
   | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK;
 /*
  * Finally, clear and enable interrupts
  */
 UART_PUT_IDR(port, -1);
 UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN);  /* enable xmit & rcvr */
 UART_PUT_IER(port, AT91C_US_RXRDY);  /* do receive only */
 return 0;
}/*
 * Disable the port
 */
static void at91_shutdown(struct uart_port *port, struct uart_info *info)
{
 /*
  * Free the interrupt
  */
 free_irq(port->irq, info); /*
  * If there is a specific "close" function (to unregister
  * control line interrupts)
  */
 if (at91_close)
  at91_close(port, info); /*
  * Disable all interrupts, port and break condition.
  */
 UART_PUT_CR(port, AT91C_US_RSTSTA);
 UART_PUT_IDR(port, -1); /* Disable peripheral clock if required */
 if (port->irq != AT91C_ID_SYS)
  AT91_SYS->PMC_PCDR = 1 << port->irq;
}/*
 * Change the port parameters
 */
static void at91_change_speed(struct uart_port *port, u_int cflag, u_int iflag, 
u_int quot)
{
 unsigned long flags;
 unsigned int mode, imr; /* Get current mode register */
 mode = UART_GET_MR(port) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR); 
/* byte size */
 switch (cflag & CSIZE) {
 case CS5:
  mode |= AT91C_US_CHRL_5_BITS;
  break;
 case CS6:
  mode |= AT91C_US_CHRL_6_BITS;
  break;
 case CS7:
  mode |= AT91C_US_CHRL_7_BITS;
  break;
 default:
  mode |= AT91C_US_CHRL_8_BITS;
  break;
 } /* stop bits */
 if (cflag & CSTOPB)
  mode |= AT91C_US_NBSTOP_2_BIT; /* parity */
 if (cflag & PARENB) {
  if (cflag & PARODD)
   mode |= AT91C_US_PAR_ODD;
  else
   mode |= AT91C_US_PAR_EVEN;
 }
 else
  mode |= AT91C_US_PAR_NONE; port->read_status_mask |= AT91C_US_OVRE;
 if (iflag & INPCK)
  port->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE;
 if (iflag & (BRKINT | PARMRK))
  port->read_status_mask |= AT91C_US_RXBRK; /*
  * Characters to ignore
  */
 port->ignore_status_mask = 0;
 if (iflag & IGNPAR)
  port->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE);
 if (iflag & IGNBRK) {
  port->ignore_status_mask |= AT91C_US_RXBRK;
  /*
   * If we're ignoring parity and break indicators,
   * ignore overruns too (for real raw support).
   */
  if (iflag & IGNPAR)
   port->ignore_status_mask |= AT91C_US_OVRE;
 } // TODO: Ignore all characters if CREAD is set. /* first, disable interrupts 
and drain transmitter */
 local_irq_save(flags);
 imr = UART_GET_IMR(port); /* get interrupt mask */
 UART_PUT_IDR(port, -1);  /* disable all interrupts */
 local_irq_restore(flags);
 while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); } /* disable 
receiver and transmitter */
 UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS); /* set the parity, stop 
bits and data size */
 UART_PUT_MR(port, mode); /* set the baud rate */
 UART_PUT_BRGR(port, quot);
 UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); /* restore interrupts */
 UART_PUT_IER(port, imr);
}/*
 * Return string describing the specified port
 */
static const char *at91_type(struct uart_port *port)
{
 return port->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL;
}/*
 * Release the memory region(s) being used by 'port'.
 */
static void at91_release_port(struct uart_port *port)
{
 release_mem_region(port->mapbase,
  port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K);
}/*
 * Request the memory region(s) being used by 'port'.
 */
static int at91_request_port(struct uart_port *port)
{
 return request_mem_region(port->mapbase,
  port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K,
  "at91_serial") != NULL ? 0 : -EBUSY;}/*
 * Configure/autoconfigure the port.
 */
static void at91_config_port(struct uart_port *port, int flags)
{
 if (flags & UART_CONFIG_TYPE) {
  port->type = PORT_AT91RM9200;
  at91_request_port(port);
 }
}/*
 * Verify the new serial_struct (for TIOCSSERIAL).
 */
static int at91_verify_port(struct uart_port *port, struct serial_struct *ser)
{
 int ret = 0;
 if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200)
  ret = -EINVAL;
 if (port->irq != ser->irq)
  ret = -EINVAL;
 if (ser->io_type != SERIAL_IO_MEM)
  ret = -EINVAL;
 if (port->uartclk / 16 != ser->baud_base)
  ret = -EINVAL;
 if ((void *)port->mapbase != ser->iomem_base)
  ret = -EINVAL;
 if (port->iobase != ser->port)
  ret = -EINVAL;
 if (ser->hub6 != 0)
  ret = -EINVAL;
 return ret;
}static struct uart_ops at91_pops = {
 tx_empty: at91_tx_empty,
 set_mctrl: at91_set_mctrl,
 get_mctrl: at91_get_mctrl,
 stop_tx: at91_stop_tx,
 start_tx: at91_start_tx,
 stop_rx: at91_stop_rx,
 enable_ms: at91_enable_ms,
 break_ctl: at91_break_ctl,
 startup: at91_startup,
 shutdown: at91_shutdown,
 change_speed: at91_change_speed,
 type:  at91_type,
 release_port: at91_release_port,
 request_port: at91_request_port,
 config_port: at91_config_port,
 verify_port: at91_verify_port,
};static struct uart_port at91_ports[AT91C_NR_UART];void __init 
at91_register_uart_fns(struct at91_port_fns *fns)
{
 if (fns->enable_ms)
  at91_pops.enable_ms = fns->enable_ms;
 if (fns->get_mctrl)
  at91_pops.get_mctrl = fns->get_mctrl;
 if (fns->set_mctrl)
  at91_pops.set_mctrl = fns->set_mctrl;
 at91_open          = fns->open;
 at91_close         = fns->close;
 at91_pops.pm       = fns->pm;
 at91_pops.set_wake = fns->set_wake;
}/*
 * Setup ports.
 */
void __init at91_register_uart(int idx, int port)
{
 if ((idx < 0) || (idx >= AT91C_NR_UART)) {
  printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx);
  return;
 } at91_ports[idx].iotype   = SERIAL_IO_MEM;
 at91_ports[idx].flags    = ASYNC_BOOT_AUTOCONF;
 at91_ports[idx].uartclk  = AT91C_MASTER_CLOCK;
 at91_ports[idx].ops      = &at91_pops;
 at91_ports[idx].fifosize = 0; switch (port) {
 case 0:
  at91_ports[idx].membase = (void *) AT91C_VA_BASE_US0;
  at91_ports[idx].mapbase = AT91C_VA_BASE_US0;
  at91_ports[idx].irq     = AT91C_ID_US0;
  AT91_CfgPIO_USART0();
  break;
 case 1:
  at91_ports[idx].membase = (void *) AT91C_VA_BASE_US1;
  at91_ports[idx].mapbase = AT91C_VA_BASE_US1;
  at91_ports[idx].irq     = AT91C_ID_US1;
  AT91_CfgPIO_USART1();
  break;
 case 2:
  at91_ports[idx].membase = (void *) AT91C_VA_BASE_US2;
  at91_ports[idx].mapbase = AT91C_VA_BASE_US2;
  at91_ports[idx].irq     = AT91C_ID_US2;
  AT91_CfgPIO_USART2();
  break;
 case 3:
  at91_ports[idx].membase = (void *) AT91C_VA_BASE_US3;
  at91_ports[idx].mapbase = AT91C_VA_BASE_US3;
  at91_ports[idx].irq     = AT91C_ID_US3;
  AT91_CfgPIO_USART3();
  break;
 case 4:
  at91_ports[idx].membase = (void *) AT91C_VA_BASE_DBGU;
  at91_ports[idx].mapbase = AT91C_VA_BASE_DBGU;
  at91_ports[idx].irq     = AT91C_ID_SYS;
  AT91_CfgPIO_DBGU();
  break;
 default:
  printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port);
 }
}#ifdef CONFIG_SERIAL_AT91_CONSOLE#ifndef CONFIG_AT91_DEFAULT_BAUDRATE
#define CONFIG_AT91_DEFAULT_BAUDRATE 115200
#endif/*
 * Interrupts are disabled on entering
 */
static void at91_console_write(struct console *co, const char *s, u_int count)
{
 struct uart_port *port = at91_ports + co->index;
 unsigned int status, i, imr; /*
  * First, save IMR and then disable interrupts
  */
 imr = UART_GET_IMR(port); /* get interrupt mask */
 UART_PUT_IDR(port, AT91C_US_RXRDY | AT91C_US_TXRDY); /*
  * Now, do each character
  */
 for (i = 0; i < count; i++) {
  do {
   status = UART_GET_CSR(port);
  } while (!(status & AT91C_US_TXRDY));
  UART_PUT_CHAR(port, s[i]);
  if (s[i] == '\n') {
   do {
    status = UART_GET_CSR(port);
   } while (!(status & AT91C_US_TXRDY));
   UART_PUT_CHAR(port, '\r');
  }
 } /*
  * Finally, wait for transmitter to become empty
  * and restore IMR
  */
 do {
  status = UART_GET_CSR(port);
 } while (status & AT91C_US_TXRDY);
 UART_PUT_IER(port, imr); /* set interrupts back the way they were */
}static kdev_t at91_console_device(struct console *co)
{
 return MKDEV(SERIAL_AT91_MAJOR, MINOR_START + co->index);
}/*
 * If the port was already initialised (eg, by a boot loader), try to determine
 * the current setup.
 */
static void __init at91_console_get_options(struct uart_port *port, int *baud, 
int *parity, int *bits)
{
 unsigned int cr, mr, quot;// TODO: CR is a write-only register
// cr = UART_GET_CR(port) & (AT91C_US_RXEN | AT91C_US_TXEN);
// if (cr == (AT91C_US_RXEN | AT91C_US_TXEN)) {
//  /* ok, the port was enabled */
//
//  mr = UART_GET_MR(port) & AT91C_US_PAR;
//
//  *parity = 'n';
//  if (mr == AT91C_US_PAR_EVEN)
//   *parity = 'e';
//  else if (mr == AT91C_US_PAR_ODD)
//   *parity = 'o';
// } mr = UART_GET_MR(port) & AT91C_US_CHRL;
 if (mr == AT91C_US_CHRL_8_BITS)
  *bits = 8;
 else
  *bits = 7; quot = UART_GET_BRGR(port);
 *baud = port->uartclk / (16 * (quot));
}static int __init at91_console_setup(struct console *co, char *options)
{
 struct uart_port *port;
 int baud = CONFIG_AT91_DEFAULT_BAUDRATE;
 int bits = 8;
 int parity = 'n';
 int flow = 'n'; /*
  * Check whether an invalid uart number has been specified, and
  * if so, search for the first available port that does have
  * console support.
  */
 port = uart_get_console(at91_ports, AT91C_NR_UART, co); // TODO: The console 
port should be initialized, and clock enabled if
 //  we're not relying on the bootloader to do it. if (options)
  uart_parse_options(options, &baud, &parity, &bits, &flow);
 else
  at91_console_get_options(port, &baud, &parity, &bits); return 
uart_set_options(port, co, baud, parity, bits, flow);
}static struct console at91_console = {
 name:  "ttyS",
 write:  at91_console_write,
 device:  at91_console_device,
 setup:  at91_console_setup,
 flags:  CON_PRINTBUFFER,
 index:  AT91C_CONSOLE,
};#define AT91_CONSOLE_DEVICE &at91_consolevoid __init at91_console_init(void)
{
 register_console(&at91_console);
}#else
#define AT91_CONSOLE_DEVICE NULL
#endifstatic struct uart_driver at91_reg = {
 owner:   THIS_MODULE,
 normal_major:  SERIAL_AT91_MAJOR,
#ifdef CONFIG_DEVFS_FS
 normal_name:  "ttyS%d",
 callout_name:  "cua%d",
#else
 normal_name:  "ttyS",
 callout_name:  "cua",
#endif
 normal_driver:  &normal,
 callout_major:  CALLOUT_AT91_MAJOR,
 callout_driver:  &callout,
 table:   at91_table,
 termios:  at91_termios,
 termios_locked:  at91_termios_locked,
 minor:   MINOR_START,
 nr:   AT91C_NR_UART,
 port:   at91_ports,
 cons:   AT91_CONSOLE_DEVICE,
};static int __init at91_serial_init(void)
{
 return uart_register_driver(&at91_reg);
}static void __exit at91_serial_exit(void)
{
 uart_unregister_driver(&at91_reg);
}module_init(at91_serial_init);
module_exit(at91_serial_exit);EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("AT91 generic serial port driver");
MODULE_LICENSE("GPL");
***************************************************************And  I found the 
structures inlinux/include/asm-arm/mach/serial_at91rm9200.h,just like below: /*
 *  linux/include/asm-arm/mach/serial_at91rm9200.h
 *
 *  Based on serial_sa1100.h  by Nicolas Pitre
 *
 *  Copyright (C) 2002 ATMEL Rousset
 *
 *  Low level machine dependent UART functions.
 */
#include <linux/config.h>struct uart_port;
struct uart_info;/*
 * This is a temporary structure for registering these
 * functions; it is intended to be discarded after boot.
 */
struct at91rm9200_port_fns {
 void (*set_mctrl)(struct uart_port *, u_int);
 u_int (*get_mctrl)(struct uart_port *);
 void (*enable_ms)(struct uart_port *);
 void (*pm)(struct uart_port *, u_int, u_int);
 int (*set_wake)(struct uart_port *, u_int);
 int (*open)(struct uart_port *, struct uart_info *);
 void (*close)(struct uart_port *, struct uart_info *);
};#if defined(CONFIG_SERIAL_AT91RM9200)
void at91rm9200_register_uart_fns(struct at91rm9200_port_fns *fns);
void at91rm9200_register_uart(int idx, int port);
#else
#define at91rm9200_register_uart_fns(fns) do { } while (0)
#define at91rm9200_register_uart(idx,port) do { } while (0)
#endif ***********************************************************I wonder 
where are the  at91_register_uart_fns()and __init at91_register_uart(int idx, 
int port) been called How at91_open() is defined? 
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to