#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #define WEIGHT_ADDR 0x4307F000 // 权重加载的内存地址处 // #define M_PAGE_SIZE (4 * 1024) // 内存对齐,应该是4K #define MEM_ACCESS_RELEASE_PHYS_ADDR _IOR('M', 0, unsigned int) #define MEM_ACCESS_GET_WKSRC_SRC _IOW('M', 1, unsigned int) #define MEM_ACCESS_SET_WKSRC_SRC _IOR('M', 2, unsigned int) typedef struct { unsigned char readData[sizeof(int)]; } wakeup_src_t; static int major = 0; static struct class *mem_operation_class; struct mem_area_info { atomic_t init_flag; void __iomem *g_vaddr; int len; }; static struct mem_area_info g_mem = {.init_flag = ATOMIC_INIT(0), .g_vaddr = NULL}; int mem_set_wakeup_source(unsigned char wakeup_src) { if (atomic_read(&g_mem.init_flag) == 1) { writeb(wakeup_src, g_mem.g_vaddr); return 0; } return -1; } EXPORT_SYMBOL(mem_set_wakeup_source); unsigned char mem_get_wakeup_source(void) { if (atomic_read(&g_mem.init_flag) == 1) { return readb(g_mem.g_vaddr); } return 0xFF; } EXPORT_SYMBOL(mem_get_wakeup_source); static int check_page_reserved(unsigned long addr) { struct page *page; page = pfn_to_page(addr >> PAGE_SHIFT); // 将虚拟地址转换为页面索引,然后得到页面结构 if (PageReserved(page)) { printk(KERN_INFO "Page at address 0x%lx is reserved.\n", addr); return 0; } else { printk(KERN_INFO "Page at address 0x%lx is not reserved.\n", addr); return -1; } } static int mem_operation_drv_open (struct inode *node, struct file *file) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static int mem_operation_drv_close (struct inode *node, struct file *file) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static int mem_operation_drv_mmap(struct file *file, struct vm_area_struct *vma) { unsigned long phy = (unsigned long)g_mem.g_vaddr; if(check_page_reserved((unsigned long)g_mem.g_vaddr) < 0) return -EINVAL; /* 设置属性: cache, buffer */ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* map */ if (remap_pfn_range(vma, vma->vm_start, phy >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { printk("mmap remap_pfn_range failed\n"); return -ENOBUFS; } return 0; } static long mem_operation_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { wakeup_src_t wakeupsrc = {.readData[0] = 0}; switch (cmd) { case MEM_ACCESS_RELEASE_PHYS_ADDR: { unsigned int mem_size; if (get_user(mem_size, (unsigned long __user *)arg)) return -EFAULT; if(check_page_reserved((unsigned long)g_mem.g_vaddr) < 0) return -EINVAL; memblock_free((unsigned int)g_mem.g_vaddr, mem_size); free_reserved_area(__va(g_mem.g_vaddr), __va(g_mem.g_vaddr + mem_size), -1, "wakeup_source"); // printk("release phy addr: 0x%x, size: %d\n", (int)g_mem.g_vaddr, mem_size); break; } case MEM_ACCESS_GET_WKSRC_SRC: { // void __iomem *vaddr = NULL; // vaddr = ioremap(WEIGHT_ADDR, sizeof(wakeupsrc)); // vaddr = ioremap_nocache(PHYS_ADDR, SIZE); wakeupsrc.readData[0] = readb(g_mem.g_vaddr); // memcpy_fromio(buffer, vaddr, SIZE); // copy_to_user(arg, vaddr, SIZE) ? // printk(KERN_EMERG "give wake up source:%d\n", wakeupsrc.readData[0]); if (copy_to_user((void *)arg, &wakeupsrc, sizeof(wakeupsrc))) { // iounmap(vaddr); return -EINVAL; } // iounmap(vaddr); break; } case MEM_ACCESS_SET_WKSRC_SRC: { // void __iomem *vaddr = NULL; if (copy_from_user(&wakeupsrc, (void __user *)arg, sizeof(wakeupsrc))) { return -EFAULT; } writeb(wakeupsrc.readData[0], g_mem.g_vaddr); // printk(KERN_EMERG "set wake up source:%d\n", wakeupsrc.readData[0]); break; } default: return -EINVAL; break; } return 0; } static struct file_operations mem_operation_drv = { .owner = THIS_MODULE, .open = mem_operation_drv_open, .release = mem_operation_drv_close, .mmap = mem_operation_drv_mmap, .unlocked_ioctl = mem_operation_drv_ioctl, }; static int __init mem_operation_init(void) { int err; struct device_node *np; struct resource res; np = of_find_compatible_node(NULL, NULL, "wakeup-src"); if (!np) { pr_err("mem Reserved memory node not found\n"); return -ENODEV; } if (of_address_to_resource(np, 0, &res)) { pr_err("mem Failed to parse reg\n"); of_node_put(np); return -EFAULT; } g_mem.len = resource_size(&res); g_mem.g_vaddr = memremap(res.start, g_mem.len, MEMREMAP_WB); if (!g_mem.g_vaddr) { return -EINVAL; } #ifdef CONFIG_XR806_WLAN writeb(0, g_mem.g_vaddr); // 如果xr806而非boot0获取唤醒源,需要先设默认值 #endif atomic_set(&g_mem.init_flag, 1); // printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); major = register_chrdev(0, "mem_operation", &mem_operation_drv); /* /dev/mem_operation */ mem_operation_class = class_create(THIS_MODULE, "mem_operation_class"); err = PTR_ERR(mem_operation_class); if (IS_ERR(mem_operation_class)) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "mem_operation"); memunmap(g_mem.g_vaddr); return -1; } device_create(mem_operation_class, NULL, MKDEV(major, 0), NULL, "mem_operation"); /* 设备节点: /dev/mem_operation */ return 0; } static void __exit mem_operation_exit(void) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); device_destroy(mem_operation_class, MKDEV(major, 0)); class_destroy(mem_operation_class); unregister_chrdev(major, "mem_operation"); if (atomic_read(&g_mem.init_flag) == 1) { memunmap(g_mem.g_vaddr); } } // 注意放在disp之前 fs_initcall_sync(mem_operation_init); module_exit(mem_operation_exit); MODULE_LICENSE("GPL");