vbus.c 37 KB

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