diff options
| author | copilot-swe-agent[bot] <[email protected]> | 2025-10-28 23:36:25 +0000 |
|---|---|---|
| committer | copilot-swe-agent[bot] <[email protected]> | 2025-10-28 23:36:25 +0000 |
| commit | 35e4335ee752da9adb3029a06cb6004f3d9320f7 (patch) | |
| tree | 25f26a0a9992f35e877ff08c1d0a41c48fd726c4 /components | |
| parent | 6d2f401e172911b8433bebe6d6a6e76c1b637d5c (diff) | |
Remove vbus component and related codecopilot/remove-vbus-code-implementation
Co-authored-by: BernardXiong <[email protected]>
Diffstat (limited to 'components')
| -rw-r--r-- | components/Kconfig | 1 | ||||
| -rw-r--r-- | components/vbus/Kconfig | 56 | ||||
| -rw-r--r-- | components/vbus/SConscript | 23 | ||||
| -rw-r--r-- | components/vbus/prio_queue.c | 256 | ||||
| -rw-r--r-- | components/vbus/prio_queue.h | 54 | ||||
| -rw-r--r-- | components/vbus/share_hdr/vbus_api.h | 89 | ||||
| -rw-r--r-- | components/vbus/vbus.c | 1318 | ||||
| -rw-r--r-- | components/vbus/vbus.h | 177 | ||||
| -rw-r--r-- | components/vbus/vbus_chnx.c | 269 | ||||
| -rw-r--r-- | components/vbus/watermark_queue.c | 50 | ||||
| -rw-r--r-- | components/vbus/watermark_queue.h | 129 |
11 files changed, 0 insertions, 2422 deletions
diff --git a/components/Kconfig b/components/Kconfig index 1427e1e709..0b9b3ab9d0 100644 --- a/components/Kconfig +++ b/components/Kconfig @@ -37,7 +37,6 @@ rsource "libc/Kconfig" rsource "net/Kconfig" rsource "mprotect/Kconfig" rsource "utilities/Kconfig" -rsource "vbus/Kconfig" endif if ARCH_MM_MMU diff --git a/components/vbus/Kconfig b/components/vbus/Kconfig deleted file mode 100644 index d7605f595d..0000000000 --- a/components/vbus/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -menuconfig RT_USING_VBUS - bool "VBus: virtual software bus" - default n - -if RT_USING_VBUS - config RT_USING_VBUS_RFS - bool "Enable Remote File System on VBus" - default n - help - When enable remote file system, the application can visit the remote file system - through VBus with POSIX file I/O. - - config RT_USING_VBUS_RSHELL - bool "Enable Remote Shell on VBus" - default n - help - When enable remote shell, the finsh/msh of RT-Thread can be operated from another - Operating System. - - config RT_VBUS_USING_TESTS - bool "Enable tests on VBus" - default n - - config _RT_VBUS_RING_BASE - hex "VBus address" - help - VBus ring buffer physical address. - - config _RT_VBUS_RING_SZ - int "VBus ring size" - help - VBus size of the ring buffer. - - config RT_VBUS_GUEST_VIRQ - int "RT_VBUS_GUEST_VIRQ" - help - The interrupt number used to notify the client on a particular system. - - config RT_VBUS_HOST_VIRQ - int "RT_VBUS_HOST_VIRQ" - help - The interrupt be triggered on a particular system when the client notify the host. - - config RT_VBUS_SHELL_DEV_NAME - string "RT_VBUS_SHELL_DEV_NAME" - default "vbser0" - help - The name of the UBUS shell device. - - config RT_VBUS_RFS_DEV_NAME - string "RT_VBUS_RFS_DEV_NAME" - default "rfs" - help - The name of the UBUS rfs device. - -endif diff --git a/components/vbus/SConscript b/components/vbus/SConscript deleted file mode 100644 index 7a07ea9539..0000000000 --- a/components/vbus/SConscript +++ /dev/null @@ -1,23 +0,0 @@ -# RT-Thread building script for component - -import SCons, os -from building import * - -group = [] -if not GetDepend(['RT_USING_VBUS']): - Return('group') - -cwd = GetCurrentDir() -src = Glob('*.c') - -for c, f in [['RT_USING_VBUS_RFS', 'utilities/rfs.c'], - ['RT_USING_VBUS_RSHELL', 'utilities/rshell.c'], - ]: - if GetDepend(c): - src += Glob(f) - -CPPPATH = [cwd, os.path.join(cwd, 'share_hdr')] - -group = DefineGroup('VBus', src, depend = ['RT_USING_VBUS'], CPPPATH = CPPPATH) - -Return('group') diff --git a/components/vbus/prio_queue.c b/components/vbus/prio_queue.c deleted file mode 100644 index 9c8dca5157..0000000000 --- a/components/vbus/prio_queue.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-11-04 Grissiom add comment - */ - -#include <rthw.h> -#include <rtthread.h> - -#include "prio_queue.h" - -struct rt_prio_queue_item { - struct rt_prio_queue_item *next; - /* data follows */ -}; - -static void _do_push(struct rt_prio_queue *que, - rt_uint8_t prio, - struct rt_prio_queue_item *item) -{ - if (que->head[prio] == RT_NULL) - { - que->head[prio] = item; - que->bitmap |= 1 << prio; - } - else - { - RT_ASSERT(que->tail[prio]); - que->tail[prio]->next = item; - } - que->tail[prio] = item; -} - -static struct rt_prio_queue_item* _do_pop(struct rt_prio_queue *que) -{ - int ffs; - struct rt_prio_queue_item *item; - - ffs = __rt_ffs(que->bitmap); - if (ffs == 0) - return RT_NULL; - ffs--; - - item = que->head[ffs]; - RT_ASSERT(item); - - que->head[ffs] = item->next; - if (que->head[ffs] == RT_NULL) - { - que->bitmap &= ~(1 << ffs); - } - - return item; -} - -rt_err_t rt_prio_queue_init(struct rt_prio_queue *que, - const char *name, - void *buf, - rt_size_t bufsz, - rt_size_t itemsz) -{ - RT_ASSERT(que); - - rt_memset(que, 0, sizeof(*que)); - - rt_list_init(&(que->suspended_pop_list)); - - rt_mp_init(&que->pool, name, buf, bufsz, - sizeof(struct rt_prio_queue_item) + itemsz); - - que->item_sz = itemsz; - - return RT_EOK; -} - -void rt_prio_queue_detach(struct rt_prio_queue *que) -{ - /* wake up all suspended pop threads, push thread is suspended on mempool. - */ - while (!rt_list_isempty(&(que->suspended_pop_list))) - { - rt_thread_t thread; - - /* disable interrupt */ - rt_base_t level = rt_hw_interrupt_disable(); - - /* get next suspend thread */ - thread = RT_THREAD_LIST_NODE_ENTRY(que->suspended_pop_list.next); - /* set error code to -RT_ERROR */ - thread->error = -RT_ERROR; - - rt_thread_resume(thread); - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - } - rt_mp_detach(&que->pool); -} - -#ifdef RT_USING_HEAP -struct rt_prio_queue* rt_prio_queue_create(const char *name, - rt_size_t item_nr, - rt_size_t item_sz) -{ - struct rt_prio_queue *que; - rt_size_t bufsz; - - bufsz = item_nr * (sizeof(struct rt_prio_queue_item) - + item_sz - + sizeof(void*)); - - RT_ASSERT(item_nr); - - que = rt_malloc(sizeof(*que) + bufsz); - if (!que) - return RT_NULL; - - rt_prio_queue_init(que, name, que+1, bufsz, item_sz); - - return que; -} - -void rt_prio_queue_delete(struct rt_prio_queue *que) -{ - rt_prio_queue_detach(que); - rt_free(que); -} -#endif - -rt_err_t rt_prio_queue_push(struct rt_prio_queue *que, - rt_uint8_t prio, - void *data, - rt_int32_t timeout) -{ - rt_base_t level; - struct rt_prio_queue_item *item; - - RT_ASSERT(que); - - if (prio >= RT_PRIO_QUEUE_PRIO_MAX) - return -RT_ERROR; - - item = rt_mp_alloc(&que->pool, timeout); - if (item == RT_NULL) - return -RT_ENOMEM; - - rt_memcpy(item+1, data, que->item_sz); - item->next = RT_NULL; - - level = rt_hw_interrupt_disable(); - - _do_push(que, prio, item); - - if (!rt_list_isempty(&(que->suspended_pop_list))) - { - rt_thread_t thread; - - /* get thread entry */ - thread = RT_THREAD_LIST_NODE_ENTRY(que->suspended_pop_list.next); - /* resume it */ - rt_thread_resume(thread); - rt_hw_interrupt_enable(level); - - /* perform a schedule */ - rt_schedule(); - - return RT_EOK; - } - - rt_hw_interrupt_enable(level); - - return RT_EOK; -} - -rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que, - void *data, - rt_int32_t timeout) -{ - rt_base_t level; - struct rt_prio_queue_item *item; - - RT_ASSERT(que); - RT_ASSERT(data); - - level = rt_hw_interrupt_disable(); - for (item = _do_pop(que); - item == RT_NULL; - item = _do_pop(que)) - { - rt_thread_t thread; - - if (timeout == 0) - { - rt_hw_interrupt_enable(level); - return -RT_ETIMEOUT; - } - - RT_DEBUG_NOT_IN_INTERRUPT; - - thread = rt_thread_self(); - thread->error = RT_EOK; - rt_thread_suspend(thread); - - rt_list_insert_before(&(que->suspended_pop_list), &RT_THREAD_LIST_NODE(thread)); - - if (timeout > 0) - { - rt_tick_t timeout_tick = timeout; - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout_tick); - rt_timer_start(&(thread->thread_timer)); - } - - rt_hw_interrupt_enable(level); - - rt_schedule(); - - /* thread is waked up */ - if (thread->error != RT_EOK) - return thread->error; - level = rt_hw_interrupt_disable(); - } - - rt_hw_interrupt_enable(level); - - rt_memcpy(data, item+1, que->item_sz); - rt_mp_free(item); - - return RT_EOK; -} - -void rt_prio_queue_dump(struct rt_prio_queue *que) -{ - int level = 0; - - rt_kprintf("bitmap: %08x\n", que->bitmap); - for (level = 0; level < RT_PRIO_QUEUE_PRIO_MAX; level++) - { - struct rt_prio_queue_item *item; - - rt_kprintf("%2d: ", level); - for (item = que->head[level]; - item; - item = item->next) - { - rt_kprintf("%p, ", item); - } - rt_kprintf("\n"); - } -} - diff --git a/components/vbus/prio_queue.h b/components/vbus/prio_queue.h deleted file mode 100644 index 0af36d0ea9..0000000000 --- a/components/vbus/prio_queue.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-11-04 Grissiom add comment - */ - -#ifndef __PRIO_QUEUE_H__ -#define __PRIO_QUEUE_H__ - -#include <rtthread.h> - -#define RT_PRIO_QUEUE_PRIO_MAX 32 - -struct rt_prio_queue_item; - -struct rt_prio_queue { - rt_uint32_t bitmap; - struct rt_prio_queue_item *head[RT_PRIO_QUEUE_PRIO_MAX]; - struct rt_prio_queue_item *tail[RT_PRIO_QUEUE_PRIO_MAX]; - /* push thread suspend on the mempool, not queue */ - rt_list_t suspended_pop_list; - rt_size_t item_sz; - - struct rt_mempool pool; -}; - -rt_err_t rt_prio_queue_init(struct rt_prio_queue *que, - const char *name, - void *buf, - rt_size_t bufsz, - rt_size_t itemsz); -void rt_prio_queue_detach(struct rt_prio_queue *que); - -rt_err_t rt_prio_queue_push(struct rt_prio_queue *que, - rt_uint8_t prio, - void *data, - rt_int32_t timeout); -rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que, - void *data, - rt_int32_t timeout); -#ifdef RT_USING_HEAP -struct rt_prio_queue* rt_prio_queue_create(const char *name, - rt_size_t item_nr, - rt_size_t item_sz); -void rt_prio_queue_delete(struct rt_prio_queue *que); -#endif - -void rt_prio_queue_dump(struct rt_prio_queue *que); - -#endif /* end of include guard: __PRIO_QUEUE_H__ */ diff --git a/components/vbus/share_hdr/vbus_api.h b/components/vbus/share_hdr/vbus_api.h deleted file mode 100644 index a643822a9c..0000000000 --- a/components/vbus/share_hdr/vbus_api.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ -#ifndef __VBUS_API_H__ -#define __VBUS_API_H__ - -#define RT_VBUS_USING_FLOW_CONTROL - -#define RT_VBUS_CHANNEL_NR 32 - -#define RT_VBUS_BLK_HEAD_SZ 4 -#define RT_VBUS_MAX_PKT_SZ (256 - RT_VBUS_BLK_HEAD_SZ) - -#define RT_VMM_RB_BLK_NR (_RT_VBUS_RING_SZ / 64 - 1) - -#ifndef __ASSEMBLY__ -#include <stddef.h> /* For size_t */ - -struct rt_vbus_blk -{ - unsigned char id; - unsigned char qos; - unsigned char len; - unsigned char reserved; - unsigned char data[60]; -} __attribute__((packed)); - -struct rt_vbus_ring -{ - volatile size_t put_idx; - volatile size_t get_idx; - /* whether the writer is blocked on this ring. For RTT, it means the - * central writer thread is waiting. For Linux, it means there are some - * threads waiting for space to write. - * - * Note that we don't record whether there are reading thread blocked. When - * there is new data, the other side will always be waked up. */ - volatile unsigned int blocked; - struct rt_vbus_blk blks[RT_VMM_RB_BLK_NR]; -}; - -enum -{ - RT_VBUS_CHN0_CMD_ENABLE, - RT_VBUS_CHN0_CMD_DISABLE, - RT_VBUS_CHN0_CMD_SET, - RT_VBUS_CHN0_CMD_ACK, - RT_VBUS_CHN0_CMD_NAK, - /* If the recieving side reached high water mark. It has the right to - * suspend the channel. All the server/client should know about this - * command but the one that does not implement flow control could ignore - * this command. */ - RT_VBUS_CHN0_CMD_SUSPEND, - RT_VBUS_CHN0_CMD_RESUME, - RT_VBUS_CHN0_CMD_MAX, -}; - -enum rt_vbus_chn_status -{ - /* initial state, available for reuse */ - RT_VBUS_CHN_ST_AVAILABLE, - /* ACK DISABLE send(CS) or received(CS), but not ready for reuse.(the - * channel is not closed by this end) */ - RT_VBUS_CHN_ST_CLOSED, - /* ENABLE send(client) or received(server) */ - RT_VBUS_CHN_ST_ESTABLISHING, - /* ACK SET send(C) or received(S) */ - RT_VBUS_CHN_ST_ESTABLISHED, - /* Channel suspended by flow control. */ - RT_VBUS_CHN_ST_SUSPEND, - /* DISABLE received(CS) */ - RT_VBUS_CHN_ST_CLOSING, -}; -#endif - -#undef BUILD_ASSERT -/* borrowed from http://lxr.linux.no/linux+v2.6.26.5/include/linux/kernel.h#L494 */ -#define BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)])) - -/* max length of a channel name, including the \0 */ -#define RT_VBUS_CHN_NAME_MAX 16 - -#endif /* end of include guard: __VBUS_API_H__ */ - diff --git a/components/vbus/vbus.c b/components/vbus/vbus.c deleted file mode 100644 index 2adaac8dda..0000000000 --- a/components/vbus/vbus.c +++ /dev/null @@ -1,1318 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-11-04 Grissiom add comment - */ - -#include <rthw.h> -#include <rtthread.h> -#include <rtdevice.h> - -#include "vbus.h" -#include "prio_queue.h" -#include "vbus_hw.h" - -//#define RT_VBUS_STATISTICS - -#define RT_VBUS_RB_LOW_TICK (RT_VMM_RB_BLK_NR * 2 / 3) -#define RT_VBUS_RB_TICK_STEP (100) - -/* console could be run on vbus. If we log on it, there will be oops. */ -#define vbus_debug(...) -#define vbus_verbose(...) -#define vbus_info(...) -#define vbus_error(...) - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0])) -#endif - -struct rt_vbus_ring *RT_VBUS_OUT_RING; -struct rt_vbus_ring *RT_VBUS_IN_RING; - -const char *rt_vbus_chn_st2str[] = { - "available", - "closed", - "establishing", - "established", - "suspended", - "closing", -}; - -const char *rt_vbus_sess_st2str[] = { - "available", - "listening", - "establishing", -}; - -const char *rt_vbus_cmd2str[] = { - "ENABLE", - "DISABLE", - "SET", - "ACK", - "NAK", - "SUSPEND", - "RESUME", -}; - -static char* dump_cmd_pkt(unsigned char *dp, size_t dsize); - -/* 4 bytes for the head */ -#define LEN2BNR(len) ((len + RT_VBUS_BLK_HEAD_SZ \ - + sizeof(struct rt_vbus_blk) - 1) \ - / sizeof(struct rt_vbus_blk)) - -rt_inline void _ring_add_get_bnr(struct rt_vbus_ring *ring, - rt_size_t bnr) -{ - int nidx = ring->get_idx + bnr; - - if (nidx >= RT_VMM_RB_BLK_NR) - { - nidx -= RT_VMM_RB_BLK_NR; - } - rt_vbus_smp_wmb(); - ring->get_idx = nidx; -} - -rt_inline int _bus_ring_space_nr(struct rt_vbus_ring *rg) -{ - int delta; - - rt_vbus_smp_rmb(); - delta = rg->get_idx - rg->put_idx; - - if (delta > 0) - { - /* Put is behind the get. */ - return delta - 1; - } - else - { - /* delta is negative. */ - return RT_VMM_RB_BLK_NR + delta - 1; - } -} - -struct rt_vbus_pkg { - rt_uint8_t id; - rt_uint8_t prio; - rt_uint8_t finished; - rt_uint8_t len; - const void *data; -}; - -/* chn0 is always connected */ -static enum rt_vbus_chn_status _chn_status[RT_VBUS_CHANNEL_NR]; - -rt_inline int _chn_connected(unsigned char chnr) -{ - return _chn_status[chnr] == RT_VBUS_CHN_ST_ESTABLISHED || - _chn_status[chnr] == RT_VBUS_CHN_ST_SUSPEND; -} - -#ifdef RT_VBUS_USING_FLOW_CONTROL -#include <watermark_queue.h> -struct rt_watermark_queue _chn_wm_que[RT_VBUS_CHANNEL_NR]; -void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high) -{ - RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_wm_que))); - rt_wm_que_set_mark(&_chn_wm_que[chnr], low, high); -} - -/* Threads suspended by the flow control of other side. */ -rt_list_t _chn_suspended_threads[RT_VBUS_CHANNEL_NR]; - -struct -{ - unsigned int level; - unsigned int high_mark; - unsigned int low_mark; - /* The suspend command does not have ACK. So if the other side still - * sending pkg after SUSPEND, warn it again. Also use it as a flag that - * tell me whether are we dropping from the high mark or not when reaching - * the low mark. */ - unsigned int last_warn; -} _chn_recv_wm[RT_VBUS_CHANNEL_NR]; - -void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high) -{ - RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_recv_wm))); - _chn_recv_wm[chnr].low_mark = low; - _chn_recv_wm[chnr].high_mark = high; -} -#else -void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high) -{} -void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high) -{} -#endif - -struct { - rt_vbus_event_listener indicate; - void *ctx; -} _vbus_rx_indi[RT_VBUS_EVENT_ID_MAX][RT_VBUS_CHANNEL_NR]; - -void rt_vbus_register_listener(unsigned char chnr, - enum rt_vbus_event_id eve, - rt_vbus_event_listener indi, - void *ctx) -{ - RT_ASSERT(chnr != 0 && chnr < RT_VBUS_CHANNEL_NR); - RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0])); - - _vbus_rx_indi[eve][chnr].indicate = indi; - _vbus_rx_indi[eve][chnr].ctx = ctx; -} - -static void _vbus_indicate(enum rt_vbus_event_id eve, unsigned char chnr) -{ - RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0])); - - if (_vbus_rx_indi[eve][chnr].indicate) - _vbus_rx_indi[eve][chnr].indicate(_vbus_rx_indi[eve][chnr].ctx); -} - -#define _BUS_OUT_THRD_STACK_SZ 2048 -#define _BUS_OUT_THRD_PRIO 8 -#define _BUS_OUT_PKG_NR RT_VMM_RB_BLK_NR - -static struct rt_thread _bus_out_thread; -static rt_uint8_t _bus_out_thread_stack[_BUS_OUT_THRD_STACK_SZ]; -struct rt_prio_queue *_bus_out_que; - -static void _bus_out_entry(void *param) -{ - struct rt_vbus_pkg dpkg; - - _bus_out_que = rt_prio_queue_create("vbus", - _BUS_OUT_PKG_NR, - sizeof(struct rt_vbus_pkg)); - - if (!_bus_out_que) - { - rt_kprintf("could not create vmm bus queue\n"); - return; - } - - while (rt_prio_queue_pop(_bus_out_que, &dpkg, - RT_WAITING_FOREVER) == RT_EOK) - { - int sp; - rt_uint32_t nxtidx; - const int dnr = LEN2BNR(dpkg.len); - -#ifdef RT_VBUS_USING_FLOW_CONTROL - rt_wm_que_dec(&_chn_wm_que[dpkg.id]); -#endif - - if (!_chn_connected(dpkg.id)) - continue; - - sp = _bus_ring_space_nr(RT_VBUS_OUT_RING); - - vbus_debug("vmm bus out" - "(data: %p, len: %d, prio: %d, id: %d)\n", - dpkg.data, dpkg.len, dpkg.prio, dpkg.id); - - /* wait for enough space */ - while (sp < dnr) - { - rt_base_t level = rt_hw_interrupt_disable(); - - RT_VBUS_OUT_RING->blocked = 1; - rt_vbus_smp_wmb(); - - /* kick the guest, hoping this could force it do the work */ - rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); - - rt_thread_suspend(rt_thread_self()); - rt_schedule(); - - RT_VBUS_OUT_RING->blocked = 0; - - rt_hw_interrupt_enable(level); - - sp = _bus_ring_space_nr(RT_VBUS_OUT_RING); - } - - nxtidx = RT_VBUS_OUT_RING->put_idx + dnr; - - RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].id = dpkg.id; - RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].qos = dpkg.prio; - RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].len = dpkg.len; - - if (nxtidx >= RT_VMM_RB_BLK_NR) - { - unsigned int tailsz; - - tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_OUT_RING->put_idx) - * sizeof(RT_VBUS_OUT_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ; - - /* the remaining block is sufficient for the data */ - if (tailsz > dpkg.len) - tailsz = dpkg.len; - - rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data, - dpkg.data, tailsz); - rt_memcpy(&RT_VBUS_OUT_RING->blks[0], - ((char*)dpkg.data)+tailsz, - dpkg.len - tailsz); - - rt_vbus_smp_wmb(); - RT_VBUS_OUT_RING->put_idx = nxtidx - RT_VMM_RB_BLK_NR; - } - else - { - rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data, - dpkg.data, dpkg.len); - - rt_vbus_smp_wmb(); - RT_VBUS_OUT_RING->put_idx = nxtidx; - } - - rt_vbus_smp_wmb(); - rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); - - if (dpkg.finished) - { - _vbus_indicate(RT_VBUS_EVENT_ID_TX, dpkg.id); - } - } - RT_ASSERT(0); -} - -void rt_vbus_resume_out_thread(void) -{ - rt_thread_resume(&_bus_out_thread); - rt_schedule(); -} - -rt_err_t rt_vbus_post(rt_uint8_t id, - rt_uint8_t prio, - const void *data, - rt_size_t size, - rt_int32_t timeout) -{ - rt_err_t err = RT_EOK; - struct rt_vbus_pkg pkg; - unsigned int putsz; - const unsigned char *dp; - - if (!_bus_out_que) - { - rt_kprintf("post (data: %p, size: %d, timeout: %d) " - "to bus before initialition\n", - data, size, timeout); - return -RT_ERROR; - } - - if (id >= RT_VBUS_CHANNEL_NR) - return -RT_ERROR; - - if (timeout != 0) - { - RT_DEBUG_IN_THREAD_CONTEXT; - } - -#ifdef RT_VBUS_USING_FLOW_CONTROL - while (_chn_status[id] == RT_VBUS_CHN_ST_SUSPEND) - { - rt_thread_t thread; - - if (timeout == 0) - { - return -RT_EFULL; - } - - thread = rt_thread_self(); - thread->error = RT_EOK; - /* We only touch the _chn_suspended_threads in thread, so lock the - * scheduler is enough. */ - rt_enter_critical(); - rt_thread_suspend(thread); - - rt_list_insert_after(&_chn_suspended_threads[id], &RT_THREAD_LIST_NODE(thread)); - if (timeout > 0) - { - rt_tick_t timeout_tick = timeout; - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout_tick); - rt_timer_start(&(thread->thread_timer)); - } - /* rt_exit_critical will do schedule on need. */ - rt_exit_critical(); - - if (thread->error != RT_EOK) - return thread->error; - } -#endif - - if (_chn_status[id] != RT_VBUS_CHN_ST_ESTABLISHED) - return -RT_ERROR; - - dp = data; - pkg.id = id; - pkg.prio = prio; - for (putsz = 0; size; size -= putsz) - { - pkg.data = dp; - - if (size > RT_VBUS_MAX_PKT_SZ) - { - putsz = RT_VBUS_MAX_PKT_SZ; - pkg.finished = 0; - } - else - { - putsz = size; - pkg.finished = 1; - } - - pkg.len = putsz; - dp += putsz; - -#ifdef RT_VBUS_USING_FLOW_CONTROL - err = rt_wm_que_inc(&_chn_wm_que[id], timeout); - if (err != RT_EOK) - break; -#endif - - vbus_debug("post (data: %p(%d), size: %d, finshed: %d, timeout: %d)\n", - pkg.data, ((unsigned char*)pkg.data)[0], - pkg.len, pkg.finished, timeout); - - err = rt_prio_queue_push(_bus_out_que, prio, &pkg, timeout); - if (err != RT_EOK) - break; - } - - return err; -} - -struct rt_completion _chn0_post_cmp; - -void _chn0_tx_listener(void *p) -{ - rt_completion_done(&_chn0_post_cmp); -} - -/* Posts in channel0 should be sync. */ -static rt_err_t _chn0_post(const void *data, - rt_size_t size, - int timeout) -{ - rt_err_t err; - - rt_completion_init(&_chn0_post_cmp); - err = rt_vbus_post(0, 0, data, size, timeout); - if (err != RT_EOK) - return err; - return rt_completion_wait(&_chn0_post_cmp, timeout); -} - -#define _BUS_IN_THRD_STACK_SZ 1024 -#define _BUS_IN_THRD_PRIO (_BUS_OUT_THRD_PRIO+1) -#if (_BUS_IN_THRD_PRIO == RT_THREAD_PRIORITY_MAX) -#error "_BUS_OUT_THRD_PRIO too low" -#endif - -static struct rt_thread _bus_in_thread; -static rt_uint8_t _bus_in_thread_stack[_BUS_OUT_THRD_STACK_SZ]; -static struct rt_semaphore _bus_in_sem; -static struct rt_event _bus_in_event; -/* {head, tail} */ -#define _IN_ACT_HEAD 0 -#define _IN_ACT_TAIL 1 -static struct rt_vbus_data *_bus_in_action[RT_VBUS_CHANNEL_NR][2]; -#ifdef RT_VBUS_STATISTICS -static unsigned int _bus_in_action_nr[RT_VBUS_CHANNEL_NR]; -#endif - -static void rt_vbus_notify_chn(unsigned char chnr, rt_err_t err) -{ -#ifdef RT_VBUS_USING_FLOW_CONTROL - /* TODO: get rid of this */ - /* Protect the list. */ - rt_enter_critical(); - while (!rt_list_isempty(&_chn_suspended_threads[chnr])) - { - rt_thread_t thread; - - thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next); - thread->error = err; - rt_thread_resume(thread); - } - rt_exit_critical(); -#endif - rt_event_send(&_bus_in_event, 1 << chnr); -} - -static void rt_vbus_notify_set(rt_uint32_t set) -{ - rt_event_send(&_bus_in_event, set); -} - -rt_err_t rt_vbus_listen_on(rt_uint8_t chnr, - rt_int32_t timeout) -{ - rt_uint32_t notuse; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR || !_chn_connected(chnr)) - return -RT_EIO; - - return rt_event_recv(&_bus_in_event, 1 << chnr, - RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, - timeout, ¬use); -} - -void rt_vbus_data_push(unsigned int id, struct rt_vbus_data *act) -{ - rt_base_t level; - - RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR); - - level = rt_hw_interrupt_disable(); - - if (_bus_in_action[id][_IN_ACT_HEAD] == RT_NULL) - { - _bus_in_action[id][_IN_ACT_HEAD] = act; - _bus_in_action[id][_IN_ACT_TAIL] = act; - } - else - { - _bus_in_action[id][_IN_ACT_TAIL]->next = act; - _bus_in_action[id][_IN_ACT_TAIL] = act; - } - -#ifdef RT_VBUS_STATISTICS - _bus_in_action_nr[id]++; -#endif - - rt_hw_interrupt_enable(level); - -#ifdef RT_VBUS_USING_FLOW_CONTROL - _chn_recv_wm[id].level++; - if (_chn_recv_wm[id].level == 0) - _chn_recv_wm[id].level = ~0; - if (_chn_recv_wm[id].level > _chn_recv_wm[id].high_mark && - _chn_recv_wm[id].level > _chn_recv_wm[id].last_warn) - { - unsigned char buf[2]; - - buf[0] = RT_VBUS_CHN0_CMD_SUSPEND; - buf[1] = id; - vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); - _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER); - /* Warn the other side in 100 more pkgs. */ - _chn_recv_wm[id].last_warn = _chn_recv_wm[id].level + 100; - } -#endif -} - -struct rt_vbus_data* rt_vbus_data_pop(unsigned int id) -{ - struct rt_vbus_data *act; - rt_base_t level; - - RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR); - - level = rt_hw_interrupt_disable(); - - act = _bus_in_action[id][_IN_ACT_HEAD]; - if (act) - { - _bus_in_action[id][_IN_ACT_HEAD] = act->next; - } - - rt_hw_interrupt_enable(level); - -#ifdef RT_VBUS_USING_FLOW_CONTROL - if (_chn_recv_wm[id].level != 0) - { - _chn_recv_wm[id].level--; - if (_chn_recv_wm[id].level <= _chn_recv_wm[id].low_mark && - _chn_recv_wm[id].last_warn > _chn_recv_wm[id].low_mark) - { - unsigned char buf[2]; - - buf[0] = RT_VBUS_CHN0_CMD_RESUME; - buf[1] = id; - vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); - _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER); - _chn_recv_wm[id].last_warn = 0; - } - } -#endif - return act; -} - -/* dump cmd that is not start with ACK/NAK */ -static size_t __dump_naked_cmd(char *dst, size_t lsize, - unsigned char *dp, size_t dsize) -{ - size_t len; - if (dp[0] == RT_VBUS_CHN0_CMD_DISABLE || - dp[0] == RT_VBUS_CHN0_CMD_SUSPEND || - dp[0] == RT_VBUS_CHN0_CMD_RESUME) - { - len = rt_snprintf(dst, lsize, "%s %d", - rt_vbus_cmd2str[dp[0]], dp[1]); - } - else if (dp[0] == RT_VBUS_CHN0_CMD_ENABLE) - { - len = rt_snprintf(dst, lsize, "%s %s", - rt_vbus_cmd2str[dp[0]], dp+1); - } - else if (dp[0] < RT_VBUS_CHN0_CMD_MAX) - { - len = rt_snprintf(dst, lsize, "%s %s %d", - rt_vbus_cmd2str[dp[0]], - dp+1, dp[2+rt_strlen((char*)dp+1)]); - } - else - { - len = rt_snprintf(dst, lsize, "(invalid)%d %d", - dp[0], dp[1]); - } - return len; -} - -static char _cmd_dump_buf[64]; -static char* dump_cmd_pkt(unsigned char *dp, size_t dsize) -{ - size_t len; - - if (dp[0] == RT_VBUS_CHN0_CMD_ACK || dp[0] == RT_VBUS_CHN0_CMD_NAK ) - { - len = rt_snprintf(_cmd_dump_buf, sizeof(_cmd_dump_buf), - "%s ", rt_vbus_cmd2str[dp[0]]); - len += __dump_naked_cmd(_cmd_dump_buf+len, sizeof(_cmd_dump_buf)-len, - dp+1, dsize-1); - } - else - { - len = __dump_naked_cmd(_cmd_dump_buf, sizeof(_cmd_dump_buf), - dp, dsize); - } - - if (len > sizeof(_cmd_dump_buf) - 1) - len = sizeof(_cmd_dump_buf) - 1; - - _cmd_dump_buf[len] = '\0'; - return _cmd_dump_buf; -} - -static rt_err_t _chn0_echo_with(rt_uint8_t prefix, - rt_uint32_t dsize, - unsigned char *dp) -{ - rt_err_t err; - unsigned char *resp; - - resp = rt_malloc(dsize+1); - if (!resp) - return -RT_ENOMEM; - *resp = prefix; - rt_memcpy(resp+1, dp, dsize); - vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1)); - - err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER); - - rt_free(resp); - - return err; -} - -static rt_err_t _chn0_nak(rt_uint32_t dsize, unsigned char *dp) -{ - return _chn0_echo_with(RT_VBUS_CHN0_CMD_NAK, dsize, dp); -} - -static rt_err_t _chn0_ack(rt_uint32_t dsize, unsigned char *dp) -{ - return _chn0_echo_with(RT_VBUS_CHN0_CMD_ACK, dsize, dp); -} - -enum _vbus_session_st -{ - SESSIOM_AVAILABLE, - SESSIOM_LISTENING, - SESSIOM_ESTABLISHING, -}; - -struct rt_vbus_conn_session -{ - /* negative value means error */ - int chnr; - enum _vbus_session_st st; - struct rt_completion cmp; - struct rt_vbus_request *req; -}; - -static struct rt_vbus_conn_session _sess[RT_VBUS_CHANNEL_NR/2]; - -static int _sess_find(const unsigned char *name, - enum _vbus_session_st st) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(_sess); i++) - { - if (_sess[i].st == st && _sess[i].req->name && - rt_strcmp(_sess[i].req->name, (char*)name) == 0) - break; - } - return i; -} - -static int _chn0_actor(unsigned char *dp, size_t dsize) -{ - if (*dp != RT_VBUS_CHN0_CMD_SUSPEND && *dp != RT_VBUS_CHN0_CMD_RESUME) - vbus_verbose("local <-- %s\n", dump_cmd_pkt(dp, dsize)); - - switch (*dp) - { - case RT_VBUS_CHN0_CMD_ENABLE: - { - int i, chnr; - rt_err_t err; - unsigned char *resp; - - i = _sess_find(dp+1, SESSIOM_LISTENING); - if (i == ARRAY_SIZE(_sess)) - { - _chn0_nak(dsize, dp); - break; - } - - for (chnr = 0; chnr < ARRAY_SIZE(_chn_status); chnr++) - { - if (_chn_status[chnr] == RT_VBUS_CHN_ST_AVAILABLE) - break; - } - if (chnr == ARRAY_SIZE(_chn_status)) - { - _chn0_nak(dsize, dp); - break; - } - - resp = rt_malloc(dsize + 1); - if (!resp) - break; - - *resp = RT_VBUS_CHN0_CMD_SET; - rt_memcpy(resp+1, dp+1, dsize-1); - resp[dsize] = chnr; - - rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high); - rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high); - - vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1)); - err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER); - - if (err == RT_EOK) - { - _sess[i].st = SESSIOM_ESTABLISHING; - vbus_debug("set sess %d st: %s\n", i, - rt_vbus_sess_st2str[_sess[i].st]); - _sess[i].chnr = chnr; - _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHING; - } - rt_free(resp); - } - break; - case RT_VBUS_CHN0_CMD_SET: - { - int i, chnr; - - i = _sess_find(dp+1, SESSIOM_ESTABLISHING); - if (i == ARRAY_SIZE(_sess)) - { - vbus_verbose("drop spurious packet\n"); - break; - } - - chnr = dp[1+rt_strlen((const char*)dp+1)+1]; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) - { - vbus_verbose("SET wrong chnr %d\n", chnr); - break; - } - if (_chn_status[chnr] != RT_VBUS_CHN_ST_AVAILABLE) - { - _chn0_nak(dsize, dp); - vbus_verbose("SET wrong chnr status %d, %s\n", - chnr, rt_vbus_chn_st2str[_chn_status[chnr]]); - break; - } - - rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high); - rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high); - - if (_chn0_ack(dsize, dp) >= 0) - { - _sess[i].chnr = chnr; - _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; - vbus_debug("chn %d %s\n", chnr, - rt_vbus_chn_st2str[_chn_status[chnr]]); - rt_completion_done(&_sess[i].cmp); - } - } - break; - case RT_VBUS_CHN0_CMD_ACK: - if (dp[1] == RT_VBUS_CHN0_CMD_SET) - { - int i, chnr; - - i = _sess_find(dp+2, SESSIOM_ESTABLISHING); - if (i == ARRAY_SIZE(_sess)) - /* drop that spurious packet */ - break; - - chnr = dp[1+rt_strlen((const char*)dp+2)+2]; - - _sess[i].chnr = chnr; - _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; - vbus_debug("chn %d %s\n", chnr, - rt_vbus_chn_st2str[_chn_status[chnr]]); - rt_completion_done(&_sess[i].cmp); - } - else if (dp[1] == RT_VBUS_CHN0_CMD_DISABLE) - { - unsigned char chnr = dp[2]; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) - break; - - /* We could only get here by sending DISABLE command, which is - * initiated by the rt_vbus_close_chn. */ - _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE; - - _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr); - /* notify the thread that the channel has been closed */ - rt_vbus_notify_chn(chnr, -RT_ERROR); - } - else - { - vbus_info("invalid ACK for %d\n", dp[1]); - } - break; - case RT_VBUS_CHN0_CMD_DISABLE: - { - unsigned char chnr = dp[1]; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) - break; - - _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING; - - _chn0_ack(dsize, dp); - - _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr); - /* notify the thread that the channel has been closed */ - rt_vbus_notify_chn(chnr, -RT_ERROR); - } - break; - case RT_VBUS_CHN0_CMD_SUSPEND: -#ifdef RT_VBUS_USING_FLOW_CONTROL - { - unsigned char chnr = dp[1]; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) - break; - - if (_chn_status[chnr] != RT_VBUS_CHN_ST_ESTABLISHED) - break; - - _chn_status[chnr] = RT_VBUS_CHN_ST_SUSPEND; - } -#endif - break; - case RT_VBUS_CHN0_CMD_RESUME: -#ifdef RT_VBUS_USING_FLOW_CONTROL - { - unsigned char chnr = dp[1]; - - if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) - break; - - if (_chn_status[chnr] != RT_VBUS_CHN_ST_SUSPEND) - break; - - _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; - - /* Protect the list. */ - rt_enter_critical(); - while (!rt_list_isempty(&_chn_suspended_threads[chnr])) - { - rt_thread_t thread; - - thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next); - rt_thread_resume(thread); - } - rt_exit_critical(); - } -#endif - break; - case RT_VBUS_CHN0_CMD_NAK: - if (dp[1] == RT_VBUS_CHN0_CMD_ENABLE) - { - int i; - - i = _sess_find(dp+2, SESSIOM_ESTABLISHING); - if (i == ARRAY_SIZE(_sess)) - /* drop that spurious packet */ - break; - - _sess[i].chnr = -RT_EIO; - rt_completion_done(&_sess[i].cmp); - } - else if (dp[1] == RT_VBUS_CHN0_CMD_SET) - { - vbus_info("NAK for %d not implemented\n", dp[1]); - } - else - { - vbus_info("invalid NAK for %d\n", dp[1]); - } - break; - default: - /* just ignore the invalid cmd */ - vbus_info("drop unknown cmd %d on chn0\n", *dp); - break; - }; - - return RT_EOK; -} - -int rt_vbus_request_chn(struct rt_vbus_request *req, - int timeout) -{ - int i, chnr, err; - size_t plen = rt_strlen(req->name) + 2; - unsigned char *pbuf; - rt_base_t level; - - level = rt_hw_interrupt_disable(); - for (i = 0; i < ARRAY_SIZE(_sess); i++) - { - if (_sess[i].st == SESSIOM_AVAILABLE) - break; - } - if (i == ARRAY_SIZE(_sess)) - { - rt_hw_interrupt_enable(level); - return -RT_ERROR; - } - - rt_completion_init(&_sess[i].cmp); - _sess[i].req = req; - - if (req->is_server) - { - _sess[i].st = SESSIOM_LISTENING; - rt_hw_interrupt_enable(level); - - vbus_debug("request listening %s on %d\n", req->name, i); - - /* always wait on the condition */ - err = RT_EOK; - goto _waitforcmp; - } - - pbuf = rt_malloc(plen); - if (!pbuf) - { - rt_hw_interrupt_enable(level); - return -RT_ENOMEM; - } - - _sess[i].st = SESSIOM_ESTABLISHING; - rt_hw_interrupt_enable(level); - - pbuf[0] = RT_VBUS_CHN0_CMD_ENABLE; - rt_memcpy(pbuf+1, req->name, plen-1); - vbus_verbose("%s --> remote\n", dump_cmd_pkt(pbuf, plen)); - - err = _chn0_post(pbuf, plen, RT_WAITING_FOREVER); - rt_free(pbuf); - -_waitforcmp: - if (err == RT_EOK) - err = rt_completion_wait(&_sess[i].cmp, timeout); - - vbus_debug("request wait cmp done %d, chnr %d\n", err, _sess[i].chnr); - - if (err) - { - /* cleanup the mass when the wait is time out but we have done some job - */ - if (_sess[i].st == SESSIOM_ESTABLISHING) - _chn_status[_sess[i].chnr] = RT_VBUS_CHN_ST_AVAILABLE; - chnr = err; - goto Out; - } - - RT_ASSERT(_sess[i].chnr != 0); - - chnr = _sess[i].chnr; - -Out: - /* detach the sess as we finished the job */ - _sess[i].st = SESSIOM_AVAILABLE; - _sess[i].req = RT_NULL; - - return chnr; -} - -void rt_vbus_close_chn(unsigned char chnr) -{ - void *p; - rt_err_t err; - unsigned char buf[2]; - - buf[0] = RT_VBUS_CHN0_CMD_DISABLE; - buf[1] = chnr; - - RT_ASSERT(0 < chnr && chnr < RT_VBUS_CHANNEL_NR); - - if (_chn_status[chnr] == RT_VBUS_CHN_ST_CLOSED || - _chn_status[chnr] == RT_VBUS_CHN_ST_CLOSING) - { - _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE; - return; - } - - if (!_chn_connected(chnr)) - return; - - _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING; - vbus_info("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); - err = _chn0_post(&buf, sizeof(buf), RT_WAITING_FOREVER); - if (err == RT_EOK) - /* wait for the ack */ - rt_vbus_listen_on(chnr, 10 * RT_TICK_PER_SECOND); - - /* cleanup the remaining data */ - for (p = rt_vbus_data_pop(chnr); p; p = rt_vbus_data_pop(chnr)) - rt_free(p); - /* FIXME: there is a chance that there are some data left on the send - * buffer. So if we connect other channel with the same number immediately, - * the new channel will receive some garbage data. However, this is highly - * un-probable. */ -} - -#ifdef RT_VBUS_STATISTICS -static unsigned int _total_data_sz; -#endif - -static void _bus_in_entry(void *param) -{ - rt_sem_init(&_bus_in_sem, "vbus", 0, RT_IPC_FLAG_FIFO); - rt_event_init(&_bus_in_event, "vbus", RT_IPC_FLAG_FIFO); - rt_memset(_bus_in_action, 0, sizeof(_bus_in_action)); - - while (rt_sem_take(&_bus_in_sem, - RT_WAITING_FOREVER) == RT_EOK) - { - rt_uint32_t event_set = 0; - - /* while(not empty) */ - while (RT_VBUS_IN_RING->get_idx != RT_VBUS_IN_RING->put_idx) - { - unsigned int id, nxtidx; - rt_size_t size; - struct rt_vbus_data *act; - - rt_vbus_smp_rmb(); - size = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].len; - id = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].id; - - vbus_debug("vmm bus in: chnr %d, size %d\n", id, size); - - /* Suspended channel can still recv data. */ - if (id > RT_VBUS_CHANNEL_NR || !_chn_connected(id)) - { - vbus_error("drop on invalid chn %d\n", id); - /* drop the invalid packet */ - _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); - continue; - } - - if (id == 0) - { - if (size > 60) - vbus_error("too big(%d) packet on chn0\n", size); - else - _chn0_actor(RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size); - _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); - continue; - } - -#ifdef RT_VBUS_STATISTICS - _total_data_sz += size; -#endif - - act = rt_malloc(sizeof(*act) + size); - if (act == RT_NULL) - { - //vbus_error("drop on OOM (%d, %d)\n", id, size); - /* drop the packet on malloc fall */ - _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); - continue; - } - - act->size = size; - act->next = RT_NULL; - - nxtidx = RT_VBUS_IN_RING->get_idx + LEN2BNR(size); - if (nxtidx >= RT_VMM_RB_BLK_NR) - { - unsigned int tailsz; - - tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_IN_RING->get_idx) - * sizeof(RT_VBUS_IN_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ; - - /* the remaining block is sufficient for the data */ - if (tailsz > size) - tailsz = size; - - rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, tailsz); - rt_memcpy((char*)(act+1) + tailsz, &RT_VBUS_IN_RING->blks[0], size - tailsz); - - /* It shall make sure the CPU has finished reading the item - * before it writes the new tail pointer, which will erase the - * item. */ - rt_vbus_smp_wmb(); - RT_VBUS_IN_RING->get_idx = nxtidx - RT_VMM_RB_BLK_NR; - } - else - { - rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size); - - rt_vbus_smp_wmb(); - RT_VBUS_IN_RING->get_idx = nxtidx; - } - - rt_vbus_data_push(id, act); - _vbus_indicate(RT_VBUS_EVENT_ID_RX, id); - event_set |= 1 << id; - - if (RT_VBUS_IN_RING->blocked) - rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); - } - - if (event_set != 0) - rt_vbus_notify_set(event_set); - } - RT_ASSERT(0); -} - -void rt_vbus_isr(int irqnr, void *param) -{ - if (RT_VBUS_OUT_RING->blocked) - rt_vbus_resume_out_thread(); - - rt_sem_release(&_bus_in_sem); - rt_vbus_hw_eoi(irqnr, param); -} - -int rt_vbus_init(void *outr, void *inr) -{ - int i; - - if (outr > inr) - { - RT_ASSERT((char*)outr - (char*)inr >= sizeof(struct rt_vbus_ring)); - } - else - { - RT_ASSERT((char*)inr - (char*)outr >= sizeof(struct rt_vbus_ring)); - } - - RT_VBUS_OUT_RING = outr; - RT_VBUS_IN_RING = inr; - - rt_memset(RT_VBUS_OUT_RING, 0, sizeof(*RT_VBUS_OUT_RING)); - rt_memset(RT_VBUS_IN_RING, 0, sizeof(*RT_VBUS_IN_RING)); - _chn_status[0] = RT_VBUS_CHN_ST_ESTABLISHED; - for (i = 1; i < ARRAY_SIZE(_chn_status); i++) - { - _chn_status[i] = RT_VBUS_CHN_ST_AVAILABLE; - } - for (i = 0; i < ARRAY_SIZE(_sess); i++) - { - _sess[i].req = RT_NULL; - _sess[i].st = SESSIOM_AVAILABLE; - } - _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].indicate = _chn0_tx_listener; - _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].ctx = RT_NULL; - -#ifdef RT_VBUS_USING_FLOW_CONTROL - for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++) - { - rt_wm_que_init(&_chn_wm_que[i], - RT_VMM_RB_BLK_NR / 3, - RT_VMM_RB_BLK_NR * 2 / 3); - } - /* Channel 0 has the full channel. */ - rt_wm_que_set_mark(&_chn_wm_que[0], 0, ~0); - - for (i = 0; i < ARRAY_SIZE(_chn_suspended_threads); i++) - { - rt_list_init(&_chn_suspended_threads[i]); - } - - for (i = 1; i < ARRAY_SIZE(_chn_recv_wm); i++) - { - rt_vbus_set_recv_wm(i, - RT_VMM_RB_BLK_NR / 3, - RT_VMM_RB_BLK_NR * 2 / 3); - _chn_recv_wm[i].level = 0; - _chn_recv_wm[i].last_warn = 0; - } - /* Channel 0 has the full channel. Don't suspend it. */ - _chn_recv_wm[0].low_mark = 0; - _chn_recv_wm[0].high_mark = ~0; - _chn_recv_wm[0].level = 0; - _chn_recv_wm[0].last_warn = 0; -#endif - - rt_thread_init(&_bus_out_thread, "vbusout", - _bus_out_entry, RT_NULL, - _bus_out_thread_stack, sizeof(_bus_out_thread_stack), - _BUS_OUT_THRD_PRIO, 20); - rt_thread_startup(&_bus_out_thread); - - rt_thread_init(&_bus_in_thread, "vbusin", - _bus_in_entry, RT_NULL, - _bus_in_thread_stack, sizeof(_bus_in_thread_stack), - _BUS_IN_THRD_PRIO, 20); - - - rt_thread_startup(&_bus_in_thread); - - rt_vbus_hw_init(); - - rt_kprintf("VBus loaded: %d out blocks, %d in blocks\n", - RT_VMM_RB_BLK_NR, RT_VMM_RB_BLK_NR); - - rt_vbus_chnx_init(); - - return 0; -} - -void rt_vbus_rb_dump(void) -{ - rt_kprintf("OUT ring:(%s blocked)\n", RT_VBUS_OUT_RING->blocked ? "is" : "not"); - rt_kprintf("put idx: %8x, get idx: %8x\n", - RT_VBUS_OUT_RING->put_idx, RT_VBUS_OUT_RING->get_idx); - rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_OUT_RING)); - - - rt_kprintf("IN ring:(%s blocked)\n", RT_VBUS_IN_RING->blocked ? "is" : "not"); - rt_kprintf("put idx: %8x, get idx: %8x\n", - RT_VBUS_IN_RING->put_idx, RT_VBUS_IN_RING->get_idx); - rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_IN_RING)); -} - -void rt_vbus_chn_dump(void) -{ - int i; - rt_kprintf("vbus channel status:\n"); - for (i = 0; i < ARRAY_SIZE(_chn_status); i++) - { - rt_kprintf("%2d:%s\n", i, rt_vbus_chn_st2str[_chn_status[i]]); - } -} - -void rt_vbus_sess_dump(void) -{ - int i; - - rt_kprintf("vbus conn session:\n"); - for (i = 0; i < ARRAY_SIZE(_sess); i++) - { - rt_kprintf("%2d(%s):%s\n", i, _sess[i].req ? _sess[i].req->name : "", - rt_vbus_sess_st2str[_sess[i].st]); - } -} - -void rt_vbus_que_dump(void) -{ - rt_kprintf("out que:\n"); - rt_prio_queue_dump(_bus_out_que); -} - -unsigned int rt_vbus_total_data_sz(void) -{ -#ifdef RT_VBUS_STATISTICS - return _total_data_sz; -#else - return (unsigned int)-1; -#endif -} - -void rt_vbus_data_pkt_dump(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(_bus_in_action); i++) - { - struct rt_vbus_data *dp; - -#ifdef RT_VBUS_STATISTICS - rt_kprintf("%2d %4d: ", i, _bus_in_action_nr[i]); -#else - rt_kprintf("%2d: ", i); -#endif - for (dp = _bus_in_action[i][_IN_ACT_HEAD]; - dp; - dp = dp->next) - { - rt_kprintf("%p(%d) -> ", dp, dp->size); - } - rt_kprintf(" nil\n"); - } -} - -#ifdef RT_VBUS_USING_FLOW_CONTROL -void rt_vbus_chm_wm_dump(void) -{ - int i; - - rt_kprintf("post wm:\n"); - for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++) - rt_wm_que_dump(&_chn_wm_que[i]); - - rt_kprintf("recv wm:\n"); - rt_kprintf(" low, high, cur, last warn\n"); - for (i = 0; i < ARRAY_SIZE(_chn_recv_wm); i++) - { - rt_kprintf("%8x, %8x, %8x, %8x\n", - _chn_recv_wm[i].low_mark, _chn_recv_wm[i].high_mark, - _chn_recv_wm[i].level, _chn_recv_wm[i].last_warn); - } -} -#endif - -#ifdef RT_USING_FINSH -#include <finsh.h> -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_rb_dump, vbrb, dump vbus ringbuffer status); -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chn_dump, vbchn, dump vbus channel status); -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_sess_dump, vbses, dump vbus session status); -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_que_dump, vbque, dump vbus out queue status); -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_total_data_sz, vbtsz, total in data); -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_data_pkt_dump, vbdq, dump the data queue); -#ifdef RT_VBUS_USING_FLOW_CONTROL -FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chm_wm_dump, vbwm, dump vbus water mark status); -#endif -#endif - diff --git a/components/vbus/vbus.h b/components/vbus/vbus.h deleted file mode 100644 index 661e310e6d..0000000000 --- a/components/vbus/vbus.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2014-06-09 Grissiom version 2.0.2; add comment - * 2015-01-06 Grissiom version 2.0.3; API change, no functional changes - */ -#ifndef __VBUS_H__ -#define __VBUS_H__ - -#include <vbus_api.h> - -int rt_vbus_init(void *outr, void *inr); - -void rt_vbus_resume_out_thread(void); - -/** Post data on channel. - * - * @param chnr the channel number - * @param prio the priority of the data - * @param datap pointer to the actual data - * @param size number of byte of the data - * @param timeout the value used in the blocking API - * - * Note: rt_vbus_post is an asynchronous function that when it returns, the - * @datap and @size is recorded in the post queue at least but there is no - * guarantee that the data is copied into the ring buffer. To avoid data - * corruption, you need to wait on the RT_VBUS_EVENT_ID_TX event. - * - * However, if you just post static data such as static string, there is no - * need to wait. - * - * @sa rt_vbus_register_listener . - */ -rt_err_t rt_vbus_post(rt_uint8_t chnr, - rt_uint8_t prio, - const void *datap, - rt_size_t size, - rt_int32_t timeout); - -struct rt_vbus_data { - /* Number of bytes in current data package. */ - unsigned char size; - /* Used internally in VBus. Don't modify this field as it may corrupt the - * receive queue. */ - struct rt_vbus_data *next; - /* Data follows the struct */ -}; - -struct rt_vbus_wm_cfg { - unsigned int low, high; -}; - -struct rt_vbus_request { - unsigned char prio; - const char *name; - int is_server; - struct rt_vbus_wm_cfg recv_wm, post_wm; -}; - -/** Request a channel. - * - * @return channel number. Negative if error happened. - */ -int rt_vbus_request_chn(struct rt_vbus_request *req, int timeout); - -/** Close channel @chnr */ -void rt_vbus_close_chn(unsigned char chnr); - -/** Set the water mark level for posting into the channel @chnr. */ -void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high); -/** Set the water mark level for receiving from the channel @chnr. */ -void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high); - -typedef void (*rt_vbus_event_listener)(void *ctx); - -enum rt_vbus_event_id { - /* On a packet received in channel. */ - RT_VBUS_EVENT_ID_RX, - /* On the data of rt_vbus_post has been written to the ring buffer. */ - RT_VBUS_EVENT_ID_TX, - /* On the channel has been closed. */ - RT_VBUS_EVENT_ID_DISCONN, - RT_VBUS_EVENT_ID_MAX, -}; - -/** Register callback @indi on the event @eve on the @chnr. - * - * @ctx will passed to @indi on calling the @indi. - */ -void rt_vbus_register_listener(unsigned char chnr, - enum rt_vbus_event_id eve, - rt_vbus_event_listener indi, - void *ctx); - -/** Listen on any events happen on the @chnr for @timeout ticks. - * - * This function blocks until events occur or timeout happened. - */ -rt_err_t rt_vbus_listen_on(rt_uint8_t chnr, - rt_int32_t timeout); - -/** Push a data package into the receive queue of the channel @chnr. */ -void rt_vbus_data_push(unsigned int chnr, - struct rt_vbus_data *data); -/** Pop a data package from the receive queue of the channel @chnr. - * - * The actual data is following the struct rt_vbus_data. After using it, it - * should be freed by rt_free. - */ -struct rt_vbus_data* rt_vbus_data_pop(unsigned int chnr); - -struct rt_vbus_dev -{ - /* Runtime infomations. */ - rt_uint8_t chnr; - struct rt_vbus_data *act; - rt_size_t pos; - - /* There will be a request for each channel. So no need to seperate them so - * clearly. */ - struct rt_vbus_request req; -}; - -rt_err_t rt_vbus_chnx_init(void); -/** Get the corresponding channel number from the VBus device @dev. */ -rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev); -/** Register a call back on the other side disconnect the channel. - * - * @sa rt_vbus_register_listener . - */ -void rt_vbus_chnx_register_disconn(rt_device_t dev, - rt_vbus_event_listener indi, - void *ctx); - -/* Commands for the device control interface. */ -#define VBUS_IOCRECV_WM 0xD1 -#define VBUS_IOCPOST_WM 0xD2 -/** Configure event listener */ -#define VBUS_IOC_LISCFG 0xD3 - -struct rt_vbus_dev_liscfg -{ - enum rt_vbus_event_id event; - rt_vbus_event_listener listener; - void *ctx; -}; - -int rt_vbus_shell_start(void); -#ifdef RT_USING_VBUS_RFS -int dfs_rfs_init(void); -#endif - -/** VBus hardware init function. - * - * BSP should implement this function to initialize the interrupts etc. - */ -int rt_vbus_hw_init(void); - -/** VBus ISR function. - * - * BSP should call this function when the interrupt from other core is - * triggered. @param is not used by VBus and will pass to rt_vbus_hw_eoi. - */ -void rt_vbus_isr(int irqnr, void *param); - -/** VBus End Of Interrupt function. - * - * This function will be called when VBus finished the ISR handling. BSP should - * define this function to clear the interrupt flag etc. - */ -int rt_vbus_hw_eoi(int irqnr, void *param); - -#endif /* end of include guard: __VBUS_H__ */ diff --git a/components/vbus/vbus_chnx.c b/components/vbus/vbus_chnx.c deleted file mode 100644 index 12b6af340e..0000000000 --- a/components/vbus/vbus_chnx.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-11-04 Grissiom add comment - */ - -#include <rthw.h> -#include <rtthread.h> -#include <rtdevice.h> - -#include "vbus.h" - -static void _rx_indicate(void *ctx) -{ - rt_device_t dev = ctx; - - if (dev->rx_indicate) - dev->rx_indicate(dev, 0); -} - -static void _tx_complete(void *ctx) -{ - rt_device_t dev = ctx; - - if (dev->tx_complete) - dev->tx_complete(dev, 0); -} - -static rt_err_t _open(rt_device_t dev, rt_uint16_t oflag) -{ - int chnr; - struct rt_vbus_dev *vdev = dev->user_data; - - if (vdev->chnr) - return RT_EOK; - - /* FIXME: request the same name for twice will crash */ - chnr = rt_vbus_request_chn(&vdev->req, RT_WAITING_FOREVER); - if (chnr < 0) - return chnr; - - vdev->chnr = chnr; - rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_RX, _rx_indicate, dev); - rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_TX, _tx_complete, dev); - - return RT_EOK; -} - -static rt_err_t _close(rt_device_t dev) -{ - struct rt_vbus_dev *vdev = dev->user_data; - - RT_ASSERT(vdev->chnr != 0); - - rt_vbus_close_chn(vdev->chnr); - vdev->chnr = 0; - - return RT_EOK; -} - -static rt_ssize_t _read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - rt_size_t outsz = 0; - struct rt_vbus_dev *vdev = dev->user_data; - - RT_ASSERT(vdev->chnr != 0); - - if (vdev->act == RT_NULL) - { - vdev->act = rt_vbus_data_pop(vdev->chnr); - vdev->pos = 0; - } - - while (1) - { - rt_err_t err; - - while (vdev->act) - { - rt_size_t cpysz; - - if (size - outsz > vdev->act->size - vdev->pos) - cpysz = vdev->act->size - vdev->pos; - else - cpysz = size - outsz; - - rt_memcpy((char*)buffer + outsz, ((char*)(vdev->act+1)) + vdev->pos, cpysz); - vdev->pos += cpysz; - - outsz += cpysz; - if (outsz == size) - { - return outsz; - } - else if (outsz > size) - RT_ASSERT(0); - - /* free old and get new */ - rt_free(vdev->act); - vdev->act = rt_vbus_data_pop(vdev->chnr); - vdev->pos = 0; - } - - /* TODO: We don't want to touch the rx_indicate here. But this lead to - * some duplication. Maybe we should find a better way to handle this. - */ - if (rt_interrupt_get_nest() == 0) - { - err = rt_vbus_listen_on(vdev->chnr, RT_WAITING_FOREVER); - } - else - { - err = rt_vbus_listen_on(vdev->chnr, 0); - } - if (err != RT_EOK) - { - rt_set_errno(err); - return outsz; - } - vdev->act = rt_vbus_data_pop(vdev->chnr); - vdev->pos = 0; - } -} - -static rt_ssize_t _write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - rt_err_t err; - struct rt_vbus_dev *vdev = dev->user_data; - - RT_ASSERT(vdev->chnr != 0); - - if (rt_interrupt_get_nest() == 0) - { - /* Thread context. */ - err = rt_vbus_post(vdev->chnr, vdev->req.prio, - buffer, size, RT_WAITING_FOREVER); - } - else - { - /* Interrupt context. */ - err = rt_vbus_post(vdev->chnr, vdev->req.prio, - buffer, size, 0); - } - - if (err) - { - rt_set_errno(err); - return 0; - } - - return size; -} - -rt_err_t _control(rt_device_t dev, int cmd, void *args) -{ - RT_ASSERT(dev); - - switch (cmd) { - case VBUS_IOC_LISCFG: { - struct rt_vbus_dev *vdev = dev->user_data; - struct rt_vbus_dev_liscfg *liscfg = args; - - RT_ASSERT(vdev->chnr != 0); - if (!liscfg) - return -RT_ERROR; - - rt_vbus_register_listener(vdev->chnr, liscfg->event, - liscfg->listener, liscfg->ctx); - return RT_EOK; - } - break; -#ifdef RT_VBUS_USING_FLOW_CONTROL - case VBUS_IOCRECV_WM: { - struct rt_vbus_dev *vdev = dev->user_data; - struct rt_vbus_wm_cfg *cfg; - - RT_ASSERT(vdev->chnr != 0); - - if (!args) - return -RT_ERROR; - - cfg = (struct rt_vbus_wm_cfg*)args; - if (cfg->low > cfg->high) - return -RT_ERROR; - - rt_vbus_set_recv_wm(vdev->chnr, cfg->low, cfg->high); - return RT_EOK; - } - break; - case VBUS_IOCPOST_WM: { - struct rt_vbus_dev *vdev = dev->user_data; - struct rt_vbus_wm_cfg *cfg; - - RT_ASSERT(vdev->chnr != 0); - - if (!args) - return -RT_ERROR; - - cfg = (struct rt_vbus_wm_cfg*)args; - if (cfg->low > cfg->high) - return -RT_ERROR; - - rt_vbus_set_post_wm(vdev->chnr, cfg->low, cfg->high); - return RT_EOK; - } - break; -#endif - default: - break; - }; - - return -RT_ENOSYS; -} - -rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev) -{ - struct rt_vbus_dev *vdev; - - RT_ASSERT(dev); - - vdev = dev->user_data; - - return vdev->chnr; -} - -void rt_vbus_chnx_register_disconn(rt_device_t dev, - rt_vbus_event_listener indi, - void *ctx) -{ - if (dev && dev->user_data) - { - struct rt_vbus_dev *vdev = dev->user_data; - RT_ASSERT(vdev->chnr != 0); - - rt_vbus_register_listener(vdev->chnr, RT_VBUS_EVENT_ID_DISCONN, - indi, ctx); - } -} - -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -extern struct rt_vbus_dev rt_vbus_chn_devx[]; -static struct rt_device _devx[32]; - -rt_err_t rt_vbus_chnx_init(void) -{ - int i; - struct rt_vbus_dev *p; - - for (i = 0, p = rt_vbus_chn_devx; - i < ARRAY_SIZE(_devx) && p->req.name; - i++, p++) - { - _devx[i].type = RT_Device_Class_Char; - _devx[i].open = _open; - _devx[i].close = _close; - _devx[i].read = _read; - _devx[i].write = _write; - _devx[i].control = _control; - _devx[i].user_data = p; - rt_device_register(&_devx[i], p->req.name, RT_DEVICE_FLAG_RDWR); - } - - return RT_EOK; -} diff --git a/components/vbus/watermark_queue.c b/components/vbus/watermark_queue.c deleted file mode 100644 index 59fcbc7d73..0000000000 --- a/components/vbus/watermark_queue.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2014-04-16 Grissiom first version - */ - -#include <rthw.h> -#include <rtthread.h> - -#include "watermark_queue.h" - -void rt_wm_que_set_mark(struct rt_watermark_queue *wg, - unsigned int low, unsigned int high) -{ - RT_ASSERT(low <= high); - - wg->high_mark = high; - wg->low_mark = low; -} - -void rt_wm_que_init(struct rt_watermark_queue *wg, - unsigned int low, unsigned int high) -{ - rt_wm_que_set_mark(wg, low, high); - rt_list_init(&wg->suspended_threads); - wg->level = 0; -} - -void rt_wm_que_dump(struct rt_watermark_queue *wg) -{ - struct rt_list_node *node; - - rt_kprintf("wg %p: low: %d, high: %d, cur: %d\n", - wg, wg->low_mark, wg->high_mark, wg->level); - rt_kprintf("thread suspend:"); - for (node = wg->suspended_threads.next; - node != &wg->suspended_threads; - node = node->next) - { - rt_thread_t thread; - - thread = RT_THREAD_LIST_NODE_ENTRY(wg->suspended_threads.next); - rt_kprintf(" %.*s", RT_NAME_MAX, thread->parent.name); - } - rt_kprintf("\n"); -} diff --git a/components/vbus/watermark_queue.h b/components/vbus/watermark_queue.h deleted file mode 100644 index d03ef9eeba..0000000000 --- a/components/vbus/watermark_queue.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2014-04-16 Grissiom first version - */ - -struct rt_watermark_queue -{ - /* Current water level. */ - unsigned int level; - unsigned int high_mark; - unsigned int low_mark; - rt_list_t suspended_threads; -}; - -/** Init the struct rt_watermark_queue. - */ -void rt_wm_que_init(struct rt_watermark_queue *wg, - unsigned int low, unsigned int high); -void rt_wm_que_set_mark(struct rt_watermark_queue *wg, - unsigned int low, unsigned int high); -void rt_wm_que_dump(struct rt_watermark_queue *wg); - -/* Water marks are often used in performance critical places. Benchmark shows - * inlining functions will have 10% performance gain in some situation(for - * example, VBus). So keep the inc/dec compact and inline. */ - -/** Increase the water level. - * - * It should be called in the thread that want to raise the water level. If the - * current level is above the high mark, the thread will be suspended up to - * @timeout ticks. - * - * @return RT_EOK if water level increased successfully. -RT_EFULL on @timeout - * is zero and the level is above water mark. -RT_ETIMEOUT if timeout occurred. - */ -rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg, - int timeout) -{ - rt_base_t level; - - /* Assert as early as possible. */ - if (timeout != 0) - { - RT_DEBUG_IN_THREAD_CONTEXT; - } - - level = rt_hw_interrupt_disable(); - - while (wg->level > wg->high_mark) - { - rt_thread_t thread; - - if (timeout == 0) - { - rt_hw_interrupt_enable(level); - return -RT_EFULL; - } - - thread = rt_thread_self(); - thread->error = RT_EOK; - rt_thread_suspend(thread); - rt_list_insert_after(&wg->suspended_threads, &RT_THREAD_LIST_NODE(thread)); - if (timeout > 0) - { - rt_tick_t timeout_tick = timeout; - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout_tick); - rt_timer_start(&(thread->thread_timer)); - } - rt_hw_interrupt_enable(level); - rt_schedule(); - if (thread->error != RT_EOK) - return thread->error; - - level = rt_hw_interrupt_disable(); - } - - wg->level++; - - if (wg->level == 0) - { - wg->level = ~0; - } - - rt_hw_interrupt_enable(level); - - return RT_EOK; -} - -/** Decrease the water level. - * - * It should be called by the consumer that drain the water out. If the water - * level reached low mark, all the thread suspended in this queue will be waken - * up. It's safe to call this function in interrupt context. - */ -rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg) -{ - int need_sched = 0; - rt_base_t level; - - if (wg->level == 0) - return; - - level = rt_hw_interrupt_disable(); - wg->level--; - if (wg->level == wg->low_mark) - { - /* There should be spaces between the low mark and high mark, so it's - * safe to resume all the threads. */ - while (!rt_list_isempty(&wg->suspended_threads)) - { - rt_thread_t thread; - - thread = RT_THREAD_LIST_NODE_ENTRY(wg->suspended_threads.next); - rt_thread_resume(thread); - need_sched = 1; - } - } - rt_hw_interrupt_enable(level); - - if (need_sched) - rt_schedule(); -} |
