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