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 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 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 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 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 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 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 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 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 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 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