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