| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 | /* * COPYRIGHT (C) 2018, 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_size_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_size_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){    struct rt_vbus_dev *vdev = dev->user_data;    RT_ASSERT(vdev->chnr != 0);    if (vdev)        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;}
 |