serial.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * serial port handler
  3. *
  4. * Copyright (c) 2009 Openmoko Inc.
  5. *
  6. * Authors Daniel Mack <daniel@caiaq.de>
  7. * Christopher Hall <hsw@openmoko.com>
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include <guilib.h>
  23. #include <wikilib.h>
  24. #include <input.h>
  25. #include <msg.h>
  26. #include <regs.h>
  27. #include <interrupt.h>
  28. #include "serial.h"
  29. static u8 console_buffer[16];
  30. static unsigned int console_read;
  31. static unsigned int console_write;
  32. serial_buffer_type *send_queue_head;
  33. serial_buffer_type *send_queue_tail;
  34. const char *transmit;
  35. volatile bool linefeed;
  36. #define BUFFER_FULL(w, r, b) ((((w) + 1) % ARRAY_SIZE(b)) == (r))
  37. #define BUFFER_EMPTY(w, r, b) ((w) == (r))
  38. #define BUFFER_NEXT(p, b) (p) = (((p) + 1) % ARRAY_SIZE(b))
  39. void serial_init(void)
  40. {
  41. static bool initialised = false;
  42. if (!initialised) {
  43. InterruptType s = Interrupt_disable();
  44. REG_INT_ESIF01 = ESRX0;
  45. REG_INT_PLCDC_PSIO0 = 0x70;
  46. console_read = 0;
  47. console_write = 0;
  48. send_queue_head = NULL;
  49. send_queue_tail = NULL;
  50. linefeed = false;
  51. initialised = true;
  52. Interrupt_enable(s);
  53. }
  54. }
  55. void serial_put(serial_buffer_type *buffer)
  56. {
  57. if (NULL != buffer) {
  58. // critical code - disable uart tx interrupts
  59. InterruptType s = Interrupt_disable();
  60. REG_INT_ESIF01 &= ~ESTX0;
  61. Interrupt_enable(s);
  62. buffer->link = NULL;
  63. if (NULL != send_queue_tail) {
  64. send_queue_tail->link = buffer;
  65. }
  66. send_queue_tail = buffer;
  67. if (NULL == send_queue_head) {
  68. send_queue_head = send_queue_tail;
  69. transmit = send_queue_head->text;
  70. s = Interrupt_disable();
  71. REG_INT_FSIF01 = FSTX0;
  72. Interrupt_enable(s);
  73. {
  74. u8 c = *transmit++;
  75. if ('\n' == c) {
  76. c = '\r';
  77. linefeed = true;
  78. }
  79. REG_EFSIF0_TXD = c;
  80. }
  81. }
  82. s = Interrupt_disable();
  83. REG_INT_ESIF01 |= ESTX0;
  84. Interrupt_enable(s);
  85. }
  86. }
  87. // in interrupt state
  88. void serial_drained_0(void)
  89. {
  90. if (!linefeed && '\0' == *transmit) {
  91. serial_buffer_type *p = send_queue_head;
  92. send_queue_head = send_queue_head->link;
  93. if (NULL != p->callback) {
  94. p->callback(p);
  95. }
  96. if (NULL == send_queue_head) {
  97. transmit = NULL;
  98. send_queue_tail = NULL;
  99. }
  100. else {
  101. transmit = send_queue_head->text;
  102. }
  103. }
  104. if (NULL == transmit) {
  105. REG_INT_ESIF01 &= ~ESTX0;
  106. }
  107. else {
  108. REG_INT_FSIF01 |= FSTX0;
  109. if (linefeed) {
  110. linefeed = false;
  111. REG_EFSIF0_TXD = '\n';
  112. }
  113. else {
  114. u8 c = *transmit++;
  115. if ('\n' == c) {
  116. c = '\r';
  117. linefeed = true;
  118. }
  119. REG_EFSIF0_TXD = c;
  120. }
  121. }
  122. }
  123. // in interrupt state
  124. void serial_filled_0(void)
  125. {
  126. while (REG_EFSIF0_STATUS & RDBFx) {
  127. u8 c = REG_EFSIF0_RXD;
  128. if (c == 0)
  129. continue;
  130. console_buffer[console_write] = c;
  131. BUFFER_NEXT(console_write, console_buffer);
  132. }
  133. }
  134. void serial_out(int port, char c)
  135. {
  136. if (port != 0)
  137. return;
  138. InterruptType s = Interrupt_disable();
  139. REG_EFSIF0_TXD = c;
  140. Interrupt_enable(s);
  141. }
  142. bool serial_event_pending(void)
  143. {
  144. return !BUFFER_EMPTY(console_write, console_read, console_buffer);
  145. }
  146. int serial_get_event(struct wl_input_event *ev)
  147. {
  148. if (BUFFER_EMPTY(console_write, console_read, console_buffer))
  149. return 0;
  150. // msg(MSG_INFO, " OUT. %d %d %p %p\n", console_read, console_write,
  151. // ev, &ev->type);
  152. ev->type = WL_INPUT_EV_TYPE_KEYBOARD;
  153. if (0x7f == console_buffer[console_read]) {
  154. console_buffer[console_read] = 0x08;
  155. }
  156. ev->key_event.keycode = console_buffer[console_read];
  157. ev->key_event.value = 1;
  158. BUFFER_NEXT(console_read, console_buffer);
  159. /* Override for scrolling... */
  160. if ((ev->key_event.keycode == WL_KEY_PLUS) || (ev->key_event.keycode == WL_KEY_DOWN)) {
  161. ev->type = WL_INPUT_EV_TYPE_CURSOR;
  162. ev->key_event.keycode = WL_INPUT_KEY_CURSOR_DOWN;
  163. }
  164. else if ((ev->key_event.keycode == WL_KEY_MINUS) || (ev->key_event.keycode == WL_KEY_UP)) {
  165. ev->type = WL_INPUT_EV_TYPE_CURSOR;
  166. ev->key_event.keycode = WL_INPUT_KEY_CURSOR_UP;
  167. }
  168. return 1;
  169. }