/* * 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 . */ #include #include #include #include #include #include #include #include #include #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[9] = ""; 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; 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}; 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_serial((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); /* 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"); MODULE_DESCRIPTION("sunxi sys info.");