• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Based on drivers/char/sunxi-sysinfo/sunxi-sysinfo.c
3  *
4  * Copyright (C) 2015 Allwinnertech Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <linux/module.h>
20 #include <linux/printk.h>
21 #include <linux/kernel.h>
22 #include <linux/device.h>
23 #include <linux/vmalloc.h>
24 #include <sunxi-sid.h>
25 #include <linux/uaccess.h>
26 #include <linux/fs.h>
27 #include <linux/miscdevice.h>
28 #include <linux/compat.h>
29 
30 #include "sunxi-sysinfo-user.h"
31 
32 static s8 key_name[SUNXI_KEY_NAME_LEN];
33 
soc_info_open(struct inode * inode,struct file * file)34 static int soc_info_open(struct inode *inode, struct file *file)
35 {
36 	return 0;
37 }
38 
soc_info_release(struct inode * inode,struct file * file)39 static int soc_info_release(struct inode *inode, struct file *file)
40 {
41 	return 0;
42 }
43 
soc_info_ioctl(struct file * file,unsigned int ioctl_num,unsigned long ioctl_param)44 static long soc_info_ioctl(struct file *file, unsigned int ioctl_num,
45 		unsigned long ioctl_param)
46 {
47 	int ret = 0;
48 	char id[17] = "";
49 
50 	memset(id, 0, sizeof(id));
51 
52 	pr_debug("IOCTRL cmd: %#x, param: %#lx\n", ioctl_num, ioctl_param);
53 	switch (ioctl_num) {
54 	case CHECK_SOC_SECURE_ATTR:
55 		ret = sunxi_soc_is_secure();
56 		if (ret)
57 			pr_debug("soc is secure. return value: %d\n", ret);
58 		else
59 			pr_debug("soc is normal. return value: %d\n", ret);
60 		break;
61 	case CHECK_SOC_VERSION:
62 		ret = sunxi_get_soc_ver();
63 		pr_debug("soc version:%x\n", ret);
64 		break;
65 	case CHECK_SOC_BONDING:
66 		sunxi_get_soc_chipid_str(id);
67 		ret = copy_to_user((void __user *)ioctl_param, id, 8);
68 		pr_debug("soc id:%s\n", id);
69 		break;
70 	case CHECK_SOC_CHIPID:
71 		sunxi_get_soc_chipid_str(id);
72 		ret = copy_to_user((void __user *)ioctl_param, id, 16);
73 		pr_debug("soc chipid:%s\n", id);
74 		break;
75 	case CHECK_SOC_FT_ZONE:
76 		sunxi_get_soc_ft_zone_str(id);
77 		ret = copy_to_user((void __user *)ioctl_param, id, 8);
78 		pr_debug("ft zone:%s\n", id);
79 		break;
80 	case CHECK_SOC_ROTPK_STATUS:
81 		sunxi_get_soc_rotpk_status_str(id);
82 		ret = copy_to_user((void __user *)ioctl_param, id, 8);
83 		pr_debug("rotpk status:%s\n", id);
84 		break;
85 	default:
86 		pr_err("Unsupported cmd:%d\n", ioctl_num);
87 		ret = -EINVAL;
88 		break;
89 	}
90 	return ret;
91 }
92 
93 #ifdef CONFIG_COMPAT
soc_info_compat_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)94 static long soc_info_compat_ioctl(struct file *filp, unsigned int cmd,
95 		unsigned long arg)
96 {
97 	unsigned long translated_arg = (unsigned long)compat_ptr(arg);
98 
99 	return soc_info_ioctl(filp, cmd, translated_arg);
100 }
101 #endif
102 
103 static const struct file_operations soc_info_ops = {
104 	.owner   = THIS_MODULE,
105 	.open    = soc_info_open,
106 	.release = soc_info_release,
107 #ifdef CONFIG_COMPAT
108 	.compat_ioctl   = soc_info_compat_ioctl,
109 #endif
110 	.unlocked_ioctl = soc_info_ioctl,
111 };
112 
113 struct miscdevice soc_info_device = {
114 	.minor = MISC_DYNAMIC_MINOR,
115 	.name  = "sunxi_soc_info",
116 	.fops  = &soc_info_ops,
117 };
118 
sys_info_show(struct class * class,struct class_attribute * attr,char * buf)119 static ssize_t sys_info_show(struct class *class,
120 			     struct class_attribute *attr, char *buf)
121 {
122 	int i;
123 	int databuf[4] = {0};
124 	char tmpbuf[129] = {0};
125 	size_t size = 0;
126 
127 	/* platform */
128 	sunxi_get_platform(tmpbuf, 129);
129 	size += sprintf(buf + size, "sunxi_platform    : %s\n", tmpbuf);
130 
131 	/* secure */
132 	size += sprintf(buf + size, "sunxi_secure      : ");
133 	if (sunxi_soc_is_secure()) {
134 		size += sprintf(buf + size, "%s\n", "secure");
135 		/* rotpk status */
136 		memset(tmpbuf, 0x0, sizeof(tmpbuf));
137 		sunxi_get_soc_rotpk_status_str(tmpbuf);
138 		size += sprintf(buf + size, "sunxi_rotpk       : %s\n", tmpbuf);
139 	} else
140 		size += sprintf(buf + size, "%s\n", "normal");
141 
142 #ifdef CONFIG_SUNXI_QA_TEST
143 	/* chipid */
144 	sunxi_get_soc_chipid((u8 *)databuf);
145 
146 	for (i = 0; i < 4; i++)
147 		sprintf(tmpbuf + i*8, "%08x", databuf[i]);
148 	tmpbuf[128] = 0;
149 	size += sprintf(buf + size, "sunxi_chipid      : %s\n", tmpbuf);
150 #endif
151 	/* serial */
152 	sunxi_get_serial((u8 *)databuf);
153 	for (i = 0; i < 4; i++)
154 		sprintf(tmpbuf + i*8, "%08x", databuf[i]);
155 	tmpbuf[128] = 0;
156 	size += sprintf(buf + size, "sunxi_serial      : %s\n", tmpbuf);
157 
158 	/* chiptype */
159 	sunxi_get_soc_chipid_str(tmpbuf);
160 	size += sprintf(buf + size, "sunxi_chiptype    : %s\n", tmpbuf);
161 
162 	/* socbatch number */
163 	size += sprintf(buf + size, "sunxi_batchno     : %#x\n",
164 			sunxi_get_soc_ver());
165 
166 	return size;
167 }
168 
key_info_show(struct class * class,struct class_attribute * attr,char * buf)169 static ssize_t key_info_show(struct class *class,
170 			     struct class_attribute *attr, char *buf)
171 {
172 	s32 i;
173 	u32 *key_data = NULL;
174 	size_t size = 0;
175 
176 	key_data = vmalloc(256);
177 	if (key_data == NULL)
178 		return -ENOMEM;
179 
180 	memset(key_data, 0, 256*4);
181 	sunxi_efuse_readn(key_name, key_data, 256);
182 	for (i = 0; i < 256; i++) {
183 		if ((i > 0) && (key_data[i] == 0))
184 			break;
185 		if ((i > 0) && (i % 8 == 0))
186 			size += sprintf(buf + size, "\n");
187 
188 		size += sprintf(buf + size, "%08x ", key_data[i]);
189 	}
190 	size += sprintf(buf + size, "\n");
191 
192 	vfree(key_data);
193 	return size;
194 }
195 
key_info_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)196 static ssize_t key_info_store(struct class *class, struct class_attribute *attr,
197 		const char *buf, size_t count)
198 {
199 	if (count >= SUNXI_KEY_NAME_LEN)
200 		return -EINVAL;
201 
202 	memset(key_name, 0, SUNXI_KEY_NAME_LEN);
203 	strncpy(key_name, buf, count);
204 	return count;
205 }
206 
207 static struct class_attribute info_class_attrs[] = {
208 	__ATTR(sys_info, 0644, sys_info_show, NULL),
209 	__ATTR(key_info, 0644, key_info_show, key_info_store),
210 };
211 
212 static struct class info_class = {
213 	.name           = "sunxi_info",
214 	.owner          = THIS_MODULE,
215 };
216 
sunxi_sys_info_init(void)217 static int __init sunxi_sys_info_init(void)
218 {
219 	s32 ret = 0, i;
220 
221 	ret = class_register(&info_class);
222 	if (ret != 0)
223 		return ret;
224 	/* need some class specific sysfs attributes */
225 	for (i = 0; i < ARRAY_SIZE(info_class_attrs); i++) {
226 		ret = class_create_file(&info_class, &info_class_attrs[i]);
227 		if (ret)
228 			goto out_class_create_file_failed;
229 	}
230 
231 	ret = misc_register(&soc_info_device);
232 	if (ret != 0) {
233 		pr_err("%s: misc_register() failed!(%d)\n", __func__, ret);
234 		class_unregister(&info_class);
235 		return ret;
236 	}
237 	return ret;
238 out_class_create_file_failed:
239 	class_unregister(&info_class);
240 		return ret;
241 }
242 
sunxi_sys_info_exit(void)243 static void __exit sunxi_sys_info_exit(void)
244 {
245 	misc_deregister(&soc_info_device);
246 	class_unregister(&info_class);
247 }
248 
249 module_init(sunxi_sys_info_init);
250 module_exit(sunxi_sys_info_exit);
251 MODULE_LICENSE("GPL v2");
252 MODULE_AUTHOR("xiafeng<xiafeng@allwinnertech.com>");
253 MODULE_DESCRIPTION("sunxi sys info.");
254