xref: /nrf52832-nimble/rt-thread/components/vbus/vbus_chnx.c (revision 104654410c56c573564690304ae786df310c91fc)
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 
_rx_indicate(void * ctx)17 static void _rx_indicate(void *ctx)
18 {
19     rt_device_t dev = ctx;
20 
21     if (dev->rx_indicate)
22         dev->rx_indicate(dev, 0);
23 }
24 
_tx_complete(void * ctx)25 static void _tx_complete(void *ctx)
26 {
27     rt_device_t dev = ctx;
28 
29     if (dev->tx_complete)
30         dev->tx_complete(dev, 0);
31 }
32 
_open(rt_device_t dev,rt_uint16_t oflag)33 static rt_err_t _open(rt_device_t dev, rt_uint16_t oflag)
34 {
35     int chnr;
36     struct rt_vbus_dev *vdev = dev->user_data;
37 
38     if (vdev->chnr)
39         return RT_EOK;
40 
41     /* FIXME: request the same name for twice will crash */
42     chnr = rt_vbus_request_chn(&vdev->req, RT_WAITING_FOREVER);
43     if (chnr < 0)
44         return chnr;
45 
46     vdev->chnr = chnr;
47     rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_RX, _rx_indicate, dev);
48     rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_TX, _tx_complete, dev);
49 
50     return RT_EOK;
51 }
52 
_close(rt_device_t dev)53 static rt_err_t _close(rt_device_t dev)
54 {
55     struct rt_vbus_dev *vdev = dev->user_data;
56 
57     RT_ASSERT(vdev->chnr != 0);
58 
59     rt_vbus_close_chn(vdev->chnr);
60     vdev->chnr = 0;
61 
62     return RT_EOK;
63 }
64 
_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)65 static rt_size_t _read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
66 {
67     rt_size_t outsz = 0;
68     struct rt_vbus_dev *vdev = dev->user_data;
69 
70     RT_ASSERT(vdev->chnr != 0);
71 
72     if (vdev->act == RT_NULL)
73     {
74         vdev->act = rt_vbus_data_pop(vdev->chnr);
75         vdev->pos = 0;
76     }
77 
78     while (1)
79     {
80         rt_err_t err;
81 
82         while (vdev->act)
83         {
84             rt_size_t cpysz;
85 
86             if (size - outsz > vdev->act->size - vdev->pos)
87                 cpysz = vdev->act->size - vdev->pos;
88             else
89                 cpysz = size - outsz;
90 
91             rt_memcpy((char*)buffer + outsz, ((char*)(vdev->act+1)) + vdev->pos, cpysz);
92             vdev->pos += cpysz;
93 
94             outsz += cpysz;
95             if (outsz == size)
96             {
97                 return outsz;
98             }
99             else if (outsz > size)
100                 RT_ASSERT(0);
101 
102             /* free old and get new */
103             rt_free(vdev->act);
104             vdev->act = rt_vbus_data_pop(vdev->chnr);
105             vdev->pos = 0;
106         }
107 
108         /* TODO: We don't want to touch the rx_indicate here. But this lead to
109          * some duplication. Maybe we should find a better way to handle this.
110          */
111         if (rt_interrupt_get_nest() == 0)
112         {
113             err = rt_vbus_listen_on(vdev->chnr, RT_WAITING_FOREVER);
114         }
115         else
116         {
117             err = rt_vbus_listen_on(vdev->chnr, 0);
118         }
119         if (err != RT_EOK)
120         {
121             rt_set_errno(err);
122             return outsz;
123         }
124         vdev->act = rt_vbus_data_pop(vdev->chnr);
125         vdev->pos = 0;
126     }
127 }
128 
_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)129 static rt_size_t _write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
130 {
131     rt_err_t err;
132     struct rt_vbus_dev *vdev = dev->user_data;
133 
134     RT_ASSERT(vdev->chnr != 0);
135 
136     if (rt_interrupt_get_nest() == 0)
137     {
138         /* Thread context. */
139         err = rt_vbus_post(vdev->chnr, vdev->req.prio,
140                            buffer, size, RT_WAITING_FOREVER);
141     }
142     else
143     {
144         /* Interrupt context. */
145         err = rt_vbus_post(vdev->chnr, vdev->req.prio,
146                            buffer, size, 0);
147     }
148 
149     if (err)
150     {
151         rt_set_errno(err);
152         return 0;
153     }
154 
155     return size;
156 }
157 
_control(rt_device_t dev,int cmd,void * args)158 rt_err_t  _control(rt_device_t dev, int cmd, void *args)
159 {
160     RT_ASSERT(dev);
161 
162     switch (cmd) {
163     case VBUS_IOC_LISCFG: {
164         struct rt_vbus_dev *vdev = dev->user_data;
165         struct rt_vbus_dev_liscfg *liscfg = args;
166 
167         RT_ASSERT(vdev->chnr != 0);
168         if (!liscfg)
169             return -RT_ERROR;
170 
171         rt_vbus_register_listener(vdev->chnr, liscfg->event,
172                                   liscfg->listener, liscfg->ctx);
173         return RT_EOK;
174     }
175         break;
176 #ifdef RT_VBUS_USING_FLOW_CONTROL
177     case VBUS_IOCRECV_WM: {
178         struct rt_vbus_dev *vdev = dev->user_data;
179         struct rt_vbus_wm_cfg *cfg;
180 
181         RT_ASSERT(vdev->chnr != 0);
182 
183         if (!args)
184             return -RT_ERROR;
185 
186         cfg = (struct rt_vbus_wm_cfg*)args;
187         if (cfg->low > cfg->high)
188             return -RT_ERROR;
189 
190         rt_vbus_set_recv_wm(vdev->chnr, cfg->low, cfg->high);
191         return RT_EOK;
192     }
193         break;
194     case VBUS_IOCPOST_WM: {
195         struct rt_vbus_dev *vdev = dev->user_data;
196         struct rt_vbus_wm_cfg *cfg;
197 
198         RT_ASSERT(vdev->chnr != 0);
199 
200         if (!args)
201             return -RT_ERROR;
202 
203         cfg = (struct rt_vbus_wm_cfg*)args;
204         if (cfg->low > cfg->high)
205             return -RT_ERROR;
206 
207         rt_vbus_set_post_wm(vdev->chnr, cfg->low, cfg->high);
208         return RT_EOK;
209     }
210         break;
211 #endif
212     default:
213         break;
214     };
215 
216     return -RT_ENOSYS;
217 }
218 
rt_vbus_get_chnnr(rt_device_t dev)219 rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev)
220 {
221     struct rt_vbus_dev *vdev;
222 
223     RT_ASSERT(dev);
224 
225     vdev = dev->user_data;
226 
227     return vdev->chnr;
228 }
229 
rt_vbus_chnx_register_disconn(rt_device_t dev,rt_vbus_event_listener indi,void * ctx)230 void rt_vbus_chnx_register_disconn(rt_device_t dev,
231                                    rt_vbus_event_listener indi,
232                                    void *ctx)
233 {
234     struct rt_vbus_dev *vdev = dev->user_data;
235 
236     RT_ASSERT(vdev->chnr != 0);
237 
238     if (vdev)
239         rt_vbus_register_listener(vdev->chnr, RT_VBUS_EVENT_ID_DISCONN,
240                                   indi, ctx);
241 }
242 
243 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
244 
245 extern struct rt_vbus_dev rt_vbus_chn_devx[];
246 static struct rt_device _devx[32];
247 
rt_vbus_chnx_init(void)248 rt_err_t rt_vbus_chnx_init(void)
249 {
250     int i;
251     struct rt_vbus_dev *p;
252 
253     for (i = 0,                   p = rt_vbus_chn_devx;
254          i < ARRAY_SIZE(_devx) && p->req.name;
255          i++,                     p++)
256     {
257         _devx[i].type      = RT_Device_Class_Char;
258         _devx[i].open      = _open;
259         _devx[i].close     = _close;
260         _devx[i].read      = _read;
261         _devx[i].write     = _write;
262         _devx[i].control   = _control;
263         _devx[i].user_data = p;
264         rt_device_register(&_devx[i], p->req.name, RT_DEVICE_FLAG_RDWR);
265     }
266 
267     return RT_EOK;
268 }
269