fci_ringbuffer.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*****************************************************************************
  2. Copyright(c) 2013 FCI Inc. All Rights Reserved
  3. File name : fci_ringbuffer.c
  4. Description : source of data buffer control
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. History :
  17. ----------------------------------------------------------------------
  18. 2010/11/25 aslan.cho initial
  19. *******************************************************************************/
  20. #include <linux/errno.h>
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/sched.h>
  24. #include <linux/string.h>
  25. #include <linux/uaccess.h>
  26. #include "fci_ringbuffer.h"
  27. #define PKT_READY 0
  28. #define PKT_DISPOSED 1
  29. void fci_ringbuffer_init(struct fci_ringbuffer *rbuf, void *data, size_t len)
  30. {
  31. rbuf->pread = rbuf->pwrite = 0;
  32. rbuf->data = data;
  33. rbuf->size = len;
  34. rbuf->error = 0;
  35. init_waitqueue_head(&rbuf->queue);
  36. spin_lock_init(&(rbuf->lock));
  37. }
  38. int fci_ringbuffer_empty(struct fci_ringbuffer *rbuf)
  39. {
  40. return (rbuf->pread == rbuf->pwrite);
  41. }
  42. ssize_t fci_ringbuffer_free(struct fci_ringbuffer *rbuf)
  43. {
  44. ssize_t free;
  45. free = rbuf->pread - rbuf->pwrite;
  46. if (free <= 0)
  47. free += rbuf->size;
  48. return free-1;
  49. }
  50. ssize_t fci_ringbuffer_avail(struct fci_ringbuffer *rbuf)
  51. {
  52. ssize_t avail;
  53. avail = rbuf->pwrite - rbuf->pread;
  54. if (avail < 0)
  55. avail += rbuf->size;
  56. return avail;
  57. }
  58. void fci_ringbuffer_flush(struct fci_ringbuffer *rbuf)
  59. {
  60. rbuf->pread = rbuf->pwrite;
  61. rbuf->error = 0;
  62. }
  63. void fci_ringbuffer_reset(struct fci_ringbuffer *rbuf)
  64. {
  65. rbuf->pread = rbuf->pwrite = 0;
  66. rbuf->error = 0;
  67. }
  68. void fci_ringbuffer_flush_spinlock_wakeup(struct fci_ringbuffer *rbuf)
  69. {
  70. unsigned long flags;
  71. spin_lock_irqsave(&rbuf->lock, flags);
  72. fci_ringbuffer_flush(rbuf);
  73. spin_unlock_irqrestore(&rbuf->lock, flags);
  74. wake_up(&rbuf->queue);
  75. }
  76. ssize_t fci_ringbuffer_read_user(struct fci_ringbuffer *rbuf
  77. , u8 __user *buf, size_t len)
  78. {
  79. size_t todo = len;
  80. size_t split;
  81. split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
  82. if (split > 0) {
  83. if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
  84. return -EFAULT;
  85. buf += split;
  86. todo -= split;
  87. rbuf->pread = 0;
  88. }
  89. if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
  90. return -EFAULT;
  91. rbuf->pread = (rbuf->pread + todo) % rbuf->size;
  92. return len;
  93. }
  94. void fci_ringbuffer_read(struct fci_ringbuffer *rbuf, u8 *buf, size_t len)
  95. {
  96. size_t todo = len;
  97. size_t split;
  98. split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
  99. if (split > 0) {
  100. memcpy(buf, rbuf->data+rbuf->pread, split);
  101. buf += split;
  102. todo -= split;
  103. rbuf->pread = 0;
  104. }
  105. memcpy(buf, rbuf->data+rbuf->pread, todo);
  106. rbuf->pread = (rbuf->pread + todo) % rbuf->size;
  107. }
  108. ssize_t fci_ringbuffer_write(struct fci_ringbuffer *rbuf
  109. , const u8 *buf, size_t len)
  110. {
  111. size_t todo = len;
  112. size_t split;
  113. split = (rbuf->pwrite + len > rbuf->size)
  114. ? rbuf->size - rbuf->pwrite : 0;
  115. if (split > 0) {
  116. memcpy(rbuf->data+rbuf->pwrite, buf, split);
  117. buf += split;
  118. todo -= split;
  119. rbuf->pwrite = 0;
  120. }
  121. memcpy(rbuf->data+rbuf->pwrite, buf, todo);
  122. rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
  123. return len;
  124. }
  125. ssize_t fci_ringbuffer_pkt_write(struct fci_ringbuffer *rbuf
  126. , u8 *buf, size_t len)
  127. {
  128. int status;
  129. ssize_t oldpwrite = rbuf->pwrite;
  130. FCI_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
  131. FCI_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
  132. FCI_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
  133. status = fci_ringbuffer_write(rbuf, buf, len);
  134. if (status < 0)
  135. rbuf->pwrite = oldpwrite;
  136. return status;
  137. }
  138. ssize_t fci_ringbuffer_pkt_read_user(struct fci_ringbuffer *rbuf, size_t idx,
  139. int offset, u8 __user *buf, size_t len)
  140. {
  141. size_t todo;
  142. size_t split;
  143. size_t pktlen;
  144. pktlen = rbuf->data[idx] << 8;
  145. pktlen |= rbuf->data[(idx + 1) % rbuf->size];
  146. if (offset > pktlen)
  147. return -EINVAL;
  148. if ((offset + len) > pktlen)
  149. len = pktlen - offset;
  150. idx = (idx + FCI_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
  151. todo = len;
  152. split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
  153. if (split > 0) {
  154. if (copy_to_user(buf, rbuf->data+idx, split))
  155. return -EFAULT;
  156. buf += split;
  157. todo -= split;
  158. idx = 0;
  159. }
  160. if (copy_to_user(buf, rbuf->data+idx, todo))
  161. return -EFAULT;
  162. return len;
  163. }
  164. ssize_t fci_ringbuffer_pkt_read(struct fci_ringbuffer *rbuf, size_t idx,
  165. int offset, u8 *buf, size_t len)
  166. {
  167. size_t todo;
  168. size_t split;
  169. size_t pktlen;
  170. pktlen = rbuf->data[idx] << 8;
  171. pktlen |= rbuf->data[(idx + 1) % rbuf->size];
  172. if (offset > pktlen)
  173. return -EINVAL;
  174. if ((offset + len) > pktlen)
  175. len = pktlen - offset;
  176. idx = (idx + FCI_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
  177. todo = len;
  178. split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
  179. if (split > 0) {
  180. memcpy(buf, rbuf->data+idx, split);
  181. buf += split;
  182. todo -= split;
  183. idx = 0;
  184. }
  185. memcpy(buf, rbuf->data+idx, todo);
  186. return len;
  187. }
  188. void fci_ringbuffer_pkt_dispose(struct fci_ringbuffer *rbuf, size_t idx)
  189. {
  190. size_t pktlen;
  191. rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
  192. while (fci_ringbuffer_avail(rbuf) > FCI_RINGBUFFER_PKTHDRSIZE) {
  193. if (FCI_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
  194. pktlen = FCI_RINGBUFFER_PEEK(rbuf, 0) << 8;
  195. pktlen |= FCI_RINGBUFFER_PEEK(rbuf, 1);
  196. FCI_RINGBUFFER_SKIP(rbuf
  197. , pktlen + FCI_RINGBUFFER_PKTHDRSIZE);
  198. } else
  199. break;
  200. }
  201. }
  202. ssize_t fci_ringbuffer_pkt_next(struct fci_ringbuffer *rbuf
  203. , size_t idx, size_t *pktlen)
  204. {
  205. int consumed;
  206. int curpktlen;
  207. int curpktstatus;
  208. if (idx == -1)
  209. idx = rbuf->pread;
  210. else {
  211. curpktlen = rbuf->data[idx] << 8;
  212. curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
  213. idx = (idx + curpktlen + FCI_RINGBUFFER_PKTHDRSIZE)
  214. % rbuf->size;
  215. }
  216. consumed = (idx - rbuf->pread) % rbuf->size;
  217. while ((fci_ringbuffer_avail(rbuf) - consumed)
  218. > FCI_RINGBUFFER_PKTHDRSIZE) {
  219. curpktlen = rbuf->data[idx] << 8;
  220. curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
  221. curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
  222. if (curpktstatus == PKT_READY) {
  223. *pktlen = curpktlen;
  224. return idx;
  225. }
  226. consumed += curpktlen + FCI_RINGBUFFER_PKTHDRSIZE;
  227. idx = (idx + curpktlen + FCI_RINGBUFFER_PKTHDRSIZE)
  228. % rbuf->size;
  229. }
  230. return -1;
  231. }