simcons.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * arch/v850/kernel/simcons.c -- Console I/O for GDB v850e simulator
  3. *
  4. * Copyright (C) 2001,02,03 NEC Electronics Corporation
  5. * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
  6. *
  7. * This file is subject to the terms and conditions of the GNU General
  8. * Public License. See the file COPYING in the main directory of this
  9. * archive for more details.
  10. *
  11. * Written by Miles Bader <miles@gnu.org>
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/console.h>
  15. #include <linux/tty.h>
  16. #include <linux/tty_flip.h>
  17. #include <linux/tty_driver.h>
  18. #include <linux/init.h>
  19. #include <asm/poll.h>
  20. #include <asm/string.h>
  21. #include <asm/simsyscall.h>
  22. /* Low-level console. */
  23. static void simcons_write (struct console *co, const char *buf, unsigned len)
  24. {
  25. V850_SIM_SYSCALL (write, 1, buf, len);
  26. }
  27. static int simcons_read (struct console *co, char *buf, unsigned len)
  28. {
  29. return V850_SIM_SYSCALL (read, 0, buf, len);
  30. }
  31. static struct tty_driver *tty_driver;
  32. static struct tty_driver *simcons_device (struct console *c, int *index)
  33. {
  34. *index = c->index;
  35. return tty_driver;
  36. }
  37. static struct console simcons =
  38. {
  39. .name = "simcons",
  40. .write = simcons_write,
  41. .read = simcons_read,
  42. .device = simcons_device,
  43. .flags = CON_PRINTBUFFER,
  44. .index = -1,
  45. };
  46. /* Higher level TTY interface. */
  47. int simcons_tty_open (struct tty_struct *tty, struct file *filp)
  48. {
  49. return 0;
  50. }
  51. int simcons_tty_write (struct tty_struct *tty,
  52. const unsigned char *buf, int count)
  53. {
  54. return V850_SIM_SYSCALL (write, 1, buf, count);
  55. }
  56. int simcons_tty_write_room (struct tty_struct *tty)
  57. {
  58. /* Completely arbitrary. */
  59. return 0x100000;
  60. }
  61. int simcons_tty_chars_in_buffer (struct tty_struct *tty)
  62. {
  63. /* We have no buffer. */
  64. return 0;
  65. }
  66. static struct tty_operations ops = {
  67. .open = simcons_tty_open,
  68. .write = simcons_tty_write,
  69. .write_room = simcons_tty_write_room,
  70. .chars_in_buffer = simcons_tty_chars_in_buffer,
  71. };
  72. int __init simcons_tty_init (void)
  73. {
  74. struct tty_driver *driver = alloc_tty_driver(1);
  75. int err;
  76. if (!driver)
  77. return -ENOMEM;
  78. driver->name = "simcons";
  79. driver->major = TTY_MAJOR;
  80. driver->minor_start = 64;
  81. driver->type = TTY_DRIVER_TYPE_SYSCONS;
  82. driver->init_termios = tty_std_termios;
  83. tty_set_operations(driver, &ops);
  84. err = tty_register_driver(driver);
  85. if (err) {
  86. put_tty_driver(driver);
  87. return err;
  88. }
  89. tty_driver = driver;
  90. return 0;
  91. }
  92. /* We use `late_initcall' instead of just `__initcall' as a workaround for
  93. the fact that (1) simcons_tty_init can't be called before tty_init,
  94. (2) tty_init is called via `module_init', (3) if statically linked,
  95. module_init == device_init, and (4) there's no ordering of init lists.
  96. We can do this easily because simcons is always statically linked, but
  97. other tty drivers that depend on tty_init and which must use
  98. `module_init' to declare their init routines are likely to be broken. */
  99. late_initcall(simcons_tty_init);
  100. /* Poll for input on the console, and if there's any, deliver it to the
  101. tty driver. */
  102. void simcons_poll_tty (struct tty_struct *tty)
  103. {
  104. int flip = 0, send_break = 0;
  105. struct pollfd pfd;
  106. pfd.fd = 0;
  107. pfd.events = POLLIN;
  108. if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) {
  109. if (pfd.revents & POLLIN) {
  110. int left = TTY_FLIPBUF_SIZE - tty->flip.count;
  111. if (left > 0) {
  112. unsigned char *buf = tty->flip.char_buf_ptr;
  113. int rd = V850_SIM_SYSCALL (read, 0, buf, left);
  114. if (rd > 0) {
  115. tty->flip.count += rd;
  116. tty->flip.char_buf_ptr += rd;
  117. memset (tty->flip.flag_buf_ptr, 0, rd);
  118. tty->flip.flag_buf_ptr += rd;
  119. flip = 1;
  120. } else
  121. send_break = 1;
  122. }
  123. } else if (pfd.revents & POLLERR)
  124. send_break = 1;
  125. }
  126. if (send_break) {
  127. tty_insert_flip_char (tty, 0, TTY_BREAK);
  128. flip = 1;
  129. }
  130. if (flip)
  131. tty_schedule_flip (tty);
  132. }
  133. void simcons_poll_ttys (void)
  134. {
  135. if (tty_driver && tty_driver->ttys[0])
  136. simcons_poll_tty (tty_driver->ttys[0]);
  137. }
  138. void simcons_setup (void)
  139. {
  140. V850_SIM_SYSCALL (make_raw, 0);
  141. register_console (&simcons);
  142. printk (KERN_INFO "Console: GDB V850E simulator stdio\n");
  143. }