SmartAudio/lichee/linux-4.9/drivers/char/sunxi-sysinfo/sunxi-sysinfo.c

215 lines
5.2 KiB
C
Executable File

/*
* Based on drivers/char/sunxi-sysinfo/sunxi-sysinfo.c
*
* Copyright (C) 2015 Allwinnertech Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/sunxi-sid.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include "sunxi-sysinfo-user.h"
static s8 key_name[SUNXI_KEY_NAME_LEN];
static int soc_info_open(struct inode *inode, struct file *file)
{
return 0;
}
static int soc_info_release(struct inode *inode, struct file *file)
{
return 0;
}
static long soc_info_ioctl(struct file *file, unsigned int ioctl_num,
unsigned long ioctl_param)
{
int ret = 0;
char id[17] = "";
pr_debug("IOCTRL cmd: %#x, param: %#lx\n", ioctl_num, ioctl_param);
switch (ioctl_num) {
case CHECK_SOC_SECURE_ATTR:
ret = sunxi_soc_is_secure();
if (ret)
pr_debug("soc is secure. return value: %d\n", ret);
else
pr_debug("soc is normal. return value: %d\n", ret);
break;
case CHECK_SOC_VERSION:
ret = sunxi_get_soc_ver();
pr_debug("soc version:%x\n", ret);
break;
case CHECK_SOC_BONDING:
sunxi_get_soc_chipid_str(id);
ret = copy_to_user((void __user *)ioctl_param, id, 8);
pr_debug("soc id:%s\n", id);
break;
case CHECK_SOC_CHIPID:
sunxi_get_soc_chipid_str(id);
ret = copy_to_user((void __user *)ioctl_param, id, 16);
pr_debug("soc chipid:%s\n", id);
break;
default:
pr_err("Unsupported cmd:%d\n", ioctl_num);
ret = -EINVAL;
break;
}
return ret;
}
static const struct file_operations soc_info_ops = {
.owner = THIS_MODULE,
.open = soc_info_open,
.release = soc_info_release,
.unlocked_ioctl = soc_info_ioctl,
};
struct miscdevice soc_info_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sunxi_soc_info",
.fops = &soc_info_ops,
};
static ssize_t sys_info_show(struct class *class,
struct class_attribute *attr, char *buf)
{
int i;
int databuf[4] = {0};
int serial[4];
char tmpbuf[129] = {0};
size_t size = 0;
/* platform */
sunxi_get_platform(tmpbuf, 129);
size += sprintf(buf + size, "sunxi_platform : %s\n", tmpbuf);
/* secure */
size += sprintf(buf + size, "sunxi_secure : ");
if (sunxi_soc_is_secure())
size += sprintf(buf + size, "%s\n", "secure");
else
size += sprintf(buf + size, "%s\n", "normal");
/* chipid */
sunxi_get_soc_chipid((u8 *)databuf);
for (i = 0; i < 4; i++)
sprintf(tmpbuf + i*8, "%08x", databuf[i]);
tmpbuf[128] = 0;
size += sprintf(buf + size, "sunxi_chipid : %s\n", tmpbuf);
/* serial */
memset(serial, 0, sizeof(serial));
sunxi_get_serial((u8 *)serial);
sprintf(tmpbuf, "%04x%08x%08x", serial[2], serial[1], serial[0]);
size += sprintf(buf+size, "sunxi_serial : %s\n", tmpbuf);
/* chiptype */
sunxi_get_soc_chipid_str(tmpbuf);
size += sprintf(buf + size, "sunxi_chiptype : %s\n", tmpbuf);
/* socbatch number */
size += sprintf(buf + size, "sunxi_batchno : %#x\n",
sunxi_get_soc_ver()&0x0ffff);
return size;
}
static ssize_t key_info_show(struct class *class,
struct class_attribute *attr, char *buf)
{
s32 i;
u32 *key_data = NULL;
size_t size = 0;
key_data = vmalloc(256);
if (key_data == NULL)
return -ENOMEM;
memset(key_data, 0, 256*4);
sunxi_efuse_readn(key_name, key_data, 256);
for (i = 0; i < 256; i++) {
if ((i > 0) && (key_data[i] == 0))
break;
if ((i > 0) && (i % 8 == 0))
size += sprintf(buf + size, "\n");
size += sprintf(buf + size, "%08x ", key_data[i]);
}
size += sprintf(buf + size, "\n");
vfree(key_data);
return size;
}
static ssize_t key_info_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t count)
{
if (count >= SUNXI_KEY_NAME_LEN)
return -EINVAL;
memset(key_name, 0, SUNXI_KEY_NAME_LEN);
strncpy(key_name, buf, count);
return count;
}
static struct class_attribute info_class_attrs[] = {
__ATTR(sys_info, 0644, sys_info_show, NULL),
__ATTR(key_info, 0644, key_info_show, key_info_store),
__ATTR_NULL,
};
static struct class info_class = {
.name = "sunxi_info",
.owner = THIS_MODULE,
.class_attrs = info_class_attrs,
};
static int __init sunxi_sys_info_init(void)
{
s32 ret = 0;
ret = class_register(&info_class);
if (ret != 0)
return ret;
ret = misc_register(&soc_info_device);
if (ret != 0) {
pr_err("%s: misc_register() failed!(%d)\n", __func__, ret);
class_unregister(&info_class);
return ret;
}
return ret;
}
static void __exit sunxi_sys_info_exit(void)
{
misc_deregister(&soc_info_device);
class_unregister(&info_class);
}
module_init(sunxi_sys_info_init);
module_exit(sunxi_sys_info_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("xiafeng<xiafeng@allwinnertech.com>");
MODULE_DESCRIPTION("sunxi sys info.");