kmsg.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /* GNU Mach Kernel Message Device.
  2. Copyright (C) 1998, 1999, 2007 Free Software Foundation, Inc.
  3. Written by OKUJI Yoshinori.
  4. This is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This software is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with the software; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. /* kmsg provides a stream interface. */
  16. #include <sys/types.h>
  17. #include <string.h>
  18. #include <device/conf.h>
  19. #include <device/ds_routines.h>
  20. #include <device/io_req.h>
  21. #include <mach/boolean.h>
  22. #include <kern/lock.h>
  23. #include <device/kmsg.h>
  24. #define KMSGBUFSIZE (4096) /* XXX */
  25. /* Simple array for buffering messages */
  26. static char kmsg_buffer[KMSGBUFSIZE];
  27. /* Point to the offset to write */
  28. static int kmsg_write_offset;
  29. /* Point to the offset to read */
  30. static int kmsg_read_offset;
  31. /* I/O request queue for blocking read */
  32. static queue_head_t kmsg_read_queue;
  33. /* Used for exclusive access to the device */
  34. static boolean_t kmsg_in_use;
  35. /* Used for exclusive access to the routines */
  36. decl_simple_lock_data (static, kmsg_lock);
  37. /* If already initialized or not */
  38. static boolean_t kmsg_init_done = FALSE;
  39. /* Kernel Message Initializer */
  40. static void
  41. kmsginit (void)
  42. {
  43. kmsg_write_offset = 0;
  44. kmsg_read_offset = 0;
  45. queue_init (&kmsg_read_queue);
  46. kmsg_in_use = FALSE;
  47. simple_lock_init (&kmsg_lock);
  48. }
  49. /* Kernel Message Open Handler */
  50. io_return_t
  51. kmsgopen (dev_t dev, int flag, const io_req_t ior)
  52. {
  53. simple_lock (&kmsg_lock);
  54. if (kmsg_in_use)
  55. {
  56. simple_unlock (&kmsg_lock);
  57. return D_ALREADY_OPEN;
  58. }
  59. kmsg_in_use = TRUE;
  60. simple_unlock (&kmsg_lock);
  61. return D_SUCCESS;
  62. }
  63. /* Kernel Message Close Handler */
  64. void
  65. kmsgclose (dev_t dev, int flag)
  66. {
  67. simple_lock (&kmsg_lock);
  68. kmsg_in_use = FALSE;
  69. simple_unlock (&kmsg_lock);
  70. }
  71. static boolean_t kmsg_read_done (io_req_t ior);
  72. /* Kernel Message Read Handler */
  73. io_return_t
  74. kmsgread (dev_t dev, io_req_t ior)
  75. {
  76. int err;
  77. int amt, len;
  78. err = device_read_alloc (ior, ior->io_count);
  79. if (err != KERN_SUCCESS)
  80. return err;
  81. simple_lock (&kmsg_lock);
  82. if (kmsg_read_offset == kmsg_write_offset)
  83. {
  84. /* The queue is empty. */
  85. if (ior->io_mode & D_NOWAIT)
  86. {
  87. simple_unlock (&kmsg_lock);
  88. return D_WOULD_BLOCK;
  89. }
  90. ior->io_done = kmsg_read_done;
  91. enqueue_tail (&kmsg_read_queue, (queue_entry_t) ior);
  92. simple_unlock (&kmsg_lock);
  93. return D_IO_QUEUED;
  94. }
  95. len = kmsg_write_offset - kmsg_read_offset;
  96. if (len < 0)
  97. len += KMSGBUFSIZE;
  98. amt = ior->io_count;
  99. if (amt > len)
  100. amt = len;
  101. if (kmsg_read_offset + amt <= KMSGBUFSIZE)
  102. {
  103. memcpy (ior->io_data, kmsg_buffer + kmsg_read_offset, amt);
  104. }
  105. else
  106. {
  107. int cnt;
  108. cnt = KMSGBUFSIZE - kmsg_read_offset;
  109. memcpy (ior->io_data, kmsg_buffer + kmsg_read_offset, cnt);
  110. memcpy (ior->io_data + cnt, kmsg_buffer, amt - cnt);
  111. }
  112. kmsg_read_offset += amt;
  113. if (kmsg_read_offset >= KMSGBUFSIZE)
  114. kmsg_read_offset -= KMSGBUFSIZE;
  115. ior->io_residual = ior->io_count - amt;
  116. simple_unlock (&kmsg_lock);
  117. return D_SUCCESS;
  118. }
  119. static boolean_t
  120. kmsg_read_done (io_req_t ior)
  121. {
  122. int amt, len;
  123. simple_lock (&kmsg_lock);
  124. if (kmsg_read_offset == kmsg_write_offset)
  125. {
  126. /* The queue is empty. */
  127. ior->io_done = kmsg_read_done;
  128. enqueue_tail (&kmsg_read_queue, (queue_entry_t) ior);
  129. simple_unlock (&kmsg_lock);
  130. return FALSE;
  131. }
  132. len = kmsg_write_offset - kmsg_read_offset;
  133. if (len < 0)
  134. len += KMSGBUFSIZE;
  135. amt = ior->io_count;
  136. if (amt > len)
  137. amt = len;
  138. if (kmsg_read_offset + amt <= KMSGBUFSIZE)
  139. {
  140. memcpy (ior->io_data, kmsg_buffer + kmsg_read_offset, amt);
  141. }
  142. else
  143. {
  144. int cnt;
  145. cnt = KMSGBUFSIZE - kmsg_read_offset;
  146. memcpy (ior->io_data, kmsg_buffer + kmsg_read_offset, cnt);
  147. memcpy (ior->io_data + cnt, kmsg_buffer, amt - cnt);
  148. }
  149. kmsg_read_offset += amt;
  150. if (kmsg_read_offset >= KMSGBUFSIZE)
  151. kmsg_read_offset -= KMSGBUFSIZE;
  152. ior->io_residual = ior->io_count - amt;
  153. simple_unlock (&kmsg_lock);
  154. ds_read_done (ior);
  155. return TRUE;
  156. }
  157. io_return_t
  158. kmsggetstat (dev_t dev, int flavor, int *data, unsigned int *count)
  159. {
  160. switch (flavor)
  161. {
  162. case DEV_GET_SIZE:
  163. data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
  164. data[DEV_GET_SIZE_RECORD_SIZE] = 1;
  165. *count = DEV_GET_SIZE_COUNT;
  166. break;
  167. default:
  168. return D_INVALID_OPERATION;
  169. }
  170. return D_SUCCESS;
  171. }
  172. /* Write to Kernel Message Buffer */
  173. void
  174. kmsg_putchar (int c)
  175. {
  176. io_req_t ior;
  177. int offset;
  178. /* XXX: cninit is not called before cnputc is used. So call kmsginit
  179. here if not initialized yet. */
  180. if (!kmsg_init_done)
  181. {
  182. kmsginit ();
  183. kmsg_init_done = TRUE;
  184. }
  185. simple_lock (&kmsg_lock);
  186. offset = kmsg_write_offset + 1;
  187. if (offset == KMSGBUFSIZE)
  188. offset = 0;
  189. if (offset == kmsg_read_offset)
  190. {
  191. /* Discard C. */
  192. simple_unlock (&kmsg_lock);
  193. return;
  194. }
  195. kmsg_buffer[kmsg_write_offset++] = c;
  196. if (kmsg_write_offset == KMSGBUFSIZE)
  197. kmsg_write_offset = 0;
  198. while ((ior = (io_req_t) dequeue_head (&kmsg_read_queue)) != NULL)
  199. iodone (ior);
  200. simple_unlock (&kmsg_lock);
  201. }