18cfb0cdfSLv Zheng /* 28cfb0cdfSLv Zheng * ACPI AML interfacing support 38cfb0cdfSLv Zheng * 48cfb0cdfSLv Zheng * Copyright (C) 2015, Intel Corporation 58cfb0cdfSLv Zheng * Authors: Lv Zheng <lv.zheng@intel.com> 68cfb0cdfSLv Zheng * 78cfb0cdfSLv Zheng * This program is free software; you can redistribute it and/or modify 88cfb0cdfSLv Zheng * it under the terms of the GNU General Public License version 2 as 98cfb0cdfSLv Zheng * published by the Free Software Foundation. 108cfb0cdfSLv Zheng */ 118cfb0cdfSLv Zheng 128cfb0cdfSLv Zheng /* #define DEBUG */ 138cfb0cdfSLv Zheng #define pr_fmt(fmt) "ACPI : AML: " fmt 148cfb0cdfSLv Zheng 158cfb0cdfSLv Zheng #include <linux/kernel.h> 168cfb0cdfSLv Zheng #include <linux/module.h> 178cfb0cdfSLv Zheng #include <linux/wait.h> 188cfb0cdfSLv Zheng #include <linux/poll.h> 198cfb0cdfSLv Zheng #include <linux/sched.h> 208cfb0cdfSLv Zheng #include <linux/kthread.h> 218cfb0cdfSLv Zheng #include <linux/proc_fs.h> 228cfb0cdfSLv Zheng #include <linux/debugfs.h> 238cfb0cdfSLv Zheng #include <linux/circ_buf.h> 24836d0830SLv Zheng #include <linux/acpi.h> 258cfb0cdfSLv Zheng #include "internal.h" 268cfb0cdfSLv Zheng 278cfb0cdfSLv Zheng #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) 288cfb0cdfSLv Zheng #define ACPI_AML_BUF_SIZE PAGE_SIZE 298cfb0cdfSLv Zheng 308cfb0cdfSLv Zheng #define circ_count(circ) \ 318cfb0cdfSLv Zheng (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) 328cfb0cdfSLv Zheng #define circ_count_to_end(circ) \ 338cfb0cdfSLv Zheng (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) 348cfb0cdfSLv Zheng #define circ_space(circ) \ 358cfb0cdfSLv Zheng (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) 368cfb0cdfSLv Zheng #define circ_space_to_end(circ) \ 378cfb0cdfSLv Zheng (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) 388cfb0cdfSLv Zheng 398cfb0cdfSLv Zheng #define ACPI_AML_OPENED 0x0001 408cfb0cdfSLv Zheng #define ACPI_AML_CLOSED 0x0002 418cfb0cdfSLv Zheng #define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */ 428cfb0cdfSLv Zheng #define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */ 438cfb0cdfSLv Zheng #define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */ 448cfb0cdfSLv Zheng #define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */ 458cfb0cdfSLv Zheng #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER) 468cfb0cdfSLv Zheng #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN) 478cfb0cdfSLv Zheng #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN) 488cfb0cdfSLv Zheng #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED) 498cfb0cdfSLv Zheng 508cfb0cdfSLv Zheng struct acpi_aml_io { 518cfb0cdfSLv Zheng wait_queue_head_t wait; 528cfb0cdfSLv Zheng unsigned long flags; 538cfb0cdfSLv Zheng unsigned long users; 548cfb0cdfSLv Zheng struct mutex lock; 558cfb0cdfSLv Zheng struct task_struct *thread; 568cfb0cdfSLv Zheng char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); 578cfb0cdfSLv Zheng struct circ_buf out_crc; 588cfb0cdfSLv Zheng char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); 598cfb0cdfSLv Zheng struct circ_buf in_crc; 608cfb0cdfSLv Zheng acpi_osd_exec_callback function; 618cfb0cdfSLv Zheng void *context; 628cfb0cdfSLv Zheng unsigned long usages; 638cfb0cdfSLv Zheng }; 648cfb0cdfSLv Zheng 658cfb0cdfSLv Zheng static struct acpi_aml_io acpi_aml_io; 668cfb0cdfSLv Zheng static bool acpi_aml_initialized; 678cfb0cdfSLv Zheng static struct file *acpi_aml_active_reader; 688cfb0cdfSLv Zheng static struct dentry *acpi_aml_dentry; 698cfb0cdfSLv Zheng 708cfb0cdfSLv Zheng static inline bool __acpi_aml_running(void) 718cfb0cdfSLv Zheng { 728cfb0cdfSLv Zheng return acpi_aml_io.thread ? true : false; 738cfb0cdfSLv Zheng } 748cfb0cdfSLv Zheng 758cfb0cdfSLv Zheng static inline bool __acpi_aml_access_ok(unsigned long flag) 768cfb0cdfSLv Zheng { 778cfb0cdfSLv Zheng /* 788cfb0cdfSLv Zheng * The debugger interface is in opened state (OPENED && !CLOSED), 798cfb0cdfSLv Zheng * then it is allowed to access the debugger buffers from either 808cfb0cdfSLv Zheng * user space or the kernel space. 818cfb0cdfSLv Zheng * In addition, for the kernel space, only the debugger thread 828cfb0cdfSLv Zheng * (thread ID matched) is allowed to access. 838cfb0cdfSLv Zheng */ 848cfb0cdfSLv Zheng if (!(acpi_aml_io.flags & ACPI_AML_OPENED) || 858cfb0cdfSLv Zheng (acpi_aml_io.flags & ACPI_AML_CLOSED) || 868cfb0cdfSLv Zheng !__acpi_aml_running()) 878cfb0cdfSLv Zheng return false; 888cfb0cdfSLv Zheng if ((flag & ACPI_AML_KERN) && 898cfb0cdfSLv Zheng current != acpi_aml_io.thread) 908cfb0cdfSLv Zheng return false; 918cfb0cdfSLv Zheng return true; 928cfb0cdfSLv Zheng } 938cfb0cdfSLv Zheng 948cfb0cdfSLv Zheng static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag) 958cfb0cdfSLv Zheng { 968cfb0cdfSLv Zheng /* 978cfb0cdfSLv Zheng * Another read is not in progress and there is data in buffer 988cfb0cdfSLv Zheng * available for read. 998cfb0cdfSLv Zheng */ 1008cfb0cdfSLv Zheng if (!(acpi_aml_io.flags & flag) && circ_count(circ)) 1018cfb0cdfSLv Zheng return true; 1028cfb0cdfSLv Zheng return false; 1038cfb0cdfSLv Zheng } 1048cfb0cdfSLv Zheng 1058cfb0cdfSLv Zheng static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag) 1068cfb0cdfSLv Zheng { 1078cfb0cdfSLv Zheng /* 1088cfb0cdfSLv Zheng * Another write is not in progress and there is buffer space 1098cfb0cdfSLv Zheng * available for write. 1108cfb0cdfSLv Zheng */ 1118cfb0cdfSLv Zheng if (!(acpi_aml_io.flags & flag) && circ_space(circ)) 1128cfb0cdfSLv Zheng return true; 1138cfb0cdfSLv Zheng return false; 1148cfb0cdfSLv Zheng } 1158cfb0cdfSLv Zheng 1168cfb0cdfSLv Zheng static inline bool __acpi_aml_busy(void) 1178cfb0cdfSLv Zheng { 1188cfb0cdfSLv Zheng if (acpi_aml_io.flags & ACPI_AML_BUSY) 1198cfb0cdfSLv Zheng return true; 1208cfb0cdfSLv Zheng return false; 1218cfb0cdfSLv Zheng } 1228cfb0cdfSLv Zheng 1238cfb0cdfSLv Zheng static inline bool __acpi_aml_opened(void) 1248cfb0cdfSLv Zheng { 1258cfb0cdfSLv Zheng if (acpi_aml_io.flags & ACPI_AML_OPEN) 1268cfb0cdfSLv Zheng return true; 1278cfb0cdfSLv Zheng return false; 1288cfb0cdfSLv Zheng } 1298cfb0cdfSLv Zheng 1308cfb0cdfSLv Zheng static inline bool __acpi_aml_used(void) 1318cfb0cdfSLv Zheng { 1328cfb0cdfSLv Zheng return acpi_aml_io.usages ? true : false; 1338cfb0cdfSLv Zheng } 1348cfb0cdfSLv Zheng 1358cfb0cdfSLv Zheng static inline bool acpi_aml_running(void) 1368cfb0cdfSLv Zheng { 1378cfb0cdfSLv Zheng bool ret; 1388cfb0cdfSLv Zheng 1398cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1408cfb0cdfSLv Zheng ret = __acpi_aml_running(); 1418cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1428cfb0cdfSLv Zheng return ret; 1438cfb0cdfSLv Zheng } 1448cfb0cdfSLv Zheng 1458cfb0cdfSLv Zheng static bool acpi_aml_busy(void) 1468cfb0cdfSLv Zheng { 1478cfb0cdfSLv Zheng bool ret; 1488cfb0cdfSLv Zheng 1498cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1508cfb0cdfSLv Zheng ret = __acpi_aml_busy(); 1518cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1528cfb0cdfSLv Zheng return ret; 1538cfb0cdfSLv Zheng } 1548cfb0cdfSLv Zheng 1558cfb0cdfSLv Zheng static bool acpi_aml_used(void) 1568cfb0cdfSLv Zheng { 1578cfb0cdfSLv Zheng bool ret; 1588cfb0cdfSLv Zheng 1598cfb0cdfSLv Zheng /* 1608cfb0cdfSLv Zheng * The usage count is prepared to avoid race conditions between the 1618cfb0cdfSLv Zheng * starts and the stops of the debugger thread. 1628cfb0cdfSLv Zheng */ 1638cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1648cfb0cdfSLv Zheng ret = __acpi_aml_used(); 1658cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1668cfb0cdfSLv Zheng return ret; 1678cfb0cdfSLv Zheng } 1688cfb0cdfSLv Zheng 1698cfb0cdfSLv Zheng static bool acpi_aml_kern_readable(void) 1708cfb0cdfSLv Zheng { 1718cfb0cdfSLv Zheng bool ret; 1728cfb0cdfSLv Zheng 1738cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1748cfb0cdfSLv Zheng ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) || 1758cfb0cdfSLv Zheng __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN); 1768cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1778cfb0cdfSLv Zheng return ret; 1788cfb0cdfSLv Zheng } 1798cfb0cdfSLv Zheng 1808cfb0cdfSLv Zheng static bool acpi_aml_kern_writable(void) 1818cfb0cdfSLv Zheng { 1828cfb0cdfSLv Zheng bool ret; 1838cfb0cdfSLv Zheng 1848cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1858cfb0cdfSLv Zheng ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) || 1868cfb0cdfSLv Zheng __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN); 1878cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1888cfb0cdfSLv Zheng return ret; 1898cfb0cdfSLv Zheng } 1908cfb0cdfSLv Zheng 1918cfb0cdfSLv Zheng static bool acpi_aml_user_readable(void) 1928cfb0cdfSLv Zheng { 1938cfb0cdfSLv Zheng bool ret; 1948cfb0cdfSLv Zheng 1958cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 1968cfb0cdfSLv Zheng ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) || 1978cfb0cdfSLv Zheng __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER); 1988cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 1998cfb0cdfSLv Zheng return ret; 2008cfb0cdfSLv Zheng } 2018cfb0cdfSLv Zheng 2028cfb0cdfSLv Zheng static bool acpi_aml_user_writable(void) 2038cfb0cdfSLv Zheng { 2048cfb0cdfSLv Zheng bool ret; 2058cfb0cdfSLv Zheng 2068cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 2078cfb0cdfSLv Zheng ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) || 2088cfb0cdfSLv Zheng __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER); 2098cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 2108cfb0cdfSLv Zheng return ret; 2118cfb0cdfSLv Zheng } 2128cfb0cdfSLv Zheng 2138cfb0cdfSLv Zheng static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag) 2148cfb0cdfSLv Zheng { 2158cfb0cdfSLv Zheng int ret = 0; 2168cfb0cdfSLv Zheng 2178cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 2188cfb0cdfSLv Zheng if (!__acpi_aml_access_ok(flag)) { 2198cfb0cdfSLv Zheng ret = -EFAULT; 2208cfb0cdfSLv Zheng goto out; 2218cfb0cdfSLv Zheng } 2228cfb0cdfSLv Zheng if (!__acpi_aml_writable(circ, flag)) { 2238cfb0cdfSLv Zheng ret = -EAGAIN; 2248cfb0cdfSLv Zheng goto out; 2258cfb0cdfSLv Zheng } 2268cfb0cdfSLv Zheng acpi_aml_io.flags |= flag; 2278cfb0cdfSLv Zheng out: 2288cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 2298cfb0cdfSLv Zheng return ret; 2308cfb0cdfSLv Zheng } 2318cfb0cdfSLv Zheng 2328cfb0cdfSLv Zheng static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag) 2338cfb0cdfSLv Zheng { 2348cfb0cdfSLv Zheng int ret = 0; 2358cfb0cdfSLv Zheng 2368cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 2378cfb0cdfSLv Zheng if (!__acpi_aml_access_ok(flag)) { 2388cfb0cdfSLv Zheng ret = -EFAULT; 2398cfb0cdfSLv Zheng goto out; 2408cfb0cdfSLv Zheng } 2418cfb0cdfSLv Zheng if (!__acpi_aml_readable(circ, flag)) { 2428cfb0cdfSLv Zheng ret = -EAGAIN; 2438cfb0cdfSLv Zheng goto out; 2448cfb0cdfSLv Zheng } 2458cfb0cdfSLv Zheng acpi_aml_io.flags |= flag; 2468cfb0cdfSLv Zheng out: 2478cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 2488cfb0cdfSLv Zheng return ret; 2498cfb0cdfSLv Zheng } 2508cfb0cdfSLv Zheng 2518cfb0cdfSLv Zheng static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup) 2528cfb0cdfSLv Zheng { 2538cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 2548cfb0cdfSLv Zheng acpi_aml_io.flags &= ~flag; 2558cfb0cdfSLv Zheng if (wakeup) 2568cfb0cdfSLv Zheng wake_up_interruptible(&acpi_aml_io.wait); 2578cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 2588cfb0cdfSLv Zheng } 2598cfb0cdfSLv Zheng 2608cfb0cdfSLv Zheng static int acpi_aml_write_kern(const char *buf, int len) 2618cfb0cdfSLv Zheng { 2628cfb0cdfSLv Zheng int ret; 2638cfb0cdfSLv Zheng struct circ_buf *crc = &acpi_aml_io.out_crc; 2648cfb0cdfSLv Zheng int n; 2658cfb0cdfSLv Zheng char *p; 2668cfb0cdfSLv Zheng 2678cfb0cdfSLv Zheng ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN); 2688cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 2698cfb0cdfSLv Zheng return ret; 2708cfb0cdfSLv Zheng /* sync tail before inserting logs */ 2718cfb0cdfSLv Zheng smp_mb(); 2728cfb0cdfSLv Zheng p = &crc->buf[crc->head]; 2738cfb0cdfSLv Zheng n = min(len, circ_space_to_end(crc)); 2748cfb0cdfSLv Zheng memcpy(p, buf, n); 2758cfb0cdfSLv Zheng /* sync head after inserting logs */ 2768cfb0cdfSLv Zheng smp_wmb(); 2778cfb0cdfSLv Zheng crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); 2788cfb0cdfSLv Zheng acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true); 2798cfb0cdfSLv Zheng return n; 2808cfb0cdfSLv Zheng } 2818cfb0cdfSLv Zheng 2828cfb0cdfSLv Zheng static int acpi_aml_readb_kern(void) 2838cfb0cdfSLv Zheng { 2848cfb0cdfSLv Zheng int ret; 2858cfb0cdfSLv Zheng struct circ_buf *crc = &acpi_aml_io.in_crc; 2868cfb0cdfSLv Zheng char *p; 2878cfb0cdfSLv Zheng 2888cfb0cdfSLv Zheng ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN); 2898cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 2908cfb0cdfSLv Zheng return ret; 2918cfb0cdfSLv Zheng /* sync head before removing cmds */ 2928cfb0cdfSLv Zheng smp_rmb(); 2938cfb0cdfSLv Zheng p = &crc->buf[crc->tail]; 2948cfb0cdfSLv Zheng ret = (int)*p; 2958cfb0cdfSLv Zheng /* sync tail before inserting cmds */ 2968cfb0cdfSLv Zheng smp_mb(); 2978cfb0cdfSLv Zheng crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); 2988cfb0cdfSLv Zheng acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true); 2998cfb0cdfSLv Zheng return ret; 3008cfb0cdfSLv Zheng } 3018cfb0cdfSLv Zheng 3028cfb0cdfSLv Zheng /* 3038cfb0cdfSLv Zheng * acpi_aml_write_log() - Capture debugger output 3048cfb0cdfSLv Zheng * @msg: the debugger output 3058cfb0cdfSLv Zheng * 3068cfb0cdfSLv Zheng * This function should be used to implement acpi_os_printf() to filter out 3078cfb0cdfSLv Zheng * the debugger output and store the output into the debugger interface 3088cfb0cdfSLv Zheng * buffer. Return the size of stored logs or errno. 3098cfb0cdfSLv Zheng */ 310836d0830SLv Zheng static ssize_t acpi_aml_write_log(const char *msg) 3118cfb0cdfSLv Zheng { 3128cfb0cdfSLv Zheng int ret = 0; 3138cfb0cdfSLv Zheng int count = 0, size = 0; 3148cfb0cdfSLv Zheng 3158cfb0cdfSLv Zheng if (!acpi_aml_initialized) 3168cfb0cdfSLv Zheng return -ENODEV; 3178cfb0cdfSLv Zheng if (msg) 3188cfb0cdfSLv Zheng count = strlen(msg); 3198cfb0cdfSLv Zheng while (count > 0) { 3208cfb0cdfSLv Zheng again: 3218cfb0cdfSLv Zheng ret = acpi_aml_write_kern(msg + size, count); 3228cfb0cdfSLv Zheng if (ret == -EAGAIN) { 3238cfb0cdfSLv Zheng ret = wait_event_interruptible(acpi_aml_io.wait, 3248cfb0cdfSLv Zheng acpi_aml_kern_writable()); 3258cfb0cdfSLv Zheng /* 3268cfb0cdfSLv Zheng * We need to retry when the condition 3278cfb0cdfSLv Zheng * becomes true. 3288cfb0cdfSLv Zheng */ 3298cfb0cdfSLv Zheng if (ret == 0) 3308cfb0cdfSLv Zheng goto again; 3318cfb0cdfSLv Zheng break; 3328cfb0cdfSLv Zheng } 3338cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 3348cfb0cdfSLv Zheng break; 3358cfb0cdfSLv Zheng size += ret; 3368cfb0cdfSLv Zheng count -= ret; 3378cfb0cdfSLv Zheng } 3388cfb0cdfSLv Zheng return size > 0 ? size : ret; 3398cfb0cdfSLv Zheng } 3408cfb0cdfSLv Zheng 3418cfb0cdfSLv Zheng /* 3428cfb0cdfSLv Zheng * acpi_aml_read_cmd() - Capture debugger input 3438cfb0cdfSLv Zheng * @msg: the debugger input 3448cfb0cdfSLv Zheng * @size: the size of the debugger input 3458cfb0cdfSLv Zheng * 3468cfb0cdfSLv Zheng * This function should be used to implement acpi_os_get_line() to capture 3478cfb0cdfSLv Zheng * the debugger input commands and store the input commands into the 3488cfb0cdfSLv Zheng * debugger interface buffer. Return the size of stored commands or errno. 3498cfb0cdfSLv Zheng */ 350836d0830SLv Zheng static ssize_t acpi_aml_read_cmd(char *msg, size_t count) 3518cfb0cdfSLv Zheng { 3528cfb0cdfSLv Zheng int ret = 0; 3538cfb0cdfSLv Zheng int size = 0; 3548cfb0cdfSLv Zheng 3558cfb0cdfSLv Zheng /* 3568cfb0cdfSLv Zheng * This is ensured by the running fact of the debugger thread 3578cfb0cdfSLv Zheng * unless a bug is introduced. 3588cfb0cdfSLv Zheng */ 3598cfb0cdfSLv Zheng BUG_ON(!acpi_aml_initialized); 3608cfb0cdfSLv Zheng while (count > 0) { 3618cfb0cdfSLv Zheng again: 3628cfb0cdfSLv Zheng /* 3638cfb0cdfSLv Zheng * Check each input byte to find the end of the command. 3648cfb0cdfSLv Zheng */ 3658cfb0cdfSLv Zheng ret = acpi_aml_readb_kern(); 3668cfb0cdfSLv Zheng if (ret == -EAGAIN) { 3678cfb0cdfSLv Zheng ret = wait_event_interruptible(acpi_aml_io.wait, 3688cfb0cdfSLv Zheng acpi_aml_kern_readable()); 3698cfb0cdfSLv Zheng /* 3708cfb0cdfSLv Zheng * We need to retry when the condition becomes 3718cfb0cdfSLv Zheng * true. 3728cfb0cdfSLv Zheng */ 3738cfb0cdfSLv Zheng if (ret == 0) 3748cfb0cdfSLv Zheng goto again; 3758cfb0cdfSLv Zheng } 3768cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 3778cfb0cdfSLv Zheng break; 3788cfb0cdfSLv Zheng *(msg + size) = (char)ret; 3798cfb0cdfSLv Zheng size++; 3808cfb0cdfSLv Zheng count--; 3818cfb0cdfSLv Zheng if (ret == '\n') { 3828cfb0cdfSLv Zheng /* 3838cfb0cdfSLv Zheng * acpi_os_get_line() requires a zero terminated command 3848cfb0cdfSLv Zheng * string. 3858cfb0cdfSLv Zheng */ 3868cfb0cdfSLv Zheng *(msg + size - 1) = '\0'; 3878cfb0cdfSLv Zheng break; 3888cfb0cdfSLv Zheng } 3898cfb0cdfSLv Zheng } 3908cfb0cdfSLv Zheng return size > 0 ? size : ret; 3918cfb0cdfSLv Zheng } 3928cfb0cdfSLv Zheng 3938cfb0cdfSLv Zheng static int acpi_aml_thread(void *unsed) 3948cfb0cdfSLv Zheng { 3958cfb0cdfSLv Zheng acpi_osd_exec_callback function = NULL; 3968cfb0cdfSLv Zheng void *context; 3978cfb0cdfSLv Zheng 3988cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 3998cfb0cdfSLv Zheng if (acpi_aml_io.function) { 4008cfb0cdfSLv Zheng acpi_aml_io.usages++; 4018cfb0cdfSLv Zheng function = acpi_aml_io.function; 4028cfb0cdfSLv Zheng context = acpi_aml_io.context; 4038cfb0cdfSLv Zheng } 4048cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 4058cfb0cdfSLv Zheng 4068cfb0cdfSLv Zheng if (function) 4078cfb0cdfSLv Zheng function(context); 4088cfb0cdfSLv Zheng 4098cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 4108cfb0cdfSLv Zheng acpi_aml_io.usages--; 4118cfb0cdfSLv Zheng if (!__acpi_aml_used()) { 4128cfb0cdfSLv Zheng acpi_aml_io.thread = NULL; 4138cfb0cdfSLv Zheng wake_up(&acpi_aml_io.wait); 4148cfb0cdfSLv Zheng } 4158cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 4168cfb0cdfSLv Zheng 4178cfb0cdfSLv Zheng return 0; 4188cfb0cdfSLv Zheng } 4198cfb0cdfSLv Zheng 4208cfb0cdfSLv Zheng /* 4218cfb0cdfSLv Zheng * acpi_aml_create_thread() - Create AML debugger thread 4228cfb0cdfSLv Zheng * @function: the debugger thread callback 4238cfb0cdfSLv Zheng * @context: the context to be passed to the debugger thread 4248cfb0cdfSLv Zheng * 4258cfb0cdfSLv Zheng * This function should be used to implement acpi_os_execute() which is 4268cfb0cdfSLv Zheng * used by the ACPICA debugger to create the debugger thread. 4278cfb0cdfSLv Zheng */ 428836d0830SLv Zheng static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) 4298cfb0cdfSLv Zheng { 4308cfb0cdfSLv Zheng struct task_struct *t; 4318cfb0cdfSLv Zheng 4328cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 4338cfb0cdfSLv Zheng acpi_aml_io.function = function; 4348cfb0cdfSLv Zheng acpi_aml_io.context = context; 4358cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 4368cfb0cdfSLv Zheng 4378cfb0cdfSLv Zheng t = kthread_create(acpi_aml_thread, NULL, "aml"); 4388cfb0cdfSLv Zheng if (IS_ERR(t)) { 4398cfb0cdfSLv Zheng pr_err("Failed to create AML debugger thread.\n"); 4408cfb0cdfSLv Zheng return PTR_ERR(t); 4418cfb0cdfSLv Zheng } 4428cfb0cdfSLv Zheng 4438cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 4448cfb0cdfSLv Zheng acpi_aml_io.thread = t; 4458cfb0cdfSLv Zheng acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t); 4468cfb0cdfSLv Zheng wake_up_process(t); 4478cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 4488cfb0cdfSLv Zheng return 0; 4498cfb0cdfSLv Zheng } 4508cfb0cdfSLv Zheng 451836d0830SLv Zheng static int acpi_aml_wait_command_ready(bool single_step, 452836d0830SLv Zheng char *buffer, size_t length) 4538cfb0cdfSLv Zheng { 4548cfb0cdfSLv Zheng acpi_status status; 4558cfb0cdfSLv Zheng 456836d0830SLv Zheng if (single_step) 4578cfb0cdfSLv Zheng acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); 458836d0830SLv Zheng else 459836d0830SLv Zheng acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); 4608cfb0cdfSLv Zheng 461836d0830SLv Zheng status = acpi_os_get_line(buffer, length, NULL); 4628cfb0cdfSLv Zheng if (ACPI_FAILURE(status)) 4638cfb0cdfSLv Zheng return -EINVAL; 4648cfb0cdfSLv Zheng return 0; 4658cfb0cdfSLv Zheng } 4668cfb0cdfSLv Zheng 467836d0830SLv Zheng static int acpi_aml_notify_command_complete(void) 4688cfb0cdfSLv Zheng { 4698cfb0cdfSLv Zheng return 0; 4708cfb0cdfSLv Zheng } 4718cfb0cdfSLv Zheng 4728cfb0cdfSLv Zheng static int acpi_aml_open(struct inode *inode, struct file *file) 4738cfb0cdfSLv Zheng { 4748cfb0cdfSLv Zheng int ret = 0; 4758cfb0cdfSLv Zheng acpi_status status; 4768cfb0cdfSLv Zheng 4778cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 4788cfb0cdfSLv Zheng /* 4798cfb0cdfSLv Zheng * The debugger interface is being closed, no new user is allowed 4808cfb0cdfSLv Zheng * during this period. 4818cfb0cdfSLv Zheng */ 4828cfb0cdfSLv Zheng if (acpi_aml_io.flags & ACPI_AML_CLOSED) { 4838cfb0cdfSLv Zheng ret = -EBUSY; 4848cfb0cdfSLv Zheng goto err_lock; 4858cfb0cdfSLv Zheng } 4868cfb0cdfSLv Zheng if ((file->f_flags & O_ACCMODE) != O_WRONLY) { 4878cfb0cdfSLv Zheng /* 4888cfb0cdfSLv Zheng * Only one reader is allowed to initiate the debugger 4898cfb0cdfSLv Zheng * thread. 4908cfb0cdfSLv Zheng */ 4918cfb0cdfSLv Zheng if (acpi_aml_active_reader) { 4928cfb0cdfSLv Zheng ret = -EBUSY; 4938cfb0cdfSLv Zheng goto err_lock; 4948cfb0cdfSLv Zheng } else { 4958cfb0cdfSLv Zheng pr_debug("Opening debugger reader.\n"); 4968cfb0cdfSLv Zheng acpi_aml_active_reader = file; 4978cfb0cdfSLv Zheng } 4988cfb0cdfSLv Zheng } else { 4998cfb0cdfSLv Zheng /* 5008cfb0cdfSLv Zheng * No writer is allowed unless the debugger thread is 5018cfb0cdfSLv Zheng * ready. 5028cfb0cdfSLv Zheng */ 5038cfb0cdfSLv Zheng if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) { 5048cfb0cdfSLv Zheng ret = -ENODEV; 5058cfb0cdfSLv Zheng goto err_lock; 5068cfb0cdfSLv Zheng } 5078cfb0cdfSLv Zheng } 5088cfb0cdfSLv Zheng if (acpi_aml_active_reader == file) { 5098cfb0cdfSLv Zheng pr_debug("Opening debugger interface.\n"); 5108cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 5118cfb0cdfSLv Zheng 5128cfb0cdfSLv Zheng pr_debug("Initializing debugger thread.\n"); 5138cfb0cdfSLv Zheng status = acpi_initialize_debugger(); 5148cfb0cdfSLv Zheng if (ACPI_FAILURE(status)) { 5158cfb0cdfSLv Zheng pr_err("Failed to initialize debugger.\n"); 5168cfb0cdfSLv Zheng ret = -EINVAL; 5178cfb0cdfSLv Zheng goto err_lock; 5188cfb0cdfSLv Zheng } 5198cfb0cdfSLv Zheng pr_debug("Debugger thread initialized.\n"); 5208cfb0cdfSLv Zheng 5218cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 522*73af2d59SLv Zheng acpi_aml_io.flags |= ACPI_AML_OPENED; 5238cfb0cdfSLv Zheng acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; 5248cfb0cdfSLv Zheng acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; 5258cfb0cdfSLv Zheng pr_debug("Debugger interface opened.\n"); 5268cfb0cdfSLv Zheng } 5278cfb0cdfSLv Zheng acpi_aml_io.users++; 5288cfb0cdfSLv Zheng err_lock: 5298cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) { 5308cfb0cdfSLv Zheng if (acpi_aml_active_reader == file) 5318cfb0cdfSLv Zheng acpi_aml_active_reader = NULL; 5328cfb0cdfSLv Zheng } 5338cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 5348cfb0cdfSLv Zheng return ret; 5358cfb0cdfSLv Zheng } 5368cfb0cdfSLv Zheng 5378cfb0cdfSLv Zheng static int acpi_aml_release(struct inode *inode, struct file *file) 5388cfb0cdfSLv Zheng { 5398cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 5408cfb0cdfSLv Zheng acpi_aml_io.users--; 5418cfb0cdfSLv Zheng if (file == acpi_aml_active_reader) { 5428cfb0cdfSLv Zheng pr_debug("Closing debugger reader.\n"); 5438cfb0cdfSLv Zheng acpi_aml_active_reader = NULL; 5448cfb0cdfSLv Zheng 5458cfb0cdfSLv Zheng pr_debug("Closing debugger interface.\n"); 5468cfb0cdfSLv Zheng acpi_aml_io.flags |= ACPI_AML_CLOSED; 5478cfb0cdfSLv Zheng 5488cfb0cdfSLv Zheng /* 5498cfb0cdfSLv Zheng * Wake up all user space/kernel space blocked 5508cfb0cdfSLv Zheng * readers/writers. 5518cfb0cdfSLv Zheng */ 5528cfb0cdfSLv Zheng wake_up_interruptible(&acpi_aml_io.wait); 5538cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 5548cfb0cdfSLv Zheng /* 5558cfb0cdfSLv Zheng * Wait all user space/kernel space readers/writers to 5568cfb0cdfSLv Zheng * stop so that ACPICA command loop of the debugger thread 5578cfb0cdfSLv Zheng * should fail all its command line reads after this point. 5588cfb0cdfSLv Zheng */ 5598cfb0cdfSLv Zheng wait_event(acpi_aml_io.wait, !acpi_aml_busy()); 5608cfb0cdfSLv Zheng 5618cfb0cdfSLv Zheng /* 5628cfb0cdfSLv Zheng * Then we try to terminate the debugger thread if it is 5638cfb0cdfSLv Zheng * not terminated. 5648cfb0cdfSLv Zheng */ 5658cfb0cdfSLv Zheng pr_debug("Terminating debugger thread.\n"); 5668cfb0cdfSLv Zheng acpi_terminate_debugger(); 5678cfb0cdfSLv Zheng wait_event(acpi_aml_io.wait, !acpi_aml_used()); 5688cfb0cdfSLv Zheng pr_debug("Debugger thread terminated.\n"); 5698cfb0cdfSLv Zheng 5708cfb0cdfSLv Zheng mutex_lock(&acpi_aml_io.lock); 5718cfb0cdfSLv Zheng acpi_aml_io.flags &= ~ACPI_AML_OPENED; 5728cfb0cdfSLv Zheng } 5738cfb0cdfSLv Zheng if (acpi_aml_io.users == 0) { 5748cfb0cdfSLv Zheng pr_debug("Debugger interface closed.\n"); 5758cfb0cdfSLv Zheng acpi_aml_io.flags &= ~ACPI_AML_CLOSED; 5768cfb0cdfSLv Zheng } 5778cfb0cdfSLv Zheng mutex_unlock(&acpi_aml_io.lock); 5788cfb0cdfSLv Zheng return 0; 5798cfb0cdfSLv Zheng } 5808cfb0cdfSLv Zheng 5818cfb0cdfSLv Zheng static int acpi_aml_read_user(char __user *buf, int len) 5828cfb0cdfSLv Zheng { 5838cfb0cdfSLv Zheng int ret; 5848cfb0cdfSLv Zheng struct circ_buf *crc = &acpi_aml_io.out_crc; 5858cfb0cdfSLv Zheng int n; 5868cfb0cdfSLv Zheng char *p; 5878cfb0cdfSLv Zheng 5888cfb0cdfSLv Zheng ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); 5898cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 5908cfb0cdfSLv Zheng return ret; 5918cfb0cdfSLv Zheng /* sync head before removing logs */ 5928cfb0cdfSLv Zheng smp_rmb(); 5938cfb0cdfSLv Zheng p = &crc->buf[crc->tail]; 5948cfb0cdfSLv Zheng n = min(len, circ_count_to_end(crc)); 5958cfb0cdfSLv Zheng ret = copy_to_user(buf, p, n); 5968cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 5978cfb0cdfSLv Zheng goto out; 5988cfb0cdfSLv Zheng /* sync tail after removing logs */ 5998cfb0cdfSLv Zheng smp_mb(); 6008cfb0cdfSLv Zheng crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); 6018cfb0cdfSLv Zheng ret = n; 6028cfb0cdfSLv Zheng out: 6038cfb0cdfSLv Zheng acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret)); 6048cfb0cdfSLv Zheng return ret; 6058cfb0cdfSLv Zheng } 6068cfb0cdfSLv Zheng 6078cfb0cdfSLv Zheng static ssize_t acpi_aml_read(struct file *file, char __user *buf, 6088cfb0cdfSLv Zheng size_t count, loff_t *ppos) 6098cfb0cdfSLv Zheng { 6108cfb0cdfSLv Zheng int ret = 0; 6118cfb0cdfSLv Zheng int size = 0; 6128cfb0cdfSLv Zheng 6138cfb0cdfSLv Zheng if (!buf || count < 0) 6148cfb0cdfSLv Zheng return -EINVAL; 6158cfb0cdfSLv Zheng if (!count) 6168cfb0cdfSLv Zheng return 0; 6178cfb0cdfSLv Zheng if (!access_ok(VERIFY_WRITE, buf, count)) 6188cfb0cdfSLv Zheng return -EFAULT; 6198cfb0cdfSLv Zheng 6208cfb0cdfSLv Zheng while (count > 0) { 6218cfb0cdfSLv Zheng again: 6228cfb0cdfSLv Zheng ret = acpi_aml_read_user(buf + size, count); 6238cfb0cdfSLv Zheng if (ret == -EAGAIN) { 6248cfb0cdfSLv Zheng if (file->f_flags & O_NONBLOCK) 6258cfb0cdfSLv Zheng break; 6268cfb0cdfSLv Zheng else { 6278cfb0cdfSLv Zheng ret = wait_event_interruptible(acpi_aml_io.wait, 6288cfb0cdfSLv Zheng acpi_aml_user_readable()); 6298cfb0cdfSLv Zheng /* 6308cfb0cdfSLv Zheng * We need to retry when the condition 6318cfb0cdfSLv Zheng * becomes true. 6328cfb0cdfSLv Zheng */ 6338cfb0cdfSLv Zheng if (ret == 0) 6348cfb0cdfSLv Zheng goto again; 6358cfb0cdfSLv Zheng } 6368cfb0cdfSLv Zheng } 6378cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) { 6388cfb0cdfSLv Zheng if (!acpi_aml_running()) 6398cfb0cdfSLv Zheng ret = 0; 6408cfb0cdfSLv Zheng break; 6418cfb0cdfSLv Zheng } 6428cfb0cdfSLv Zheng if (ret) { 6438cfb0cdfSLv Zheng size += ret; 6448cfb0cdfSLv Zheng count -= ret; 6458cfb0cdfSLv Zheng *ppos += ret; 6468cfb0cdfSLv Zheng break; 6478cfb0cdfSLv Zheng } 6488cfb0cdfSLv Zheng } 6498cfb0cdfSLv Zheng return size > 0 ? size : ret; 6508cfb0cdfSLv Zheng } 6518cfb0cdfSLv Zheng 6528cfb0cdfSLv Zheng static int acpi_aml_write_user(const char __user *buf, int len) 6538cfb0cdfSLv Zheng { 6548cfb0cdfSLv Zheng int ret; 6558cfb0cdfSLv Zheng struct circ_buf *crc = &acpi_aml_io.in_crc; 6568cfb0cdfSLv Zheng int n; 6578cfb0cdfSLv Zheng char *p; 6588cfb0cdfSLv Zheng 6598cfb0cdfSLv Zheng ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); 6608cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 6618cfb0cdfSLv Zheng return ret; 6628cfb0cdfSLv Zheng /* sync tail before inserting cmds */ 6638cfb0cdfSLv Zheng smp_mb(); 6648cfb0cdfSLv Zheng p = &crc->buf[crc->head]; 6658cfb0cdfSLv Zheng n = min(len, circ_space_to_end(crc)); 6668cfb0cdfSLv Zheng ret = copy_from_user(p, buf, n); 6678cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) 6688cfb0cdfSLv Zheng goto out; 6698cfb0cdfSLv Zheng /* sync head after inserting cmds */ 6708cfb0cdfSLv Zheng smp_wmb(); 6718cfb0cdfSLv Zheng crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); 6728cfb0cdfSLv Zheng ret = n; 6738cfb0cdfSLv Zheng out: 6748cfb0cdfSLv Zheng acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret)); 6758cfb0cdfSLv Zheng return n; 6768cfb0cdfSLv Zheng } 6778cfb0cdfSLv Zheng 6788cfb0cdfSLv Zheng static ssize_t acpi_aml_write(struct file *file, const char __user *buf, 6798cfb0cdfSLv Zheng size_t count, loff_t *ppos) 6808cfb0cdfSLv Zheng { 6818cfb0cdfSLv Zheng int ret = 0; 6828cfb0cdfSLv Zheng int size = 0; 6838cfb0cdfSLv Zheng 6848cfb0cdfSLv Zheng if (!buf || count < 0) 6858cfb0cdfSLv Zheng return -EINVAL; 6868cfb0cdfSLv Zheng if (!count) 6878cfb0cdfSLv Zheng return 0; 6888cfb0cdfSLv Zheng if (!access_ok(VERIFY_READ, buf, count)) 6898cfb0cdfSLv Zheng return -EFAULT; 6908cfb0cdfSLv Zheng 6918cfb0cdfSLv Zheng while (count > 0) { 6928cfb0cdfSLv Zheng again: 6938cfb0cdfSLv Zheng ret = acpi_aml_write_user(buf + size, count); 6948cfb0cdfSLv Zheng if (ret == -EAGAIN) { 6958cfb0cdfSLv Zheng if (file->f_flags & O_NONBLOCK) 6968cfb0cdfSLv Zheng break; 6978cfb0cdfSLv Zheng else { 6988cfb0cdfSLv Zheng ret = wait_event_interruptible(acpi_aml_io.wait, 6998cfb0cdfSLv Zheng acpi_aml_user_writable()); 7008cfb0cdfSLv Zheng /* 7018cfb0cdfSLv Zheng * We need to retry when the condition 7028cfb0cdfSLv Zheng * becomes true. 7038cfb0cdfSLv Zheng */ 7048cfb0cdfSLv Zheng if (ret == 0) 7058cfb0cdfSLv Zheng goto again; 7068cfb0cdfSLv Zheng } 7078cfb0cdfSLv Zheng } 7088cfb0cdfSLv Zheng if (IS_ERR_VALUE(ret)) { 7098cfb0cdfSLv Zheng if (!acpi_aml_running()) 7108cfb0cdfSLv Zheng ret = 0; 7118cfb0cdfSLv Zheng break; 7128cfb0cdfSLv Zheng } 7138cfb0cdfSLv Zheng if (ret) { 7148cfb0cdfSLv Zheng size += ret; 7158cfb0cdfSLv Zheng count -= ret; 7168cfb0cdfSLv Zheng *ppos += ret; 7178cfb0cdfSLv Zheng } 7188cfb0cdfSLv Zheng } 7198cfb0cdfSLv Zheng return size > 0 ? size : ret; 7208cfb0cdfSLv Zheng } 7218cfb0cdfSLv Zheng 7228cfb0cdfSLv Zheng static unsigned int acpi_aml_poll(struct file *file, poll_table *wait) 7238cfb0cdfSLv Zheng { 7248cfb0cdfSLv Zheng int masks = 0; 7258cfb0cdfSLv Zheng 7268cfb0cdfSLv Zheng poll_wait(file, &acpi_aml_io.wait, wait); 7278cfb0cdfSLv Zheng if (acpi_aml_user_readable()) 7288cfb0cdfSLv Zheng masks |= POLLIN | POLLRDNORM; 7298cfb0cdfSLv Zheng if (acpi_aml_user_writable()) 7308cfb0cdfSLv Zheng masks |= POLLOUT | POLLWRNORM; 7318cfb0cdfSLv Zheng 7328cfb0cdfSLv Zheng return masks; 7338cfb0cdfSLv Zheng } 7348cfb0cdfSLv Zheng 7358cfb0cdfSLv Zheng static const struct file_operations acpi_aml_operations = { 7368cfb0cdfSLv Zheng .read = acpi_aml_read, 7378cfb0cdfSLv Zheng .write = acpi_aml_write, 7388cfb0cdfSLv Zheng .poll = acpi_aml_poll, 7398cfb0cdfSLv Zheng .open = acpi_aml_open, 7408cfb0cdfSLv Zheng .release = acpi_aml_release, 7418cfb0cdfSLv Zheng .llseek = generic_file_llseek, 7428cfb0cdfSLv Zheng }; 7438cfb0cdfSLv Zheng 744836d0830SLv Zheng static const struct acpi_debugger_ops acpi_aml_debugger = { 745836d0830SLv Zheng .create_thread = acpi_aml_create_thread, 746836d0830SLv Zheng .read_cmd = acpi_aml_read_cmd, 747836d0830SLv Zheng .write_log = acpi_aml_write_log, 748836d0830SLv Zheng .wait_command_ready = acpi_aml_wait_command_ready, 749836d0830SLv Zheng .notify_command_complete = acpi_aml_notify_command_complete, 750836d0830SLv Zheng }; 751836d0830SLv Zheng 7528cfb0cdfSLv Zheng int __init acpi_aml_init(void) 7538cfb0cdfSLv Zheng { 754836d0830SLv Zheng int ret = 0; 755836d0830SLv Zheng 756836d0830SLv Zheng if (!acpi_debugfs_dir) { 757836d0830SLv Zheng ret = -ENOENT; 758836d0830SLv Zheng goto err_exit; 759836d0830SLv Zheng } 760836d0830SLv Zheng 7618cfb0cdfSLv Zheng /* Initialize AML IO interface */ 7628cfb0cdfSLv Zheng mutex_init(&acpi_aml_io.lock); 7638cfb0cdfSLv Zheng init_waitqueue_head(&acpi_aml_io.wait); 7648cfb0cdfSLv Zheng acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; 7658cfb0cdfSLv Zheng acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; 7668cfb0cdfSLv Zheng acpi_aml_dentry = debugfs_create_file("acpidbg", 7678cfb0cdfSLv Zheng S_IFREG | S_IRUGO | S_IWUSR, 7688cfb0cdfSLv Zheng acpi_debugfs_dir, NULL, 7698cfb0cdfSLv Zheng &acpi_aml_operations); 770836d0830SLv Zheng if (acpi_aml_dentry == NULL) { 771836d0830SLv Zheng ret = -ENODEV; 772836d0830SLv Zheng goto err_exit; 773836d0830SLv Zheng } 774836d0830SLv Zheng ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); 775836d0830SLv Zheng if (ret) 776836d0830SLv Zheng goto err_fs; 7778cfb0cdfSLv Zheng acpi_aml_initialized = true; 778836d0830SLv Zheng 779836d0830SLv Zheng err_fs: 780836d0830SLv Zheng if (ret) { 781836d0830SLv Zheng debugfs_remove(acpi_aml_dentry); 782836d0830SLv Zheng acpi_aml_dentry = NULL; 783836d0830SLv Zheng } 784836d0830SLv Zheng err_exit: 785836d0830SLv Zheng return ret; 7868cfb0cdfSLv Zheng } 7878cfb0cdfSLv Zheng 7888cfb0cdfSLv Zheng void __exit acpi_aml_exit(void) 7898cfb0cdfSLv Zheng { 790836d0830SLv Zheng if (acpi_aml_initialized) { 791836d0830SLv Zheng acpi_unregister_debugger(&acpi_aml_debugger); 792836d0830SLv Zheng if (acpi_aml_dentry) { 7938cfb0cdfSLv Zheng debugfs_remove(acpi_aml_dentry); 794836d0830SLv Zheng acpi_aml_dentry = NULL; 795836d0830SLv Zheng } 7968cfb0cdfSLv Zheng acpi_aml_initialized = false; 7978cfb0cdfSLv Zheng } 798836d0830SLv Zheng } 7998cfb0cdfSLv Zheng 8008cfb0cdfSLv Zheng module_init(acpi_aml_init); 8018cfb0cdfSLv Zheng module_exit(acpi_aml_exit); 802836d0830SLv Zheng 803836d0830SLv Zheng MODULE_AUTHOR("Lv Zheng"); 804836d0830SLv Zheng MODULE_DESCRIPTION("ACPI debugger userspace IO driver"); 805836d0830SLv Zheng MODULE_LICENSE("GPL"); 806