1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <poll.h>
6
7 #include <aos/driver/wdg.h>
8 #include <vfsdev/wdg_dev.h>
9 #include <devicevfs/devicevfs.h>
10
11 #ifdef CONFIG_WDG_NUM
12 #define PLATFORM_WDG_NUM CONFIG_WDG_NUM
13 #else
14 #define PLATFORM_WDG_NUM 1
15 #endif
16
17 #if (PLATFORM_WDG_NUM > 0)
18
19 // WDG device node will be named with "/dev/wdg<x>", where <x> is wdg port id
20 #define WDG_DEV_NAME_FORMAT "wdg%d"
21
22 typedef struct vfs_wdg {
23 unsigned char port; /**< wdg port */
24 } vfs_wdg_t;
25
wdg_device_ioctl(file_t * f,int cmd,unsigned long arg)26 int wdg_device_ioctl (file_t *f, int cmd, unsigned long arg) {
27 int ret = -1;
28 vfs_wdg_t *vt = (vfs_wdg_t *)f->node->i_arg;
29 wdg_dev_handle_t wdg = (wdg_dev_handle_t)f->f_arg;
30
31 if (!vt || !wdg) {
32 ddkc_err("%s invalid vt:%p or wdg:%p", vt, wdg);
33 return -EINVAL;
34 }
35
36 ddkc_dbg("cmd:0x%x, arg:0x%lx\r\n", cmd, arg);
37
38 switch (cmd) {
39 case IOC_WDG_RELOAD:
40 case IOC_WDG_FEED:
41 ret = aos_wdg_feed(wdg);
42 if (ret) {
43 ddkc_err("%s feed watchdog failed\r\n", __func__, ret);
44 }
45 break;
46 case IOC_WDG_START:
47 ret = aos_wdg_start(wdg);
48 if (ret) {
49 ddkc_err("%s start watchdog failed\r\n", __func__, ret);
50 }
51 break;
52 case IOC_WDG_STOP:
53 ret = aos_wdg_stop(wdg);
54 if (ret) {
55 ddkc_err("%s start watchdog failed\r\n", __func__, ret);
56 }
57 break;
58 default:
59 ddkc_err("%s invalid cmd:%d\r\n", __func__, cmd);
60 break;
61 }
62
63 return ret;
64 }
65
wdg_device_open(inode_t * node,file_t * f)66 int wdg_device_open (inode_t *node, file_t *f) {
67 int ret = 0;
68 vfs_wdg_t *vt = (vfs_wdg_t *)f->node->i_arg;
69 wdg_dev_handle_t wdg = NULL;
70
71 if (!vt) {
72 ddkc_err("%s open failed, invalid i_arg:%p\r\n", node->i_name, vt);
73 return -EINVAL;
74 }
75
76 wdg = aos_wdg_open(vt->port, 0xFFFFFFFF - 1);
77 if (!wdg) {
78 printf("i2c%d open failed\r\n", vt->port);
79 return -1;
80 }
81
82 f->f_arg = wdg;
83
84 ddkc_dbg("%s opened, port:%d\r\n", node->i_name, vt->port);
85
86 return 0;
87 }
88
wdg_device_close(file_t * f)89 int wdg_device_close (file_t *f) {
90 int ret = 0;
91 vfs_wdg_t *vt = (vfs_wdg_t *)f->node->i_arg;
92 wdg_dev_handle_t wdg = (wdg_dev_handle_t)f->f_arg;
93
94 if (!vt || !wdg) {
95 ddkc_err("%s invalid vt:%p or wdg:%p", vt, wdg);
96 return -EINVAL;
97 }
98
99 ddkc_dbg("close %s, port:%d\r\n", f->node->i_name, vt->port);
100
101 ret = aos_wdg_close(wdg);
102 if (ret) {
103 ddkc_err("aos_wdg_close on wdg%d failed, ret=%d\r\n", vt->port, ret);
104 }
105 f->f_arg = NULL;
106
107 return 0;
108 }
109
110
111 /************************** device ****************************/
112
113
114 subsys_file_ops_t wdg_device_fops = {
115 .open = wdg_device_open,
116 .close = wdg_device_close,
117 .read = NULL,
118 .write = NULL,
119 .ioctl = wdg_device_ioctl,
120 .poll = NULL,
121 };
122
wdg_device_probe(struct u_platform_device * pdev)123 int wdg_device_probe (struct u_platform_device *pdev) {
124 // make sure 0 is returned if probe operation success
125 // or aos_dev_reg procedure will break and no device node will be registered
126 ddkc_dbg("%s\r\n", __func__);
127 return 0;
128 }
129
wdg_device_remove(struct u_platform_device * pdev)130 int wdg_device_remove (struct u_platform_device *pdev) {
131 ddkc_dbg("%s\r\n", __func__);
132 return 0;
133 }
134
wdg_device_shutdown(struct u_platform_device * pdev)135 void wdg_device_shutdown (struct u_platform_device *pdev) {
136 ddkc_dbg("%s\r\n", __func__);
137 return;
138 }
139
wdg_device_suspend(struct u_platform_device * pdev,u_pm_ops_t state)140 int wdg_device_suspend (struct u_platform_device *pdev, u_pm_ops_t state) {
141 ddkc_dbg("%s\r\n", __func__);
142 return 0;
143 }
144
wdg_device_resume(struct u_platform_device * pdev)145 int wdg_device_resume (struct u_platform_device *pdev) {
146 ddkc_dbg("%s\r\n", __func__);
147 return 0;
148 }
149
150 struct subsys_drv wdg_device_drv = {
151 .drv_name = "wdg",
152 .probe = wdg_device_probe,
153 .remove = wdg_device_remove,
154 .shutdown = wdg_device_shutdown,
155 .suspend = wdg_device_suspend,
156 .resume = wdg_device_resume,
157 };
158
159 struct subsys_dev *g_wdg_device_array[PLATFORM_WDG_NUM];
160
161
vfs_wdg_drv_init(void)162 int vfs_wdg_drv_init (void) {
163 int i = 0;
164 int j = 0;
165 int ret = 0;
166 int node_name_len = 0;
167 struct subsys_dev **ppsdev = NULL;
168
169 ddkc_info("wdg vfs driver init starts\r\n");
170
171 node_name_len = strlen(WDG_DEV_NAME_FORMAT) + 1;
172 ddkc_dbg("node_name_len:%d\r\n", node_name_len);
173
174 memset(g_wdg_device_array, 0, sizeof(g_wdg_device_array));
175 ppsdev = g_wdg_device_array;
176
177 for (i = 0; i < PLATFORM_WDG_NUM; i++) {
178 vfs_wdg_t *vt = malloc(sizeof(vfs_wdg_t));
179
180 *ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
181 if (!(*ppsdev) || !vt) {
182 ddkc_info("malloc failed, *ppsdev:%p, vt:%p\r\n", *ppsdev, vt);
183
184 if (*ppsdev) {
185 free(*ppsdev);
186 *ppsdev = NULL;
187 }
188
189 if (vt)
190 free(vt);
191
192 goto err;
193 }
194
195 memset(*ppsdev, 0, sizeof(struct subsys_dev) + node_name_len);
196 memset(vt, 0, sizeof(*vt));
197 // vfs_wdg_t's port should be remained during the whole driver life
198 vt->port = i;
199
200 (*ppsdev)->node_name = (char *)((*ppsdev) + 1);
201 snprintf((*ppsdev)->node_name, node_name_len, WDG_DEV_NAME_FORMAT, i);
202 ddkc_dbg("*ppsdev:%p, node_name:%s, (*ppsdev) + 1:%p, sizeof(struct subsys_dev):%d\r\n",
203 *ppsdev, (*ppsdev)->node_name, (*ppsdev) + 1, sizeof(struct subsys_dev));
204 (*ppsdev)->permission = 0;
205 // please refer to definitions in enum SUBSYS_BUS_TYPE
206 (*ppsdev)->type = BUS_TYPE_PLATFORM;
207 // user_data will be passed to open operation via node->i_arg
208 (*ppsdev)->user_data = vt;
209
210 ret = aos_dev_reg(*ppsdev, &wdg_device_fops, &wdg_device_drv);
211 if (ret) {
212 ddkc_err("aos_dev_reg for wdg%d failed, ret:%d\r\n", i, ret);
213
214 free(vt);
215 free(*ppsdev);
216 *ppsdev = NULL;
217
218 goto err;
219 }
220
221 ppsdev++;
222 }
223
224 ddkc_info("wdg vfs driver init finish, ret:%d\r\n", ret);
225 return 0;
226
227 err:
228 ppsdev = g_wdg_device_array;
229 for (j = 0; j < i; j++) {
230 // shall uninstall wdg devices who are already registered
231 if (*ppsdev) {
232 aos_dev_unreg(*ppsdev);
233
234 ddkc_info("free memory for wdg%d\r\n", j);
235
236 if ((*ppsdev)->user_data)
237 free((*ppsdev)->user_data);
238
239 free(*ppsdev);
240 *ppsdev = NULL;
241 }
242 ppsdev++;
243 }
244 ddkc_err("wdg vfs driver init failed, ret:%d\r\n", ret);
245
246 return ret;
247 }
248
249 VFS_DRIVER_ENTRY(vfs_wdg_drv_init)
250
251 #endif
252