import RT-Thread@9217865c without bsp, libcpu and components/net

This commit is contained in:
Zihao Yu 2023-05-20 16:23:33 +08:00
commit e2376a3709
1414 changed files with 390370 additions and 0 deletions

58
components/vbus/Kconfig Normal file
View file

@ -0,0 +1,58 @@
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
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

View file

@ -0,0 +1,23 @@
# 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')

View file

@ -0,0 +1,257 @@
/*
* 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_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist);
/* 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_list_entry(que->suspended_pop_list.next,
struct rt_thread,
tlist);
/* 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), &(thread->tlist));
if (timeout > 0)
{
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
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");
}
}

View file

@ -0,0 +1,54 @@
/*
* 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__ */

View file

@ -0,0 +1,89 @@
/*
* 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__ */

1321
components/vbus/vbus.c Normal file

File diff suppressed because it is too large Load diff

177
components/vbus/vbus.h Normal file
View file

@ -0,0 +1,177 @@
/*
* 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__ */

269
components/vbus/vbus_chnx.c Normal file
View file

@ -0,0 +1,269 @@
/*
* 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;
}

View file

@ -0,0 +1,52 @@
/*
* 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_list_entry(wg->suspended_threads.next,
struct rt_thread,
tlist);
rt_kprintf(" %.*s", RT_NAME_MAX, thread->parent.name);
}
rt_kprintf("\n");
}

View file

@ -0,0 +1,130 @@
/*
* 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, &thread->tlist);
if (timeout > 0)
{
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
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_list_entry(wg->suspended_threads.next,
struct rt_thread,
tlist);
rt_thread_resume(thread);
need_sched = 1;
}
}
rt_hw_interrupt_enable(level);
if (need_sched)
rt_schedule();
}