1 /*
2 * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "fs/driver.h"
32 #include "securec.h"
33 #include "user_copy.h"
34 #include "hdf_log.h"
35 #include "osal_mem.h"
36 #include "uart_dev.h"
37
38 #define HDF_LOG_TAG hdf_uart_dev
39 #define HDF_UART_FS_MODE 0660
40 #define ARG_MAX_RANG 0xFFFFFFFF
41
UartDevOpen(struct file * filep)42 static int32_t UartDevOpen(struct file *filep)
43 {
44 struct UartHost *host = NULL;
45
46 if (filep == NULL || filep->f_vnode == NULL) {
47 HDF_LOGE("UartDevOpen: filep or f_vnode is null!");
48 return HDF_ERR_INVALID_PARAM;
49 }
50 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
51 host = (struct UartHost *)drv->priv;
52 return UartHostRequest(host);
53 }
54
UartDevRelease(struct file * filep)55 static int32_t UartDevRelease(struct file *filep)
56 {
57 struct UartHost *host = NULL;
58
59 if (filep == NULL || filep->f_vnode == NULL) {
60 HDF_LOGE("UartDevRelease: filep or f_vnode is null!");
61 return HDF_ERR_INVALID_PARAM;
62 }
63 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
64 host = (struct UartHost *)drv->priv;
65
66 return UartHostRelease(host);
67 }
68
UartDevRead(struct file * filep,char * buf,size_t count)69 static ssize_t UartDevRead(struct file *filep, char *buf, size_t count)
70 {
71 int32_t size;
72 int32_t ret = LOS_OK;
73 uint8_t *tmpBuf = NULL;
74 struct UartHost *host = NULL;
75
76 if (filep == NULL || filep->f_vnode == NULL) {
77 HDF_LOGE("UartDevRead: filep or f_vnode is null!");
78 return HDF_ERR_INVALID_PARAM;
79 }
80 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
81 host = (struct UartHost *)drv->priv;
82
83 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
84 tmpBuf = (uint8_t *)OsalMemCalloc(count);
85 if (tmpBuf == NULL) {
86 HDF_LOGE("UartDevRead: OsalMemCalloc error!");
87 return HDF_ERR_MALLOC_FAIL;
88 }
89 size = UartHostRead(host, tmpBuf, count);
90 if (size > 0) {
91 ret = (int32_t)LOS_ArchCopyToUser(buf, tmpBuf, size);
92 }
93 OsalMemFree(tmpBuf);
94 return ret != LOS_OK ? ret : size;
95 } else {
96 return UartHostRead(host, (uint8_t *)buf, count);
97 }
98 }
99
UartDevWrite(struct file * filep,const char * buf,size_t count)100 static ssize_t UartDevWrite(struct file *filep, const char *buf, size_t count)
101 {
102 int32_t ret;
103 uint8_t *tmpBuf = NULL;
104 struct UartHost *host = NULL;
105
106 if (filep == NULL || filep->f_vnode == NULL) {
107 HDF_LOGE("UartDevWrite: filep or f_vnode is null!");
108 return HDF_ERR_INVALID_PARAM;
109 }
110 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
111 host = (struct UartHost *)drv->priv;
112
113 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
114 tmpBuf = (uint8_t *)OsalMemCalloc(count);
115 if (tmpBuf == NULL) {
116 HDF_LOGE("UartDevWrite: OsalMemCalloc error!");
117 return HDF_ERR_MALLOC_FAIL;
118 }
119 ret = (int32_t)LOS_ArchCopyFromUser(tmpBuf, buf, count);
120 if (ret != LOS_OK) {
121 OsalMemFree(tmpBuf);
122 return ret;
123 }
124 ret = UartHostWrite(host, tmpBuf, count);
125 OsalMemFree(tmpBuf);
126 return ret;
127 } else {
128 return UartHostWrite(host, (uint8_t *)buf, count);
129 }
130 }
131
UartCfgAttr(struct UartHost * host,unsigned long arg)132 static int32_t UartCfgAttr(struct UartHost *host, unsigned long arg)
133 {
134 int32_t ret;
135 struct UartAttribute attr;
136 int32_t len = sizeof(struct UartAttribute);
137
138 if (!LOS_IsUserAddressRange((vaddr_t)arg, len)) {
139 ret = memcpy_s((void *)&attr, len, (void *)arg, len);
140 } else {
141 ret = (int32_t)LOS_ArchCopyFromUser(&attr, (void *)(uintptr_t)arg, len);
142 }
143 if (ret != LOS_OK) {
144 return ret;
145 }
146 ret = UartHostSetAttribute(host, &attr);
147 return ret;
148 }
149
UartDevIoctl(struct file * filep,int32_t cmd,unsigned long arg)150 static int32_t UartDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
151 {
152 int32_t ret = HDF_FAILURE;
153 struct UartHost *host = NULL;
154
155 if (arg == 0) {
156 HDF_LOGE("UartDevIoctl: arg is 0!");
157 return HDF_ERR_INVALID_PARAM;
158 }
159
160 if (filep == NULL || filep->f_vnode == NULL) {
161 HDF_LOGE("UartDevIoctl: filep or f_vnode is null!");
162 return HDF_ERR_INVALID_PARAM;
163 }
164 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
165 host = (struct UartHost *)drv->priv;
166
167 switch (cmd) {
168 case UART_CFG_BAUDRATE:
169 if (arg > ARG_MAX_RANG) {
170 HDF_LOGE("UartDevIoctl: arg out of range!");
171 ret = HDF_ERR_INVALID_PARAM;
172 break;
173 }
174 ret = UartHostSetBaud(host, arg);
175 break;
176 case UART_CFG_RD_BLOCK:
177 if (arg == UART_RD_BLOCK) {
178 ret = UartHostSetTransMode(host, UART_MODE_RD_BLOCK);
179 } else if (arg == UART_RD_NONBLOCK) {
180 ret = UartHostSetTransMode(host, UART_MODE_RD_NONBLOCK);
181 }
182 break;
183 case UART_CFG_ATTR:
184 ret = UartCfgAttr(host, arg);
185 break;
186 case TIOCGWINSZ:
187 /* Simply support ioctl(f->fd, TIOCGWINSZ, &wsz) system call, and the detailed design will be done later */
188 ret = LOS_OK;
189 break;
190 default:
191 HDF_LOGE("UartDevIoctl: cmd %d is not support!", cmd);
192 ret = HDF_ERR_NOT_SUPPORT;
193 break;
194 }
195 return ret;
196 }
197 extern void poll_wait(struct file *filp,
198 wait_queue_head_t *wait_address, poll_table *p);
uartdev_poll(struct file * filep,poll_table * table)199 static int uartdev_poll(struct file *filep, poll_table *table)
200 {
201 struct UartHost *host = NULL;
202
203 if (filep == NULL || filep->f_vnode == NULL) {
204 HDF_LOGE("uartdev_poll: filep or f_vnode is null!");
205 return HDF_ERR_INVALID_PARAM;
206 }
207 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
208 host = (struct UartHost *)drv->priv;
209
210 return UartHostPollEvent(host, filep, table);
211 }
212
213 static const struct file_operations_vfs g_uartDevFops = {
214 .open = UartDevOpen,
215 .close = UartDevRelease,
216 .read = UartDevRead,
217 .write = UartDevWrite,
218 .ioctl = UartDevIoctl,
219 #ifndef CONFIG_DISABLE_POLL
220 .poll = uartdev_poll,
221 #endif
222
223 };
224
225 #define MAX_DEV_NAME_SIZE 32
UartAddRemoveDev(struct UartHost * host,bool add)226 static void UartAddRemoveDev(struct UartHost *host, bool add)
227 {
228 int32_t ret;
229 char *devName = NULL;
230
231 if (host == NULL || host->priv == NULL) {
232 HDF_LOGE("UartAddRemoveDev: invalid parameter!");
233 return;
234 }
235
236 devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
237 if (devName == NULL) {
238 HDF_LOGE("UartAddRemoveDev: OsalMemCalloc error!");
239 return;
240 }
241 ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num);
242 if (ret < 0) {
243 HDF_LOGE("UartAddRemoveDev snprintf_s fail!");
244 OsalMemFree(devName);
245 return;
246 }
247 if (add) {
248 HDF_LOGI("create /dev/uartdev-%d", host->num);
249 if (register_driver(devName, &g_uartDevFops, HDF_UART_FS_MODE, host) != HDF_SUCCESS) {
250 HDF_LOGE("UartAddRemoveDev: gen /dev/uartdev-%d fail!", host->num);
251 OsalMemFree(devName);
252 return;
253 }
254 } else {
255 if (unregister_driver(devName) != HDF_SUCCESS) {
256 HDF_LOGE("UartAddRemoveDev: remove /dev/uartdev-%d fail!", host->num);
257 OsalMemFree(devName);
258 return;
259 }
260 }
261 OsalMemFree(devName);
262 }
263
UartAddDev(struct UartHost * host)264 void UartAddDev(struct UartHost *host)
265 {
266 UartAddRemoveDev(host, true);
267 }
268
UartRemoveDev(struct UartHost * host)269 void UartRemoveDev(struct UartHost *host)
270 {
271 UartAddRemoveDev(host, false);
272 }
273