vbus.c 36 KB

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