vbus.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /*
  2. * VMM Bus
  3. *
  4. * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd
  5. * http://www.rt-thread.com
  6. *
  7. * This file is part of RT-Thread (http://www.rt-thread.org)
  8. *
  9. * All rights reserved.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  24. *
  25. * Change Logs:
  26. * Date Author Notes
  27. * 2013-11-04 Grissiom add comment
  28. */
  29. #include <rthw.h>
  30. #include <rtthread.h>
  31. #include <rtdevice.h>
  32. #include "vbus.h"
  33. #include "prio_queue.h"
  34. #include "vbus_hw.h"
  35. //#define RT_VBUS_STATISTICS
  36. #define RT_VBUS_RB_LOW_TICK (RT_VMM_RB_BLK_NR * 2 / 3)
  37. #define RT_VBUS_RB_TICK_STEP (100)
  38. #ifndef RT_USING_LOGTRACE
  39. /* console could be run on vbus. If we log on it, there will be oops. */
  40. #define vbus_debug(...)
  41. #define vbus_verbose(...)
  42. #define vbus_info(...)
  43. #define vbus_error(...)
  44. #else // have RT_USING_LOGTRACE
  45. #include <log_trace.h>
  46. #if defined(log_session_lvl)
  47. /* Define log_trace_session as const so the compiler could optimize some log
  48. * out. */
  49. const static struct log_trace_session _lgs = {
  50. .id = {.name = "vbus"},
  51. .lvl = LOG_TRACE_LEVEL_VERBOSE,
  52. };
  53. #define vbus_debug(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
  54. #define vbus_verbose(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_VERBOSE, fmt, ##__VA_ARGS__)
  55. #define vbus_info(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_INFO, fmt, ##__VA_ARGS__)
  56. #define vbus_error(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_ERROR, fmt, ##__VA_ARGS__)
  57. #else
  58. static struct log_trace_session _lgs = {
  59. .id = {.name = "vbus"},
  60. .lvl = LOG_TRACE_LEVEL_VERBOSE,
  61. };
  62. #define vbus_debug(fmt, ...) log_session(&_lgs, LOG_TRACE_DEBUG""fmt, ##__VA_ARGS__)
  63. #define vbus_verbose(fmt, ...) log_session(&_lgs, LOG_TRACE_VERBOSE""fmt, ##__VA_ARGS__)
  64. #define vbus_info(fmt, ...) log_session(&_lgs, LOG_TRACE_INFO""fmt, ##__VA_ARGS__)
  65. #define vbus_error(fmt, ...) log_session(&_lgs, LOG_TRACE_ERROR""fmt, ##__VA_ARGS__)
  66. #endif
  67. #endif // RT_USING_LOGTRACE
  68. #ifndef ARRAY_SIZE
  69. #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
  70. #endif
  71. struct rt_vbus_ring *RT_VBUS_OUT_RING;
  72. struct rt_vbus_ring *RT_VBUS_IN_RING;
  73. const char *rt_vbus_chn_st2str[] = {
  74. "available",
  75. "closed",
  76. "establishing",
  77. "established",
  78. "suspended",
  79. "closing",
  80. };
  81. const char *rt_vbus_sess_st2str[] = {
  82. "available",
  83. "listening",
  84. "establishing",
  85. };
  86. const char *rt_vbus_cmd2str[] = {
  87. "ENABLE",
  88. "DISABLE",
  89. "SET",
  90. "ACK",
  91. "NAK",
  92. "SUSPEND",
  93. "RESUME",
  94. };
  95. static char* dump_cmd_pkt(unsigned char *dp, size_t dsize);
  96. /* 4 bytes for the head */
  97. #define LEN2BNR(len) ((len + RT_VBUS_BLK_HEAD_SZ \
  98. + sizeof(struct rt_vbus_blk) - 1) \
  99. / sizeof(struct rt_vbus_blk))
  100. rt_inline void _ring_add_get_bnr(struct rt_vbus_ring *ring,
  101. rt_size_t bnr)
  102. {
  103. int nidx = ring->get_idx + bnr;
  104. if (nidx >= RT_VMM_RB_BLK_NR)
  105. {
  106. nidx -= RT_VMM_RB_BLK_NR;
  107. }
  108. rt_vbus_smp_wmb();
  109. ring->get_idx = nidx;
  110. }
  111. rt_inline int _bus_ring_space_nr(struct rt_vbus_ring *rg)
  112. {
  113. int delta;
  114. rt_vbus_smp_rmb();
  115. delta = rg->get_idx - rg->put_idx;
  116. if (delta > 0)
  117. {
  118. /* Put is behind the get. */
  119. return delta - 1;
  120. }
  121. else
  122. {
  123. /* delta is negative. */
  124. return RT_VMM_RB_BLK_NR + delta - 1;
  125. }
  126. }
  127. struct rt_vbus_pkg {
  128. rt_uint8_t id;
  129. rt_uint8_t prio;
  130. rt_uint8_t finished;
  131. rt_uint8_t len;
  132. const void *data;
  133. };
  134. /* chn0 is always connected */
  135. static enum rt_vbus_chn_status _chn_status[RT_VBUS_CHANNEL_NR];
  136. rt_inline int _chn_connected(unsigned char chnr)
  137. {
  138. return _chn_status[chnr] == RT_VBUS_CHN_ST_ESTABLISHED ||
  139. _chn_status[chnr] == RT_VBUS_CHN_ST_SUSPEND;
  140. }
  141. #ifdef RT_VBUS_USING_FLOW_CONTROL
  142. #include <watermark_queue.h>
  143. struct rt_watermark_queue _chn_wm_que[RT_VBUS_CHANNEL_NR];
  144. void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high)
  145. {
  146. RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_wm_que)));
  147. rt_wm_que_set_mark(&_chn_wm_que[chnr], low, high);
  148. }
  149. /* Threads suspended by the flow control of other side. */
  150. rt_list_t _chn_suspended_threads[RT_VBUS_CHANNEL_NR];
  151. struct
  152. {
  153. unsigned int level;
  154. unsigned int high_mark;
  155. unsigned int low_mark;
  156. /* The suspend command does not have ACK. So if the other side still
  157. * sending pkg after SUSPEND, warn it again. Also use it as a flag that
  158. * tell me whether are we dropping from the high mark or not when reaching
  159. * the low mark. */
  160. unsigned int last_warn;
  161. } _chn_recv_wm[RT_VBUS_CHANNEL_NR];
  162. void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high)
  163. {
  164. RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_recv_wm)));
  165. _chn_recv_wm[chnr].low_mark = low;
  166. _chn_recv_wm[chnr].high_mark = high;
  167. }
  168. #else
  169. void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high)
  170. {}
  171. void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high)
  172. {}
  173. #endif
  174. struct {
  175. rt_vbus_event_listener indicate;
  176. void *ctx;
  177. } _vbus_rx_indi[RT_VBUS_EVENT_ID_MAX][RT_VBUS_CHANNEL_NR];
  178. void rt_vbus_register_listener(unsigned char chnr,
  179. enum rt_vbus_event_id eve,
  180. rt_vbus_event_listener indi,
  181. void *ctx)
  182. {
  183. RT_ASSERT(chnr != 0 && chnr < RT_VBUS_CHANNEL_NR);
  184. RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0]));
  185. _vbus_rx_indi[eve][chnr].indicate = indi;
  186. _vbus_rx_indi[eve][chnr].ctx = ctx;
  187. }
  188. static void _vbus_indicate(enum rt_vbus_event_id eve, unsigned char chnr)
  189. {
  190. RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0]));
  191. if (_vbus_rx_indi[eve][chnr].indicate)
  192. _vbus_rx_indi[eve][chnr].indicate(_vbus_rx_indi[eve][chnr].ctx);
  193. }
  194. #define _BUS_OUT_THRD_STACK_SZ 2048
  195. #define _BUS_OUT_THRD_PRIO 8
  196. #define _BUS_OUT_PKG_NR RT_VMM_RB_BLK_NR
  197. static struct rt_thread _bus_out_thread;
  198. static rt_uint8_t _bus_out_thread_stack[_BUS_OUT_THRD_STACK_SZ];
  199. struct rt_prio_queue *_bus_out_que;
  200. static void _bus_out_entry(void *param)
  201. {
  202. struct rt_vbus_pkg dpkg;
  203. _bus_out_que = rt_prio_queue_create("vbus",
  204. _BUS_OUT_PKG_NR,
  205. sizeof(struct rt_vbus_pkg));
  206. if (!_bus_out_que)
  207. {
  208. rt_kprintf("could not create vmm bus queue\n");
  209. return;
  210. }
  211. while (rt_prio_queue_pop(_bus_out_que, &dpkg,
  212. RT_WAITING_FOREVER) == RT_EOK)
  213. {
  214. int sp;
  215. rt_uint32_t nxtidx;
  216. const int dnr = LEN2BNR(dpkg.len);
  217. #ifdef RT_VBUS_USING_FLOW_CONTROL
  218. rt_wm_que_dec(&_chn_wm_que[dpkg.id]);
  219. #endif
  220. if (!_chn_connected(dpkg.id))
  221. continue;
  222. sp = _bus_ring_space_nr(RT_VBUS_OUT_RING);
  223. vbus_debug("vmm bus out"
  224. "(data: %p, len: %d, prio: %d, id: %d)\n",
  225. dpkg.data, dpkg.len, dpkg.prio, dpkg.id);
  226. /* wait for enough space */
  227. while (sp < dnr)
  228. {
  229. rt_ubase_t lvl = rt_hw_interrupt_disable();
  230. RT_VBUS_OUT_RING->blocked = 1;
  231. rt_vbus_smp_wmb();
  232. /* kick the guest, hoping this could force it do the work */
  233. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  234. rt_thread_suspend(rt_thread_self());
  235. rt_schedule();
  236. RT_VBUS_OUT_RING->blocked = 0;
  237. rt_hw_interrupt_enable(lvl);
  238. sp = _bus_ring_space_nr(RT_VBUS_OUT_RING);
  239. }
  240. nxtidx = RT_VBUS_OUT_RING->put_idx + dnr;
  241. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].id = dpkg.id;
  242. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].qos = dpkg.prio;
  243. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].len = dpkg.len;
  244. if (nxtidx >= RT_VMM_RB_BLK_NR)
  245. {
  246. unsigned int tailsz;
  247. tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_OUT_RING->put_idx)
  248. * sizeof(RT_VBUS_OUT_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ;
  249. /* the remaining block is sufficient for the data */
  250. if (tailsz > dpkg.len)
  251. tailsz = dpkg.len;
  252. rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data,
  253. dpkg.data, tailsz);
  254. rt_memcpy(&RT_VBUS_OUT_RING->blks[0],
  255. ((char*)dpkg.data)+tailsz,
  256. dpkg.len - tailsz);
  257. rt_vbus_smp_wmb();
  258. RT_VBUS_OUT_RING->put_idx = nxtidx - RT_VMM_RB_BLK_NR;
  259. }
  260. else
  261. {
  262. rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data,
  263. dpkg.data, dpkg.len);
  264. rt_vbus_smp_wmb();
  265. RT_VBUS_OUT_RING->put_idx = nxtidx;
  266. }
  267. rt_vbus_smp_wmb();
  268. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  269. if (dpkg.finished)
  270. {
  271. _vbus_indicate(RT_VBUS_EVENT_ID_TX, dpkg.id);
  272. }
  273. }
  274. RT_ASSERT(0);
  275. }
  276. void rt_vbus_resume_out_thread(void)
  277. {
  278. rt_thread_resume(&_bus_out_thread);
  279. rt_schedule();
  280. }
  281. rt_err_t rt_vbus_post(rt_uint8_t id,
  282. rt_uint8_t prio,
  283. const void *data,
  284. rt_size_t size,
  285. rt_int32_t timeout)
  286. {
  287. rt_err_t err = RT_EOK;
  288. struct rt_vbus_pkg pkg;
  289. unsigned int putsz;
  290. const unsigned char *dp;
  291. if (!_bus_out_que)
  292. {
  293. rt_kprintf("post (data: %p, size: %d, timeout: %d) "
  294. "to bus before initialition\n",
  295. data, size, timeout);
  296. return -RT_ERROR;
  297. }
  298. if (id >= RT_VBUS_CHANNEL_NR)
  299. return -RT_ERROR;
  300. if (timeout != 0)
  301. {
  302. RT_DEBUG_IN_THREAD_CONTEXT;
  303. }
  304. #ifdef RT_VBUS_USING_FLOW_CONTROL
  305. while (_chn_status[id] == RT_VBUS_CHN_ST_SUSPEND)
  306. {
  307. rt_thread_t thread;
  308. if (timeout == 0)
  309. {
  310. return -RT_EFULL;
  311. }
  312. thread = rt_thread_self();
  313. thread->error = RT_EOK;
  314. /* We only touch the _chn_suspended_threads in thread, so lock the
  315. * scheduler is enough. */
  316. rt_enter_critical();
  317. rt_thread_suspend(thread);
  318. rt_list_insert_after(&_chn_suspended_threads[id], &thread->tlist);
  319. if (timeout > 0)
  320. {
  321. rt_timer_control(&(thread->thread_timer),
  322. RT_TIMER_CTRL_SET_TIME,
  323. &timeout);
  324. rt_timer_start(&(thread->thread_timer));
  325. }
  326. /* rt_exit_critical will do schedule on need. */
  327. rt_exit_critical();
  328. if (thread->error != RT_EOK)
  329. return thread->error;
  330. }
  331. #endif
  332. if (_chn_status[id] != RT_VBUS_CHN_ST_ESTABLISHED)
  333. return -RT_ERROR;
  334. dp = data;
  335. pkg.id = id;
  336. pkg.prio = prio;
  337. for (putsz = 0; size; size -= putsz)
  338. {
  339. pkg.data = dp;
  340. if (size > RT_VBUS_MAX_PKT_SZ)
  341. {
  342. putsz = RT_VBUS_MAX_PKT_SZ;
  343. pkg.finished = 0;
  344. }
  345. else
  346. {
  347. putsz = size;
  348. pkg.finished = 1;
  349. }
  350. pkg.len = putsz;
  351. dp += putsz;
  352. #ifdef RT_VBUS_USING_FLOW_CONTROL
  353. err = rt_wm_que_inc(&_chn_wm_que[id], timeout);
  354. if (err != RT_EOK)
  355. break;
  356. #endif
  357. vbus_debug("post (data: %p(%d), size: %d, finshed: %d, timeout: %d)\n",
  358. pkg.data, ((unsigned char*)pkg.data)[0],
  359. pkg.len, pkg.finished, timeout);
  360. err = rt_prio_queue_push(_bus_out_que, prio, &pkg, timeout);
  361. if (err != RT_EOK)
  362. break;
  363. }
  364. return err;
  365. }
  366. struct rt_completion _chn0_post_cmp;
  367. void _chn0_tx_listener(void *p)
  368. {
  369. rt_completion_done(&_chn0_post_cmp);
  370. }
  371. /* Posts in channel0 should be sync. */
  372. static rt_err_t _chn0_post(const void *data,
  373. rt_size_t size,
  374. int timeout)
  375. {
  376. rt_err_t err;
  377. rt_completion_init(&_chn0_post_cmp);
  378. err = rt_vbus_post(0, 0, data, size, timeout);
  379. if (err != RT_EOK)
  380. return err;
  381. return rt_completion_wait(&_chn0_post_cmp, timeout);
  382. }
  383. #define _BUS_IN_THRD_STACK_SZ 1024
  384. #define _BUS_IN_THRD_PRIO (_BUS_OUT_THRD_PRIO+1)
  385. #if (_BUS_IN_THRD_PRIO == RT_THREAD_PRIORITY_MAX)
  386. #error "_BUS_OUT_THRD_PRIO too low"
  387. #endif
  388. static struct rt_thread _bus_in_thread;
  389. static rt_uint8_t _bus_in_thread_stack[_BUS_OUT_THRD_STACK_SZ];
  390. static struct rt_semaphore _bus_in_sem;
  391. static struct rt_event _bus_in_event;
  392. /* {head, tail} */
  393. #define _IN_ACT_HEAD 0
  394. #define _IN_ACT_TAIL 1
  395. static struct rt_vbus_data *_bus_in_action[RT_VBUS_CHANNEL_NR][2];
  396. #ifdef RT_VBUS_STATISTICS
  397. static unsigned int _bus_in_action_nr[RT_VBUS_CHANNEL_NR];
  398. #endif
  399. static void rt_vbus_notify_chn(unsigned char chnr, rt_err_t err)
  400. {
  401. #ifdef RT_VBUS_USING_FLOW_CONTROL
  402. /* TODO: get rid of this */
  403. /* Protect the list. */
  404. rt_enter_critical();
  405. while (!rt_list_isempty(&_chn_suspended_threads[chnr]))
  406. {
  407. rt_thread_t thread;
  408. thread = rt_list_entry(_chn_suspended_threads[chnr].next,
  409. struct rt_thread,
  410. tlist);
  411. thread->error = err;
  412. rt_thread_resume(thread);
  413. }
  414. rt_exit_critical();
  415. #endif
  416. rt_event_send(&_bus_in_event, 1 << chnr);
  417. }
  418. static void rt_vbus_notify_set(rt_uint32_t set)
  419. {
  420. rt_event_send(&_bus_in_event, set);
  421. }
  422. rt_err_t rt_vbus_listen_on(rt_uint8_t chnr,
  423. rt_int32_t timeout)
  424. {
  425. rt_uint32_t notuse;
  426. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR || !_chn_connected(chnr))
  427. return -RT_EIO;
  428. return rt_event_recv(&_bus_in_event, 1 << chnr,
  429. RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  430. timeout, &notuse);
  431. }
  432. void rt_vbus_data_push(unsigned int id, struct rt_vbus_data *act)
  433. {
  434. rt_ubase_t lvl;
  435. RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR);
  436. lvl = rt_hw_interrupt_disable();
  437. if (_bus_in_action[id][_IN_ACT_HEAD] == RT_NULL)
  438. {
  439. _bus_in_action[id][_IN_ACT_HEAD] = act;
  440. _bus_in_action[id][_IN_ACT_TAIL] = act;
  441. }
  442. else
  443. {
  444. _bus_in_action[id][_IN_ACT_TAIL]->next = act;
  445. _bus_in_action[id][_IN_ACT_TAIL] = act;
  446. }
  447. #ifdef RT_VBUS_STATISTICS
  448. _bus_in_action_nr[id]++;
  449. #endif
  450. rt_hw_interrupt_enable(lvl);
  451. #ifdef RT_VBUS_USING_FLOW_CONTROL
  452. _chn_recv_wm[id].level++;
  453. if (_chn_recv_wm[id].level == 0)
  454. _chn_recv_wm[id].level = ~0;
  455. if (_chn_recv_wm[id].level > _chn_recv_wm[id].high_mark &&
  456. _chn_recv_wm[id].level > _chn_recv_wm[id].last_warn)
  457. {
  458. unsigned char buf[2];
  459. buf[0] = RT_VBUS_CHN0_CMD_SUSPEND;
  460. buf[1] = id;
  461. vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  462. _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER);
  463. /* Warn the other side in 100 more pkgs. */
  464. _chn_recv_wm[id].last_warn = _chn_recv_wm[id].level + 100;
  465. }
  466. #endif
  467. }
  468. struct rt_vbus_data* rt_vbus_data_pop(unsigned int id)
  469. {
  470. struct rt_vbus_data *act;
  471. rt_ubase_t lvl;
  472. RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR);
  473. lvl = rt_hw_interrupt_disable();
  474. act = _bus_in_action[id][_IN_ACT_HEAD];
  475. if (act)
  476. {
  477. _bus_in_action[id][_IN_ACT_HEAD] = act->next;
  478. }
  479. rt_hw_interrupt_enable(lvl);
  480. #ifdef RT_VBUS_USING_FLOW_CONTROL
  481. if (_chn_recv_wm[id].level != 0)
  482. {
  483. _chn_recv_wm[id].level--;
  484. if (_chn_recv_wm[id].level <= _chn_recv_wm[id].low_mark &&
  485. _chn_recv_wm[id].last_warn > _chn_recv_wm[id].low_mark)
  486. {
  487. unsigned char buf[2];
  488. buf[0] = RT_VBUS_CHN0_CMD_RESUME;
  489. buf[1] = id;
  490. vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  491. _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER);
  492. _chn_recv_wm[id].last_warn = 0;
  493. }
  494. }
  495. #endif
  496. return act;
  497. }
  498. /* dump cmd that is not start with ACK/NAK */
  499. static size_t __dump_naked_cmd(char *dst, size_t lsize,
  500. unsigned char *dp, size_t dsize)
  501. {
  502. size_t len;
  503. if (dp[0] == RT_VBUS_CHN0_CMD_DISABLE ||
  504. dp[0] == RT_VBUS_CHN0_CMD_SUSPEND ||
  505. dp[0] == RT_VBUS_CHN0_CMD_RESUME)
  506. {
  507. len = rt_snprintf(dst, lsize, "%s %d",
  508. rt_vbus_cmd2str[dp[0]], dp[1]);
  509. }
  510. else if (dp[0] == RT_VBUS_CHN0_CMD_ENABLE)
  511. {
  512. len = rt_snprintf(dst, lsize, "%s %s",
  513. rt_vbus_cmd2str[dp[0]], dp+1);
  514. }
  515. else if (dp[0] < RT_VBUS_CHN0_CMD_MAX)
  516. {
  517. len = rt_snprintf(dst, lsize, "%s %s %d",
  518. rt_vbus_cmd2str[dp[0]],
  519. dp+1, dp[2+rt_strlen((char*)dp+1)]);
  520. }
  521. else
  522. {
  523. len = rt_snprintf(dst, lsize, "(invalid)%d %d",
  524. dp[0], dp[1]);
  525. }
  526. return len;
  527. }
  528. static char _cmd_dump_buf[64];
  529. static char* dump_cmd_pkt(unsigned char *dp, size_t dsize)
  530. {
  531. size_t len;
  532. if (dp[0] == RT_VBUS_CHN0_CMD_ACK || dp[0] == RT_VBUS_CHN0_CMD_NAK )
  533. {
  534. len = rt_snprintf(_cmd_dump_buf, sizeof(_cmd_dump_buf),
  535. "%s ", rt_vbus_cmd2str[dp[0]]);
  536. len += __dump_naked_cmd(_cmd_dump_buf+len, sizeof(_cmd_dump_buf)-len,
  537. dp+1, dsize-1);
  538. }
  539. else
  540. {
  541. len = __dump_naked_cmd(_cmd_dump_buf, sizeof(_cmd_dump_buf),
  542. dp, dsize);
  543. }
  544. if (len > sizeof(_cmd_dump_buf) - 1)
  545. len = sizeof(_cmd_dump_buf) - 1;
  546. _cmd_dump_buf[len] = '\0';
  547. return _cmd_dump_buf;
  548. }
  549. static rt_err_t _chn0_echo_with(rt_uint8_t prefix,
  550. rt_uint32_t dsize,
  551. unsigned char *dp)
  552. {
  553. rt_err_t err;
  554. unsigned char *resp;
  555. resp = rt_malloc(dsize+1);
  556. if (!resp)
  557. return -RT_ENOMEM;
  558. *resp = prefix;
  559. rt_memcpy(resp+1, dp, dsize);
  560. vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1));
  561. err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER);
  562. rt_free(resp);
  563. return err;
  564. }
  565. static rt_err_t _chn0_nak(rt_uint32_t dsize, unsigned char *dp)
  566. {
  567. return _chn0_echo_with(RT_VBUS_CHN0_CMD_NAK, dsize, dp);
  568. }
  569. static rt_err_t _chn0_ack(rt_uint32_t dsize, unsigned char *dp)
  570. {
  571. return _chn0_echo_with(RT_VBUS_CHN0_CMD_ACK, dsize, dp);
  572. }
  573. enum _vbus_session_st
  574. {
  575. SESSIOM_AVAILABLE,
  576. SESSIOM_LISTENING,
  577. SESSIOM_ESTABLISHING,
  578. };
  579. struct rt_vbus_conn_session
  580. {
  581. /* negative value means error */
  582. int chnr;
  583. enum _vbus_session_st st;
  584. struct rt_completion cmp;
  585. struct rt_vbus_request *req;
  586. };
  587. static struct rt_vbus_conn_session _sess[RT_VBUS_CHANNEL_NR/2];
  588. static int _sess_find(const unsigned char *name,
  589. enum _vbus_session_st st)
  590. {
  591. int i;
  592. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  593. {
  594. if (_sess[i].st == st && _sess[i].req->name &&
  595. rt_strcmp(_sess[i].req->name, (char*)name) == 0)
  596. break;
  597. }
  598. return i;
  599. }
  600. static int _chn0_actor(unsigned char *dp, size_t dsize)
  601. {
  602. if (*dp != RT_VBUS_CHN0_CMD_SUSPEND && *dp != RT_VBUS_CHN0_CMD_RESUME)
  603. vbus_verbose("local <-- %s\n", dump_cmd_pkt(dp, dsize));
  604. switch (*dp)
  605. {
  606. case RT_VBUS_CHN0_CMD_ENABLE:
  607. {
  608. int i, chnr;
  609. rt_err_t err;
  610. unsigned char *resp;
  611. i = _sess_find(dp+1, SESSIOM_LISTENING);
  612. if (i == ARRAY_SIZE(_sess))
  613. {
  614. _chn0_nak(dsize, dp);
  615. break;
  616. }
  617. for (chnr = 0; chnr < ARRAY_SIZE(_chn_status); chnr++)
  618. {
  619. if (_chn_status[chnr] == RT_VBUS_CHN_ST_AVAILABLE)
  620. break;
  621. }
  622. if (chnr == ARRAY_SIZE(_chn_status))
  623. {
  624. _chn0_nak(dsize, dp);
  625. break;
  626. }
  627. resp = rt_malloc(dsize + 1);
  628. if (!resp)
  629. break;
  630. *resp = RT_VBUS_CHN0_CMD_SET;
  631. rt_memcpy(resp+1, dp+1, dsize-1);
  632. resp[dsize] = chnr;
  633. rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high);
  634. rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high);
  635. vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1));
  636. err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER);
  637. if (err == RT_EOK)
  638. {
  639. _sess[i].st = SESSIOM_ESTABLISHING;
  640. vbus_debug("set sess %d st: %s\n", i,
  641. rt_vbus_sess_st2str[_sess[i].st]);
  642. _sess[i].chnr = chnr;
  643. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHING;
  644. }
  645. rt_free(resp);
  646. }
  647. break;
  648. case RT_VBUS_CHN0_CMD_SET:
  649. {
  650. int i, chnr;
  651. i = _sess_find(dp+1, SESSIOM_ESTABLISHING);
  652. if (i == ARRAY_SIZE(_sess))
  653. {
  654. vbus_verbose("drop spurious packet\n");
  655. break;
  656. }
  657. chnr = dp[1+rt_strlen((const char*)dp+1)+1];
  658. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  659. {
  660. vbus_verbose("SET wrong chnr %d\n", chnr);
  661. break;
  662. }
  663. if (_chn_status[chnr] != RT_VBUS_CHN_ST_AVAILABLE)
  664. {
  665. _chn0_nak(dsize, dp);
  666. vbus_verbose("SET wrong chnr status %d, %s\n",
  667. chnr, rt_vbus_chn_st2str[_chn_status[chnr]]);
  668. break;
  669. }
  670. rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high);
  671. rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high);
  672. if (_chn0_ack(dsize, dp) >= 0)
  673. {
  674. _sess[i].chnr = chnr;
  675. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  676. vbus_debug("chn %d %s\n", chnr,
  677. rt_vbus_chn_st2str[_chn_status[chnr]]);
  678. rt_completion_done(&_sess[i].cmp);
  679. }
  680. }
  681. break;
  682. case RT_VBUS_CHN0_CMD_ACK:
  683. if (dp[1] == RT_VBUS_CHN0_CMD_SET)
  684. {
  685. int i, chnr;
  686. i = _sess_find(dp+2, SESSIOM_ESTABLISHING);
  687. if (i == ARRAY_SIZE(_sess))
  688. /* drop that spurious packet */
  689. break;
  690. chnr = dp[1+rt_strlen((const char*)dp+2)+2];
  691. _sess[i].chnr = chnr;
  692. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  693. vbus_debug("chn %d %s\n", chnr,
  694. rt_vbus_chn_st2str[_chn_status[chnr]]);
  695. rt_completion_done(&_sess[i].cmp);
  696. }
  697. else if (dp[1] == RT_VBUS_CHN0_CMD_DISABLE)
  698. {
  699. unsigned char chnr = dp[2];
  700. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  701. break;
  702. /* We could only get here by sending DISABLE command, which is
  703. * initiated by the rt_vbus_close_chn. */
  704. _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  705. _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr);
  706. /* notify the thread that the channel has been closed */
  707. rt_vbus_notify_chn(chnr, -RT_ERROR);
  708. }
  709. else
  710. {
  711. vbus_info("invalid ACK for %d\n", dp[1]);
  712. }
  713. break;
  714. case RT_VBUS_CHN0_CMD_DISABLE:
  715. {
  716. unsigned char chnr = dp[1];
  717. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  718. break;
  719. _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING;
  720. _chn0_ack(dsize, dp);
  721. _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr);
  722. /* notify the thread that the channel has been closed */
  723. rt_vbus_notify_chn(chnr, -RT_ERROR);
  724. }
  725. break;
  726. case RT_VBUS_CHN0_CMD_SUSPEND:
  727. #ifdef RT_VBUS_USING_FLOW_CONTROL
  728. {
  729. unsigned char chnr = dp[1];
  730. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  731. break;
  732. if (_chn_status[chnr] != RT_VBUS_CHN_ST_ESTABLISHED)
  733. break;
  734. _chn_status[chnr] = RT_VBUS_CHN_ST_SUSPEND;
  735. }
  736. #endif
  737. break;
  738. case RT_VBUS_CHN0_CMD_RESUME:
  739. #ifdef RT_VBUS_USING_FLOW_CONTROL
  740. {
  741. unsigned char chnr = dp[1];
  742. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  743. break;
  744. if (_chn_status[chnr] != RT_VBUS_CHN_ST_SUSPEND)
  745. break;
  746. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  747. /* Protect the list. */
  748. rt_enter_critical();
  749. while (!rt_list_isempty(&_chn_suspended_threads[chnr]))
  750. {
  751. rt_thread_t thread;
  752. thread = rt_list_entry(_chn_suspended_threads[chnr].next,
  753. struct rt_thread,
  754. tlist);
  755. rt_thread_resume(thread);
  756. }
  757. rt_exit_critical();
  758. }
  759. #endif
  760. break;
  761. case RT_VBUS_CHN0_CMD_NAK:
  762. if (dp[1] == RT_VBUS_CHN0_CMD_ENABLE)
  763. {
  764. int i;
  765. i = _sess_find(dp+2, SESSIOM_ESTABLISHING);
  766. if (i == ARRAY_SIZE(_sess))
  767. /* drop that spurious packet */
  768. break;
  769. _sess[i].chnr = -RT_EIO;
  770. rt_completion_done(&_sess[i].cmp);
  771. }
  772. else if (dp[1] == RT_VBUS_CHN0_CMD_SET)
  773. {
  774. vbus_info("NAK for %d not implemented\n", dp[1]);
  775. }
  776. else
  777. {
  778. vbus_info("invalid NAK for %d\n", dp[1]);
  779. }
  780. break;
  781. default:
  782. /* just ignore the invalid cmd */
  783. vbus_info("drop unknown cmd %d on chn0\n", *dp);
  784. break;
  785. };
  786. return RT_EOK;
  787. }
  788. int rt_vbus_request_chn(struct rt_vbus_request *req,
  789. int timeout)
  790. {
  791. int i, chnr, err;
  792. size_t plen = rt_strlen(req->name) + 2;
  793. unsigned char *pbuf;
  794. rt_ubase_t lvl;
  795. lvl = rt_hw_interrupt_disable();
  796. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  797. {
  798. if (_sess[i].st == SESSIOM_AVAILABLE)
  799. break;
  800. }
  801. if (i == ARRAY_SIZE(_sess))
  802. {
  803. rt_hw_interrupt_enable(lvl);
  804. return -RT_ERROR;
  805. }
  806. rt_completion_init(&_sess[i].cmp);
  807. _sess[i].req = req;
  808. if (req->is_server)
  809. {
  810. _sess[i].st = SESSIOM_LISTENING;
  811. rt_hw_interrupt_enable(lvl);
  812. vbus_debug("request listening %s on %d\n", req->name, i);
  813. /* always wait on the condition */
  814. err = RT_EOK;
  815. goto _waitforcmp;
  816. }
  817. pbuf = rt_malloc(plen);
  818. if (!pbuf)
  819. {
  820. rt_hw_interrupt_enable(lvl);
  821. return -RT_ENOMEM;
  822. }
  823. _sess[i].st = SESSIOM_ESTABLISHING;
  824. rt_hw_interrupt_enable(lvl);
  825. pbuf[0] = RT_VBUS_CHN0_CMD_ENABLE;
  826. rt_memcpy(pbuf+1, req->name, plen-1);
  827. vbus_verbose("%s --> remote\n", dump_cmd_pkt(pbuf, plen));
  828. err = _chn0_post(pbuf, plen, RT_WAITING_FOREVER);
  829. rt_free(pbuf);
  830. _waitforcmp:
  831. if (err == RT_EOK)
  832. err = rt_completion_wait(&_sess[i].cmp, timeout);
  833. vbus_debug("request wait cmp done %d, chnr %d\n", err, _sess[i].chnr);
  834. if (err)
  835. {
  836. /* cleanup the mass when the wait is time out but we have done some job
  837. */
  838. if (_sess[i].st == SESSIOM_ESTABLISHING)
  839. _chn_status[_sess[i].chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  840. chnr = err;
  841. goto Out;
  842. }
  843. RT_ASSERT(_sess[i].chnr != 0);
  844. chnr = _sess[i].chnr;
  845. Out:
  846. /* detach the sess as we finished the job */
  847. _sess[i].st = SESSIOM_AVAILABLE;
  848. _sess[i].req = RT_NULL;
  849. return chnr;
  850. }
  851. void rt_vbus_close_chn(unsigned char chnr)
  852. {
  853. void *p;
  854. rt_err_t err;
  855. unsigned char buf[2];
  856. buf[0] = RT_VBUS_CHN0_CMD_DISABLE;
  857. buf[1] = chnr;
  858. RT_ASSERT(0 < chnr && chnr < RT_VBUS_CHANNEL_NR);
  859. if (_chn_status[chnr] == RT_VBUS_CHN_ST_CLOSED ||
  860. _chn_status[chnr] == RT_VBUS_CHN_ST_CLOSING)
  861. {
  862. _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  863. return;
  864. }
  865. if (!_chn_connected(chnr))
  866. return;
  867. _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING;
  868. vbus_info("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  869. err = _chn0_post(&buf, sizeof(buf), RT_WAITING_FOREVER);
  870. if (err == RT_EOK)
  871. /* wait for the ack */
  872. rt_vbus_listen_on(chnr, 10 * RT_TICK_PER_SECOND);
  873. /* cleanup the remaining data */
  874. for (p = rt_vbus_data_pop(chnr); p; p = rt_vbus_data_pop(chnr))
  875. rt_free(p);
  876. /* FIXME: there is a chance that there are some data left on the send
  877. * buffer. So if we connect other channel with the same number immediately,
  878. * the new channel will receive some garbage data. However, this is highly
  879. * un-probable. */
  880. }
  881. #ifdef RT_VBUS_STATISTICS
  882. static unsigned int _total_data_sz;
  883. #endif
  884. static void _bus_in_entry(void *param)
  885. {
  886. rt_sem_init(&_bus_in_sem, "vbus", 0, RT_IPC_FLAG_FIFO);
  887. rt_event_init(&_bus_in_event, "vbus", RT_IPC_FLAG_FIFO);
  888. rt_memset(_bus_in_action, 0, sizeof(_bus_in_action));
  889. while (rt_sem_take(&_bus_in_sem,
  890. RT_WAITING_FOREVER) == RT_EOK)
  891. {
  892. rt_uint32_t event_set = 0;
  893. /* while(not empty) */
  894. while (RT_VBUS_IN_RING->get_idx != RT_VBUS_IN_RING->put_idx)
  895. {
  896. unsigned int id, nxtidx;
  897. rt_size_t size;
  898. struct rt_vbus_data *act;
  899. rt_vbus_smp_rmb();
  900. size = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].len;
  901. id = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].id;
  902. vbus_debug("vmm bus in: chnr %d, size %d\n", id, size);
  903. /* Suspended channel can still recv data. */
  904. if (id > RT_VBUS_CHANNEL_NR || !_chn_connected(id))
  905. {
  906. vbus_error("drop on invalid chn %d\n", id);
  907. /* drop the invalid packet */
  908. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  909. continue;
  910. }
  911. if (id == 0)
  912. {
  913. if (size > 60)
  914. vbus_error("too big(%d) packet on chn0\n", size);
  915. else
  916. _chn0_actor(RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size);
  917. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  918. continue;
  919. }
  920. #ifdef RT_VBUS_STATISTICS
  921. _total_data_sz += size;
  922. #endif
  923. act = rt_malloc(sizeof(*act) + size);
  924. if (act == RT_NULL)
  925. {
  926. //vbus_error("drop on OOM (%d, %d)\n", id, size);
  927. /* drop the packet on malloc fall */
  928. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  929. continue;
  930. }
  931. act->size = size;
  932. act->next = RT_NULL;
  933. nxtidx = RT_VBUS_IN_RING->get_idx + LEN2BNR(size);
  934. if (nxtidx >= RT_VMM_RB_BLK_NR)
  935. {
  936. unsigned int tailsz;
  937. tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_IN_RING->get_idx)
  938. * sizeof(RT_VBUS_IN_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ;
  939. /* the remaining block is sufficient for the data */
  940. if (tailsz > size)
  941. tailsz = size;
  942. rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, tailsz);
  943. rt_memcpy((char*)(act+1) + tailsz, &RT_VBUS_IN_RING->blks[0], size - tailsz);
  944. /* It shall make sure the CPU has finished reading the item
  945. * before it writes the new tail pointer, which will erase the
  946. * item. */
  947. rt_vbus_smp_wmb();
  948. RT_VBUS_IN_RING->get_idx = nxtidx - RT_VMM_RB_BLK_NR;
  949. }
  950. else
  951. {
  952. rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size);
  953. rt_vbus_smp_wmb();
  954. RT_VBUS_IN_RING->get_idx = nxtidx;
  955. }
  956. rt_vbus_data_push(id, act);
  957. _vbus_indicate(RT_VBUS_EVENT_ID_RX, id);
  958. event_set |= 1 << id;
  959. if (RT_VBUS_IN_RING->blocked)
  960. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  961. }
  962. if (event_set != 0)
  963. rt_vbus_notify_set(event_set);
  964. }
  965. RT_ASSERT(0);
  966. }
  967. void rt_vbus_isr(int irqnr, void *param)
  968. {
  969. if (RT_VBUS_OUT_RING->blocked)
  970. rt_vbus_resume_out_thread();
  971. rt_sem_release(&_bus_in_sem);
  972. rt_vbus_hw_eoi(irqnr, param);
  973. }
  974. int rt_vbus_init(void *outr, void *inr)
  975. {
  976. int i;
  977. #ifdef RT_USING_LOGTRACE
  978. log_trace_register_session(&_lgs);
  979. #endif
  980. if (outr > inr)
  981. {
  982. RT_ASSERT((char*)outr - (char*)inr >= sizeof(struct rt_vbus_ring));
  983. }
  984. else
  985. {
  986. RT_ASSERT((char*)inr - (char*)outr >= sizeof(struct rt_vbus_ring));
  987. }
  988. RT_VBUS_OUT_RING = outr;
  989. RT_VBUS_IN_RING = inr;
  990. rt_memset(RT_VBUS_OUT_RING, 0, sizeof(*RT_VBUS_OUT_RING));
  991. rt_memset(RT_VBUS_IN_RING, 0, sizeof(*RT_VBUS_IN_RING));
  992. _chn_status[0] = RT_VBUS_CHN_ST_ESTABLISHED;
  993. for (i = 1; i < ARRAY_SIZE(_chn_status); i++)
  994. {
  995. _chn_status[i] = RT_VBUS_CHN_ST_AVAILABLE;
  996. }
  997. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  998. {
  999. _sess[i].req = RT_NULL;
  1000. _sess[i].st = SESSIOM_AVAILABLE;
  1001. }
  1002. _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].indicate = _chn0_tx_listener;
  1003. _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].ctx = RT_NULL;
  1004. #ifdef RT_VBUS_USING_FLOW_CONTROL
  1005. for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++)
  1006. {
  1007. rt_wm_que_init(&_chn_wm_que[i],
  1008. RT_VMM_RB_BLK_NR / 3,
  1009. RT_VMM_RB_BLK_NR * 2 / 3);
  1010. }
  1011. /* Channel 0 has the full channel. */
  1012. rt_wm_que_set_mark(&_chn_wm_que[0], 0, ~0);
  1013. for (i = 0; i < ARRAY_SIZE(_chn_suspended_threads); i++)
  1014. {
  1015. rt_list_init(&_chn_suspended_threads[i]);
  1016. }
  1017. for (i = 1; i < ARRAY_SIZE(_chn_recv_wm); i++)
  1018. {
  1019. rt_vbus_set_recv_wm(i,
  1020. RT_VMM_RB_BLK_NR / 3,
  1021. RT_VMM_RB_BLK_NR * 2 / 3);
  1022. _chn_recv_wm[i].level = 0;
  1023. _chn_recv_wm[i].last_warn = 0;
  1024. }
  1025. /* Channel 0 has the full channel. Don't suspend it. */
  1026. _chn_recv_wm[0].low_mark = 0;
  1027. _chn_recv_wm[0].high_mark = ~0;
  1028. _chn_recv_wm[0].level = 0;
  1029. _chn_recv_wm[0].last_warn = 0;
  1030. #endif
  1031. rt_thread_init(&_bus_out_thread, "vbusout",
  1032. _bus_out_entry, RT_NULL,
  1033. _bus_out_thread_stack, sizeof(_bus_out_thread_stack),
  1034. _BUS_OUT_THRD_PRIO, 20);
  1035. rt_thread_startup(&_bus_out_thread);
  1036. rt_thread_init(&_bus_in_thread, "vbusin",
  1037. _bus_in_entry, RT_NULL,
  1038. _bus_in_thread_stack, sizeof(_bus_in_thread_stack),
  1039. _BUS_IN_THRD_PRIO, 20);
  1040. rt_thread_startup(&_bus_in_thread);
  1041. rt_vbus_hw_init();
  1042. rt_kprintf("VBus loaded: %d out blocks, %d in blocks\n",
  1043. RT_VMM_RB_BLK_NR, RT_VMM_RB_BLK_NR);
  1044. rt_vbus_chnx_init();
  1045. return 0;
  1046. }
  1047. void rt_vbus_rb_dump(void)
  1048. {
  1049. rt_kprintf("OUT ring:(%s blocked)\n", RT_VBUS_OUT_RING->blocked ? "is" : "not");
  1050. rt_kprintf("put idx: %8x, get idx: %8x\n",
  1051. RT_VBUS_OUT_RING->put_idx, RT_VBUS_OUT_RING->get_idx);
  1052. rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_OUT_RING));
  1053. rt_kprintf("IN ring:(%s blocked)\n", RT_VBUS_IN_RING->blocked ? "is" : "not");
  1054. rt_kprintf("put idx: %8x, get idx: %8x\n",
  1055. RT_VBUS_IN_RING->put_idx, RT_VBUS_IN_RING->get_idx);
  1056. rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_IN_RING));
  1057. }
  1058. void rt_vbus_chn_dump(void)
  1059. {
  1060. int i;
  1061. rt_kprintf("vbus channel status:\n");
  1062. for (i = 0; i < ARRAY_SIZE(_chn_status); i++)
  1063. {
  1064. rt_kprintf("%2d:%s\n", i, rt_vbus_chn_st2str[_chn_status[i]]);
  1065. }
  1066. }
  1067. void rt_vbus_sess_dump(void)
  1068. {
  1069. int i;
  1070. rt_kprintf("vbus conn session:\n");
  1071. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  1072. {
  1073. rt_kprintf("%2d(%s):%s\n", i, _sess[i].req ? _sess[i].req->name : "",
  1074. rt_vbus_sess_st2str[_sess[i].st]);
  1075. }
  1076. }
  1077. void rt_vbus_que_dump(void)
  1078. {
  1079. rt_kprintf("out que:\n");
  1080. rt_prio_queue_dump(_bus_out_que);
  1081. }
  1082. unsigned int rt_vbus_total_data_sz(void)
  1083. {
  1084. #ifdef RT_VBUS_STATISTICS
  1085. return _total_data_sz;
  1086. #else
  1087. return (unsigned int)-1;
  1088. #endif
  1089. }
  1090. void rt_vbus_data_pkt_dump(void)
  1091. {
  1092. int i;
  1093. for (i = 0; i < ARRAY_SIZE(_bus_in_action); i++)
  1094. {
  1095. struct rt_vbus_data *dp;
  1096. #ifdef RT_VBUS_STATISTICS
  1097. rt_kprintf("%2d %4d: ", i, _bus_in_action_nr[i]);
  1098. #else
  1099. rt_kprintf("%2d: ", i);
  1100. #endif
  1101. for (dp = _bus_in_action[i][_IN_ACT_HEAD];
  1102. dp;
  1103. dp = dp->next)
  1104. {
  1105. rt_kprintf("%p(%d) -> ", dp, dp->size);
  1106. }
  1107. rt_kprintf(" nil\n");
  1108. }
  1109. }
  1110. #ifdef RT_VBUS_USING_FLOW_CONTROL
  1111. void rt_vbus_chm_wm_dump(void)
  1112. {
  1113. int i;
  1114. rt_kprintf("post wm:\n");
  1115. for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++)
  1116. rt_wm_que_dump(&_chn_wm_que[i]);
  1117. rt_kprintf("recv wm:\n");
  1118. rt_kprintf(" low, high, cur, last warn\n");
  1119. for (i = 0; i < ARRAY_SIZE(_chn_recv_wm); i++)
  1120. {
  1121. rt_kprintf("%8x, %8x, %8x, %8x\n",
  1122. _chn_recv_wm[i].low_mark, _chn_recv_wm[i].high_mark,
  1123. _chn_recv_wm[i].level, _chn_recv_wm[i].last_warn);
  1124. }
  1125. }
  1126. #endif
  1127. #ifdef RT_USING_FINSH
  1128. #include <finsh.h>
  1129. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_rb_dump, vbrb, dump vbus ringbuffer status);
  1130. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chn_dump, vbchn, dump vbus channel status);
  1131. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_sess_dump, vbses, dump vbus session status);
  1132. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_que_dump, vbque, dump vbus out queue status);
  1133. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_total_data_sz, vbtsz, total in data);
  1134. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_data_pkt_dump, vbdq, dump the data queue);
  1135. #ifdef RT_VBUS_USING_FLOW_CONTROL
  1136. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chm_wm_dump, vbwm, dump vbus water mark status);
  1137. #endif
  1138. #endif