blob: 9282fc20a47f0b2ce392ca19256c83f578f8a35c [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001#include <linux/module.h>
2#include <linux/errno.h>
3#include <linux/proc_fs.h>
4#include <linux/uaccess.h>
5#include <linux/cdev.h>
6#include <linux/cpnv.h>
7#include <linux/vmalloc.h>
8#include <linux/string.h>
9#include <linux/cp_types.h>
10#include <linux/init.h>
11#include <linux/device.h>
12#include <linux/syscalls.h>
13
14#ifndef USE_CPPS_KO
15extern UINT32 zOss_NvItemWrite(UINT32 NvItemID, UINT8 * NvItemData, UINT32 NvItemLen);
16extern UINT32 zOss_NvItemRead(UINT32 NvItemID, UINT8 * NvItemData, UINT32 NvItemLen);
17extern UINT32 zOss_ResetNVFactory(VOID);
18extern UINT32 zOss_NvramFlush(VOID);
19extern UINT32 zOss_NvItemWriteFactory(UINT32 NvItemID, UINT8 * NvItemData, UINT32 NvItemLen);
20#endif
21
22extern int quick_gc_wait_done(const char *mtd_name);
23
24#define CPNV_DEVNAME "cpnv"
25struct class *class_cpnv;
26static struct semaphore cpnv_sem;
27
28struct cpnv_dev_t {
29 struct cdev cdev;
30 dev_t devt;
31} cpnv_dev;
32
33static int cpnv_open(struct inode *inode, struct file *file)
34{
35 file->private_data = (void *)(&cpnv_dev);
36
37 return 0;
38}
39
40static int cpnv_release(struct inode *inode, struct file *file)
41{
42 return 0;
43}
44
45static ssize_t cpnv_read(struct file *file, char *buf, size_t count, loff_t * ppos)
46{
47 char tmp[128] = { 0 };
48 char *itemBuf = tmp;
49 UINT32 NvItemID = 0;
50 ssize_t ret;
51 UINT32 zoss_ret;
52
53 if (!buf) {
54 printk(KERN_WARNING "Error cpnv : %s %d\n", __FILE__, __LINE__);
55 return -ENODATA;
56 }
57
58 if (count > sizeof(tmp)) {
59 itemBuf = vmalloc(count);
60 if (NULL == itemBuf) {
61 printk(KERN_ERR "cpnv_read vmalloc fail \n");
62 return -ENOMEM;
63 }
64 }
65
66 if (copy_from_user(itemBuf, buf, count)) {
67 printk(KERN_WARNING "cpnv_read() copy_from_user error! \n");
68 ret = -EFAULT;
69 goto out;
70 }
71 memcpy(&NvItemID, itemBuf, sizeof(NvItemID));
72
73 down(&cpnv_sem);
74 zoss_ret = CPPS_FUNC(cpps_callbacks, zOss_NvItemRead)(NvItemID, itemBuf, count);
75 up(&cpnv_sem);
76 if (zoss_ret != ZOSS_SUCCESS) {
77 ret = -EFAULT;
78 goto out;
79 }
80
81 if (copy_to_user(buf, itemBuf, count)) {
82 ret = -EFAULT;
83 goto out;
84 }
85 ret = count;
86
87out:
88 if (itemBuf != tmp) {
89 vfree(itemBuf);
90 }
91
92 return ret;
93}
94
95static ssize_t cpnv_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
96{
97 char tmp[128] = { 0 };
98 char *tmpBuf = tmp;
99 ssize_t ret = 0;
100 UINT32 zoss_ret = ZOSS_ERROR;
101 struct cpnv_readwrite_head *phead = (struct cpnv_readwrite_head *)buf;
102
103 if (!phead) {
104 printk(KERN_WARNING "Error: %s %d\n", __FILE__, __LINE__);
105 return -ENODATA;
106 }
107
108 if (count > sizeof(tmp)) {
109 if (!(tmpBuf = vmalloc(count))) {
110 printk(KERN_ERR "cpnv_write() vmalloc fail \n");
111 return -ENOMEM;
112 }
113 }
114
115 if (copy_from_user(tmpBuf, buf, count)) {
116 ret = -EFAULT;
117 goto out;
118 }
119
120 down(&cpnv_sem);
121 switch (phead->direction) {
122 case TO_NVRO:
123 case TO_NVRW:
124 zoss_ret = CPPS_FUNC(cpps_callbacks, zOss_NvItemWrite)(phead->NvItemID, phead->NvItemData, phead->NvItemLen);
125 break;
126 case TO_NVFAC:
127 CPPS_FUNC(cpps_callbacks, zOss_NvItemWriteFactory)(phead->NvItemID, phead->NvItemData, phead->NvItemLen);
128 zoss_ret = 0;
129 break;
130 default:
131 ret = -EINVAL;
132 break;
133 }
134 up(&cpnv_sem);
135
136 if (zoss_ret == ZOSS_SUCCESS)
137 ret = count;
138 else {
139 printk(KERN_ERR "cpnv_write error\n");
140 ret = -EFAULT;
141 }
142
143out:
144 if (tmpBuf != tmp) {
145 vfree(tmpBuf);
146 }
147 return ret;
148}
149
150static long cpnv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
151{
152 long ret = 0;
153 UINT32 zoss_ret = ZOSS_ERROR;
154
155 switch (cmd) {
156 case CPNV_IOIOCTL_FLUSH:
157 down(&cpnv_sem);
158 zoss_ret = CPPS_FUNC(cpps_callbacks, zOss_NvramFlush)();
159 if (ZOSS_SUCCESS != zoss_ret) {
160 ret = -EFAULT;
161 printk(KERN_ERR "cpnv CPNV_IOIOCTL_FLUSH error\n");
162 }
163 up(&cpnv_sem);
164 break;
165
166 case CPNV_IOIOCTL_RESETNVFACTORY:
167 down(&cpnv_sem);
168 zoss_ret = CPPS_FUNC(cpps_callbacks, zOss_ResetNVFactory)();
169 if (ZOSS_SUCCESS != zoss_ret) {
170 ret = -EFAULT;
171 printk(KERN_ERR "cpnv CPNV_IOIOCTL_RESETNVFACTORY error\n");
172 }
173 up(&cpnv_sem);
174 break;
175 default:
176 ret = -EINVAL;
177 break;
178 }
179
180 return ret;
181}
182
183static int cpnv_Remount(char *DevName, char *DirName, char *Type, unsigned int Flag)
184{
185 int ret = 0;
186 mm_segment_t old_fs = get_fs();
187
188 set_fs(KERNEL_DS);
189 ret = sys_mount(DevName, DirName, Type, Flag , 0);
190 if(ret == EBUSY)
191 ret = -1;
192 set_fs(old_fs);
193
194 return ret;
195}
196
197int cpnv_ChangeNvroAttr(int writable)
198{
199 int ret = 0;
200
201 if(writable) {
202 ret = cpnv_Remount("mtd:nvrofs", "/mnt/nvrofs", "jffs2", MS_REMOUNT |MS_VERBOSE);
203 }
204 else {
205 quick_gc_wait_done("nvrofs");
206 ret = cpnv_Remount("mtd:nvrofs", "/mnt/nvrofs", "jffs2", MS_REMOUNT |MS_VERBOSE|MS_RDONLY);
207 }
208
209 return ret;
210}
211EXPORT_SYMBOL(cpnv_ChangeNvroAttr);
212
213struct file_operations cpnv_fops = {
214 .owner = THIS_MODULE,
215 .open = cpnv_open,
216 .release = cpnv_release,
217 .read = cpnv_read,
218 .write = cpnv_write,
219 .unlocked_ioctl = cpnv_ioctl,
220 .mmap = NULL,
221};
222
223static int cpnv_init(void)
224{
225 int error = 0;
226
227 printk(KERN_DEBUG "Load cpnv driver\n");
228 cdev_init(&cpnv_dev.cdev, &cpnv_fops);
229 error = alloc_chrdev_region(&cpnv_dev.devt, 0, 1, CPNV_DEVNAME);
230 if (error) {
231 printk(KERN_ERR "cpnv alloc_chrdev_region error\n");
232 return error;
233 }
234
235 class_cpnv = class_create(THIS_MODULE, "cpnv_class");
236 if (class_cpnv == NULL) {
237 unregister_chrdev(cpnv_dev.devt, CPNV_DEVNAME);
238 return -1;
239 }
240
241 if (device_create(class_cpnv, NULL, cpnv_dev.devt, NULL, "cpnv") == NULL) {
242 class_destroy(class_cpnv);
243 unregister_chrdev(cpnv_dev.devt, CPNV_DEVNAME);
244 return -1;
245 }
246
247 error = cdev_add(&cpnv_dev.cdev, cpnv_dev.devt, 1);
248 if (error) {
249 printk(KERN_ERR "cpnv cdev_add error\n");
250 device_destroy(class_cpnv, cpnv_dev.devt);
251 class_destroy(class_cpnv);
252 unregister_chrdev(cpnv_dev.devt, CPNV_DEVNAME);
253 return error;
254 }
255 sema_init(&cpnv_sem, 1);
256
257 return error;
258}
259
260static void cpnv_exit(void)
261{
262 printk(KERN_DEBUG "cpnv driver exit\n");
263 device_destroy(class_cpnv, cpnv_dev.devt);
264 class_destroy(class_cpnv);
265 unregister_chrdev(cpnv_dev.devt, CPNV_DEVNAME);
266 cdev_del(&cpnv_dev.cdev);
267}
268
269late_initcall(cpnv_init);
270module_exit(cpnv_exit);
271MODULE_LICENSE("GPLv2");