ps2ser.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /***********************************************************************
  2. *
  3. * (C) Copyright 2004
  4. * DENX Software Engineering
  5. * Wolfgang Denk, wd@denx.de
  6. * All rights reserved.
  7. *
  8. * Simple 16550A serial driver
  9. *
  10. * Originally from linux source (drivers/char/ps2ser.c)
  11. *
  12. * Used by the PS/2 multiplexer driver (ps2mult.c)
  13. *
  14. ***********************************************************************/
  15. #include <common.h>
  16. #ifdef CONFIG_PS2SERIAL
  17. #include <asm/io.h>
  18. #include <asm/atomic.h>
  19. #include <ps2mult.h>
  20. /* #define DEBUG */
  21. #define PS2SER_BAUD 57600
  22. static int ps2ser_getc_hw(void);
  23. static void ps2ser_interrupt(void *dev_id);
  24. extern struct serial_state rs_table[]; /* in serial.c */
  25. static struct serial_state *state;
  26. static u_char ps2buf[PS2BUF_SIZE];
  27. static atomic_t ps2buf_cnt;
  28. static int ps2buf_in_idx;
  29. static int ps2buf_out_idx;
  30. static inline unsigned int ps2ser_in(int offset)
  31. {
  32. return readb((unsigned long) state->iomem_base + offset);
  33. }
  34. static inline void ps2ser_out(int offset, int value)
  35. {
  36. writeb(value, (unsigned long) state->iomem_base + offset);
  37. }
  38. int ps2ser_init(void)
  39. {
  40. int quot;
  41. unsigned cval;
  42. state = rs_table + CONFIG_PS2SERIAL;
  43. quot = state->baud_base / PS2SER_BAUD;
  44. cval = 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
  45. /* Set speed, enable interrupts, enable FIFO
  46. */
  47. ps2ser_out(UART_LCR, cval | UART_LCR_DLAB);
  48. ps2ser_out(UART_DLL, quot & 0xff);
  49. ps2ser_out(UART_DLM, quot >> 8);
  50. ps2ser_out(UART_LCR, cval);
  51. ps2ser_out(UART_IER, UART_IER_RDI);
  52. ps2ser_out(UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
  53. ps2ser_out(UART_FCR,
  54. UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
  55. /* If we read 0xff from the LSR, there is no UART here
  56. */
  57. if (ps2ser_in(UART_LSR) == 0xff) {
  58. printf ("ps2ser.c: no UART found\n");
  59. return -1;
  60. }
  61. irq_install_handler(state->irq, ps2ser_interrupt, NULL);
  62. return 0;
  63. }
  64. void ps2ser_putc(int chr)
  65. {
  66. #ifdef DEBUG
  67. printf(">>>> 0x%02x\n", chr);
  68. #endif
  69. while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE));
  70. ps2ser_out(UART_TX, chr);
  71. }
  72. static int ps2ser_getc_hw(void)
  73. {
  74. int res = -1;
  75. if (ps2ser_in(UART_LSR) & UART_LSR_DR) {
  76. res = (ps2ser_in(UART_RX));
  77. }
  78. return res;
  79. }
  80. int ps2ser_getc(void)
  81. {
  82. volatile int chr;
  83. int flags;
  84. #ifdef DEBUG
  85. printf("<< ");
  86. #endif
  87. flags = disable_interrupts();
  88. do {
  89. if (atomic_read(&ps2buf_cnt) != 0) {
  90. chr = ps2buf[ps2buf_out_idx++];
  91. ps2buf_out_idx &= (PS2BUF_SIZE - 1);
  92. atomic_dec(&ps2buf_cnt);
  93. } else {
  94. chr = ps2ser_getc_hw();
  95. }
  96. }
  97. while (chr < 0);
  98. if (flags) enable_interrupts();
  99. #ifdef DEBUG
  100. printf("0x%02x\n", chr);
  101. #endif
  102. return chr;
  103. }
  104. int ps2ser_check(void)
  105. {
  106. int flags;
  107. flags = disable_interrupts();
  108. ps2ser_interrupt(NULL);
  109. if (flags) enable_interrupts();
  110. return atomic_read(&ps2buf_cnt);
  111. }
  112. static void ps2ser_interrupt(void *dev_id)
  113. {
  114. int chr;
  115. int iir;
  116. do {
  117. chr = ps2ser_getc_hw();
  118. iir = ps2ser_in(UART_IIR);
  119. if (chr < 0) continue;
  120. if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
  121. ps2buf[ps2buf_in_idx++] = chr;
  122. ps2buf_in_idx &= (PS2BUF_SIZE - 1);
  123. atomic_inc(&ps2buf_cnt);
  124. } else {
  125. printf ("ps2ser.c: buffer overflow\n");
  126. }
  127. } while (iir & UART_IIR_RDI);
  128. if (atomic_read(&ps2buf_cnt)) {
  129. ps2mult_callback(atomic_read(&ps2buf_cnt));
  130. }
  131. }
  132. #endif /* CONFIG_PS2SERIAL */