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 "gpio_dev.h"
32 #include "fcntl.h"
33 #include "fs/driver.h"
34 #include "gpio_core.h"
35 #include "gpio_if.h"
36 #include "hdf_base.h"
37 #include "hdf_log.h"
38 #include "osal_mem.h"
39 #include "user_copy.h"
40 
GpioOpen(struct file * filep)41 static int GpioOpen(struct file *filep)
42 {
43     (void)filep;
44     return 0;
45 }
46 
GpioClose(struct file * filep)47 static int GpioClose(struct file *filep)
48 {
49     (void)filep;
50     return 0;
51 }
52 
GpioExecCmd(uint16_t gpio,struct GpioBitInfo * info,int cmd)53 static int GpioExecCmd(uint16_t gpio, struct GpioBitInfo *info, int cmd)
54 {
55     int32_t ret;
56     uint16_t tmp;
57 
58     switch (cmd) {
59         case GPIO_SET_DIR:
60             ret = GpioSetDir(gpio, info->direction);
61             if (ret != HDF_SUCCESS) {
62                 HDF_LOGE("GpioExecCmd: set dir fail, ret: %d!", ret);
63                 return -1;
64             }
65             PLAT_LOGV("GpioExecCmd: gpio:%hu set dir:%u done!", gpio, info->direction);
66             break;
67         case GPIO_GET_DIR:
68             ret = GpioGetDir(gpio, &tmp);
69             if (ret != HDF_SUCCESS) {
70                 HDF_LOGE("GpioExecCmd: get dir fail, ret: %d!", ret);
71                 return -1;
72             }
73             info->direction = (unsigned char)tmp;
74             PLAT_LOGV("GpioExecCmd: gpio:%hu get dir:%u done!", gpio, info->direction);
75             break;
76         case GPIO_READ_BIT:
77             ret = GpioRead(gpio, &tmp);
78             if (ret != HDF_SUCCESS) {
79                 HDF_LOGE("GpioExecCmd: read gpio fail, ret: %d!", ret);
80                 return -1;
81             }
82             info->value = (unsigned char)tmp;
83             PLAT_LOGV("GpioExecCmd: gpio:%hu read:%u done!", gpio, info->value);
84             break;
85         case GPIO_WRITE_BIT:
86             ret = GpioWrite(gpio, info->value);
87             if (ret != HDF_SUCCESS) {
88                 HDF_LOGE("GpioExecCmd: write gpio fail, ret: %d!", ret);
89                 return -1;
90             }
91             PLAT_LOGV("GpioExecCmd: gpio:%hu write:%u done!", gpio, info->value);
92             break;
93         default:
94             return -1;
95     }
96     return 0;
97 }
98 
GpioIoctl(struct file * filep,int cmd,unsigned long arg)99 static int GpioIoctl(struct file *filep, int cmd, unsigned long arg)
100 {
101     int ret;
102     uint16_t bitNum;
103     uint16_t gpio;
104     struct GpioBitInfo info = {0};
105     struct drv_data *drvData = NULL;
106 
107     if (arg == 0) {
108         HDF_LOGE("GpioIoctl: arg is 0!");
109         return HDF_ERR_INVALID_PARAM;
110     }
111 
112     if (filep == NULL || filep->f_vnode == NULL || filep->f_vnode->data == NULL) {
113         HDF_LOGE("GpioIoctl: function parameter is null!");
114         return HDF_ERR_INVALID_PARAM;
115     }
116 
117     drvData = (struct drv_data *)filep->f_vnode->data;
118     bitNum = (uint16_t)(uintptr_t)drvData->priv;
119 
120     ret = LOS_CopyToKernel(&info, sizeof(struct GpioBitInfo),
121         (const VOID *)(uintptr_t)arg, sizeof(struct GpioBitInfo));
122     if (ret != 0) {
123         return -1;
124     }
125     gpio = info.groupnumber * bitNum + info.bitnumber;
126     PLAT_LOGV("GpioIoctl: gn:%u, bn:%u, gpio:%hu!", info.groupnumber, info.bitnumber, gpio);
127 
128     ret = GpioExecCmd(gpio, &info, cmd);
129     if (ret != 0) {
130         return -1;
131     }
132 
133     if ((unsigned int)cmd == GPIO_GET_DIR || (unsigned int)cmd == GPIO_READ_BIT) {
134         ret = LOS_CopyFromKernel((VOID *)(uintptr_t)arg, sizeof(struct GpioBitInfo),
135             &info, sizeof(struct GpioBitInfo));
136         if (ret != 0) {
137             HDF_LOGE("GpioIoctl: copy back fail, ret: %d!", ret);
138             return -1;
139         }
140     }
141     return 0;
142 }
143 
144 static const struct file_operations_vfs g_gpioDevOps = {
145     .open = GpioOpen,
146     .close = GpioClose,
147     .ioctl = GpioIoctl,
148 };
149 
150 #define GPIO_VFS_MODE 0660
151 #define GPIO_VFS_NAME "/dev/gpio"
GpioAddVfs(uint16_t bitNum)152 int32_t GpioAddVfs(uint16_t bitNum)
153 {
154     int ret;
155 
156     ret = register_driver(GPIO_VFS_NAME, &g_gpioDevOps, GPIO_VFS_MODE, (void *)(uintptr_t)bitNum);
157     if (ret != 0) {
158         HDF_LOGE("GpioAddVfs: register vfs fail, ret: %d!", ret);
159         return HDF_FAILURE;
160     }
161     HDF_LOGI("GpioAddVfs: register vfs success!");
162     return HDF_SUCCESS;
163 }
164 
GpioRemoveVfs(void)165 void GpioRemoveVfs(void)
166 {
167     int ret;
168 
169     ret = unregister_driver(GPIO_VFS_NAME);
170     if (ret != 0) {
171         HDF_LOGE("GpioRemoveVfs: unregister vfs fail, ret: %d!", ret);
172     }
173 }
174