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