1 /*
2 * Copyright (c) 2020-2021 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 return HDF_ERR_INVALID_PARAM;
48 }
49 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
50 host = (struct UartHost *)drv->priv;
51 return UartHostRequest(host);
52 }
UartDevRelease(struct file * filep)53 static int32_t UartDevRelease(struct file *filep)
54 {
55 struct UartHost *host = NULL;
56
57 if (filep == NULL || filep->f_vnode == NULL) {
58 return HDF_ERR_INVALID_PARAM;
59 }
60 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
61 host = (struct UartHost *)drv->priv;
62
63 return UartHostRelease(host);
64 }
65
UartDevRead(struct file * filep,char * buf,size_t count)66 static ssize_t UartDevRead(struct file *filep, char *buf, size_t count)
67 {
68 int32_t size;
69 int32_t ret = LOS_OK;
70 uint8_t *tmpBuf = NULL;
71 struct UartHost *host = NULL;
72
73 if (filep == NULL || filep->f_vnode == NULL) {
74 return HDF_ERR_INVALID_PARAM;
75 }
76 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
77 host = (struct UartHost *)drv->priv;
78
79 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
80 tmpBuf = (uint8_t *)OsalMemCalloc(count);
81 if (tmpBuf == NULL) {
82 HDF_LOGE("%s: OsalMemCalloc error", __func__);
83 return HDF_ERR_MALLOC_FAIL;
84 }
85 size = UartHostRead(host, tmpBuf, count);
86 if (size > 0) {
87 ret = (int32_t)LOS_ArchCopyToUser(buf, tmpBuf, size);
88 }
89 OsalMemFree(tmpBuf);
90 return ret != LOS_OK ? ret : size;
91 } else {
92 return UartHostRead(host, (uint8_t *)buf, count);
93 }
94 }
95
UartDevWrite(struct file * filep,const char * buf,size_t count)96 static ssize_t UartDevWrite(struct file *filep, const char *buf, size_t count)
97 {
98 int32_t ret;
99 uint8_t *tmpBuf = NULL;
100 struct UartHost *host = NULL;
101
102 if (filep == NULL || filep->f_vnode == NULL) {
103 return HDF_ERR_INVALID_PARAM;
104 }
105 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
106 host = (struct UartHost *)drv->priv;
107
108 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) {
109 tmpBuf = (uint8_t *)OsalMemCalloc(count);
110 if (tmpBuf == NULL) {
111 HDF_LOGE("%s: OsalMemCalloc error", __func__);
112 return HDF_ERR_MALLOC_FAIL;
113 }
114 ret = (int32_t)LOS_ArchCopyFromUser(tmpBuf, buf, count);
115 if (ret != LOS_OK) {
116 OsalMemFree(tmpBuf);
117 return ret;
118 }
119 ret = UartHostWrite(host, tmpBuf, count);
120 OsalMemFree(tmpBuf);
121 return ret;
122 } else {
123 return UartHostWrite(host, (uint8_t *)buf, count);
124 }
125 }
126
UartCfgAttr(struct UartHost * host,unsigned long arg)127 static int32_t UartCfgAttr(struct UartHost *host, unsigned long arg)
128 {
129 int32_t ret;
130 struct UartAttribute attr;
131 int32_t len = sizeof(struct UartAttribute);
132
133 if (!LOS_IsUserAddressRange((vaddr_t)arg, len)) {
134 ret = memcpy_s((void *)&attr, len, (void *)arg, len);
135 } else {
136 ret = (int32_t)LOS_ArchCopyFromUser(&attr, (void *)(uintptr_t)arg, len);
137 }
138 if (ret != LOS_OK) {
139 return ret;
140 }
141 ret = UartHostSetAttribute(host, &attr);
142 return ret;
143 }
144
UartDevIoctl(struct file * filep,int32_t cmd,unsigned long arg)145 static int32_t UartDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
146 {
147 int32_t ret = HDF_FAILURE;
148 struct UartHost *host = NULL;
149
150 if (arg == 0) {
151 HDF_LOGE("%s arg is 0", __func__);
152 return HDF_ERR_INVALID_PARAM;
153 }
154
155 if (filep == NULL || filep->f_vnode == NULL) {
156 return HDF_ERR_INVALID_PARAM;
157 }
158 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
159 host = (struct UartHost *)drv->priv;
160
161 switch (cmd) {
162 case UART_CFG_BAUDRATE:
163 if (arg > ARG_MAX_RANG) {
164 HDF_LOGE("%s arg out of range", __func__);
165 ret = HDF_ERR_INVALID_PARAM;
166 break;
167 }
168 ret = UartHostSetBaud(host, arg);
169 break;
170 case UART_CFG_RD_BLOCK:
171 if (arg == UART_RD_BLOCK) {
172 ret = UartHostSetTransMode(host, UART_MODE_RD_BLOCK);
173 } else if (arg == UART_RD_NONBLOCK) {
174 ret = UartHostSetTransMode(host, UART_MODE_RD_NONBLOCK);
175 }
176 break;
177 case UART_CFG_ATTR:
178 ret = UartCfgAttr(host, arg);
179 break;
180 case TIOCGWINSZ:
181 /* Simply support ioctl(f->fd, TIOCGWINSZ, &wsz) system call, and the detailed design will be done later */
182 ret = LOS_OK;
183 break;
184 default:
185 HDF_LOGE("%s cmd %d not support", __func__, cmd);
186 ret = HDF_ERR_NOT_SUPPORT;
187 break;
188 }
189 return ret;
190 }
191 extern void poll_wait(struct file *filp,
192 wait_queue_head_t *wait_address, poll_table *p);
uartdev_poll(struct file * filep,poll_table * table)193 static int uartdev_poll(struct file *filep, poll_table *table)
194 {
195 struct UartHost *host = NULL;
196
197 if (filep == NULL || filep->f_vnode == NULL) {
198 return HDF_ERR_INVALID_PARAM;
199 }
200 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
201 host = (struct UartHost *)drv->priv;
202
203 return UartHostPollEvent(host, filep, table);
204 }
205
206 static const struct file_operations_vfs g_uartDevFops = {
207 .open = UartDevOpen,
208 .close = UartDevRelease,
209 .read = UartDevRead,
210 .write = UartDevWrite,
211 .ioctl = UartDevIoctl,
212 #ifndef CONFIG_DISABLE_POLL
213 .poll = uartdev_poll,
214 #endif
215
216 };
217
218 #define MAX_DEV_NAME_SIZE 32
UartAddRemoveDev(struct UartHost * host,bool add)219 static void UartAddRemoveDev(struct UartHost *host, bool add)
220 {
221 int32_t ret;
222 char *devName = NULL;
223
224 if (host == NULL || host->priv == NULL) {
225 HDF_LOGE("%s invalid parameter", __func__);
226 return;
227 }
228
229 devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
230 if (devName == NULL) {
231 HDF_LOGE("%s: OsalMemCalloc error", __func__);
232 return;
233 }
234 ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num);
235 if (ret < 0) {
236 HDF_LOGE("%s snprintf_s failed", __func__);
237 OsalMemFree(devName);
238 return;
239 }
240 if (add) {
241 HDF_LOGI("create /dev/uartdev-%d", host->num);
242 if (register_driver(devName, &g_uartDevFops, HDF_UART_FS_MODE, host) != HDF_SUCCESS) {
243 HDF_LOGE("%s: gen /dev/uartdev-%d fail!", __func__, host->num);
244 OsalMemFree(devName);
245 return;
246 }
247 } else {
248 if (unregister_driver(devName) != HDF_SUCCESS) {
249 HDF_LOGE("%s: remove /dev/uartdev-%d fail!", __func__, host->num);
250 OsalMemFree(devName);
251 return;
252 }
253 }
254 OsalMemFree(devName);
255 }
256
UartAddDev(struct UartHost * host)257 void UartAddDev(struct UartHost *host)
258 {
259 UartAddRemoveDev(host, true);
260 }
261
UartRemoveDev(struct UartHost * host)262 void UartRemoveDev(struct UartHost *host)
263 {
264 UartAddRemoveDev(host, false);
265 }
266