uboot/drivers/input/ps2ser.c
<<
>>
Prefs
   1/***********************************************************************
   2 *
   3 * (C) Copyright 2004-2009
   4 * DENX Software Engineering
   5 * Wolfgang Denk, wd@denx.de
   6 *
   7 * Simple 16550A serial driver
   8 *
   9 * Originally from linux source (drivers/char/ps2ser.c)
  10 *
  11 * Used by the PS/2 multiplexer driver (ps2mult.c)
  12 *
  13 ***********************************************************************/
  14
  15#include <common.h>
  16
  17#include <asm/io.h>
  18#include <asm/atomic.h>
  19#include <ps2mult.h>
  20/* This is needed for ns16550.h */
  21#ifndef CONFIG_SYS_NS16550_REG_SIZE
  22#define CONFIG_SYS_NS16550_REG_SIZE 1
  23#endif
  24#include <ns16550.h>
  25
  26DECLARE_GLOBAL_DATA_PTR;
  27
  28/* #define      DEBUG */
  29
  30#define PS2SER_BAUD     57600
  31
  32#if CONFIG_PS2SERIAL == 1
  33#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
  34#elif CONFIG_PS2SERIAL == 2
  35#define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
  36#else
  37#error CONFIG_PS2SERIAL must be in 1 ... 2
  38#endif
  39
  40static int      ps2ser_getc_hw(void);
  41static void     ps2ser_interrupt(void *dev_id);
  42
  43extern struct   serial_state rs_table[]; /* in serial.c */
  44
  45static u_char   ps2buf[PS2BUF_SIZE];
  46static atomic_t ps2buf_cnt;
  47static int      ps2buf_in_idx;
  48static int      ps2buf_out_idx;
  49
  50int ps2ser_init(void)
  51{
  52        NS16550_t com_port = (NS16550_t)COM_BASE;
  53
  54        com_port->ier = 0x00;
  55        com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1;
  56        com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
  57        com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
  58        com_port->lcr = UART_LCR_8N1;
  59        com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS);
  60        com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
  61
  62        return (0);
  63}
  64
  65void ps2ser_putc(int chr)
  66{
  67        NS16550_t com_port = (NS16550_t)COM_BASE;
  68        debug(">>>> 0x%02x\n", chr);
  69
  70        while ((com_port->lsr & UART_LSR_THRE) == 0);
  71        com_port->thr = chr;
  72}
  73
  74static int ps2ser_getc_hw(void)
  75{
  76        NS16550_t com_port = (NS16550_t)COM_BASE;
  77        int res = -1;
  78
  79        if (com_port->lsr & UART_LSR_DR) {
  80                res = com_port->rbr;
  81        }
  82
  83        return res;
  84}
  85
  86int ps2ser_getc(void)
  87{
  88        volatile int chr;
  89        int flags;
  90
  91        debug("<< ");
  92
  93        flags = disable_interrupts();
  94
  95        do {
  96                if (atomic_read(&ps2buf_cnt) != 0) {
  97                        chr = ps2buf[ps2buf_out_idx++];
  98                        ps2buf_out_idx &= (PS2BUF_SIZE - 1);
  99                        atomic_dec(&ps2buf_cnt);
 100                } else {
 101                        chr = ps2ser_getc_hw();
 102                }
 103        }
 104        while (chr < 0);
 105
 106        if (flags)
 107                enable_interrupts();
 108
 109        debug("0x%02x\n", chr);
 110
 111        return chr;
 112}
 113
 114int ps2ser_check(void)
 115{
 116        int flags;
 117
 118        flags = disable_interrupts();
 119        ps2ser_interrupt(NULL);
 120        if (flags) enable_interrupts();
 121
 122        return atomic_read(&ps2buf_cnt);
 123}
 124
 125static void ps2ser_interrupt(void *dev_id)
 126{
 127        NS16550_t com_port = (NS16550_t)COM_BASE;
 128        int chr;
 129        int status;
 130
 131        do {
 132                chr = ps2ser_getc_hw();
 133                status = com_port->lsr;
 134                if (chr < 0) continue;
 135
 136                if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
 137                        ps2buf[ps2buf_in_idx++] = chr;
 138                        ps2buf_in_idx &= (PS2BUF_SIZE - 1);
 139                        atomic_inc(&ps2buf_cnt);
 140                } else {
 141                        printf ("ps2ser.c: buffer overflow\n");
 142                }
 143        } while (status & UART_LSR_DR);
 144        if (atomic_read(&ps2buf_cnt)) {
 145                ps2mult_callback(atomic_read(&ps2buf_cnt));
 146        }
 147}
 148