123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805 |
- /*
- * ACPI AML interfacing support
- *
- * Copyright (C) 2015, Intel Corporation
- * Authors: Lv Zheng <lv.zheng@intel.com>
- *
- * 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.
- */
- /* #define DEBUG */
- #define pr_fmt(fmt) "ACPI : AML: " fmt
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/wait.h>
- #include <linux/poll.h>
- #include <linux/sched.h>
- #include <linux/kthread.h>
- #include <linux/proc_fs.h>
- #include <linux/debugfs.h>
- #include <linux/circ_buf.h>
- #include <linux/acpi.h>
- #include "internal.h"
- #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size))
- #define ACPI_AML_BUF_SIZE PAGE_SIZE
- #define circ_count(circ) \
- (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
- #define circ_count_to_end(circ) \
- (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
- #define circ_space(circ) \
- (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
- #define circ_space_to_end(circ) \
- (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
- #define ACPI_AML_OPENED 0x0001
- #define ACPI_AML_CLOSED 0x0002
- #define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */
- #define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */
- #define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */
- #define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */
- #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER)
- #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN)
- #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN)
- #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED)
- struct acpi_aml_io {
- wait_queue_head_t wait;
- unsigned long flags;
- unsigned long users;
- struct mutex lock;
- struct task_struct *thread;
- char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
- struct circ_buf out_crc;
- char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
- struct circ_buf in_crc;
- acpi_osd_exec_callback function;
- void *context;
- unsigned long usages;
- };
- static struct acpi_aml_io acpi_aml_io;
- static bool acpi_aml_initialized;
- static struct file *acpi_aml_active_reader;
- static struct dentry *acpi_aml_dentry;
- static inline bool __acpi_aml_running(void)
- {
- return acpi_aml_io.thread ? true : false;
- }
- static inline bool __acpi_aml_access_ok(unsigned long flag)
- {
- /*
- * The debugger interface is in opened state (OPENED && !CLOSED),
- * then it is allowed to access the debugger buffers from either
- * user space or the kernel space.
- * In addition, for the kernel space, only the debugger thread
- * (thread ID matched) is allowed to access.
- */
- if (!(acpi_aml_io.flags & ACPI_AML_OPENED) ||
- (acpi_aml_io.flags & ACPI_AML_CLOSED) ||
- !__acpi_aml_running())
- return false;
- if ((flag & ACPI_AML_KERN) &&
- current != acpi_aml_io.thread)
- return false;
- return true;
- }
- static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag)
- {
- /*
- * Another read is not in progress and there is data in buffer
- * available for read.
- */
- if (!(acpi_aml_io.flags & flag) && circ_count(circ))
- return true;
- return false;
- }
- static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag)
- {
- /*
- * Another write is not in progress and there is buffer space
- * available for write.
- */
- if (!(acpi_aml_io.flags & flag) && circ_space(circ))
- return true;
- return false;
- }
- static inline bool __acpi_aml_busy(void)
- {
- if (acpi_aml_io.flags & ACPI_AML_BUSY)
- return true;
- return false;
- }
- static inline bool __acpi_aml_opened(void)
- {
- if (acpi_aml_io.flags & ACPI_AML_OPEN)
- return true;
- return false;
- }
- static inline bool __acpi_aml_used(void)
- {
- return acpi_aml_io.usages ? true : false;
- }
- static inline bool acpi_aml_running(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = __acpi_aml_running();
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_busy(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = __acpi_aml_busy();
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_used(void)
- {
- bool ret;
- /*
- * The usage count is prepared to avoid race conditions between the
- * starts and the stops of the debugger thread.
- */
- mutex_lock(&acpi_aml_io.lock);
- ret = __acpi_aml_used();
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_kern_readable(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) ||
- __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN);
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_kern_writable(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) ||
- __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN);
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_user_readable(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) ||
- __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER);
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static bool acpi_aml_user_writable(void)
- {
- bool ret;
- mutex_lock(&acpi_aml_io.lock);
- ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) ||
- __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER);
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag)
- {
- int ret = 0;
- mutex_lock(&acpi_aml_io.lock);
- if (!__acpi_aml_access_ok(flag)) {
- ret = -EFAULT;
- goto out;
- }
- if (!__acpi_aml_writable(circ, flag)) {
- ret = -EAGAIN;
- goto out;
- }
- acpi_aml_io.flags |= flag;
- out:
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag)
- {
- int ret = 0;
- mutex_lock(&acpi_aml_io.lock);
- if (!__acpi_aml_access_ok(flag)) {
- ret = -EFAULT;
- goto out;
- }
- if (!__acpi_aml_readable(circ, flag)) {
- ret = -EAGAIN;
- goto out;
- }
- acpi_aml_io.flags |= flag;
- out:
- mutex_unlock(&acpi_aml_io.lock);
- return ret;
- }
- static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup)
- {
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.flags &= ~flag;
- if (wakeup)
- wake_up_interruptible(&acpi_aml_io.wait);
- mutex_unlock(&acpi_aml_io.lock);
- }
- static int acpi_aml_write_kern(const char *buf, int len)
- {
- int ret;
- struct circ_buf *crc = &acpi_aml_io.out_crc;
- int n;
- char *p;
- ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN);
- if (ret < 0)
- return ret;
- /* sync tail before inserting logs */
- smp_mb();
- p = &crc->buf[crc->head];
- n = min(len, circ_space_to_end(crc));
- memcpy(p, buf, n);
- /* sync head after inserting logs */
- smp_wmb();
- crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
- acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true);
- return n;
- }
- static int acpi_aml_readb_kern(void)
- {
- int ret;
- struct circ_buf *crc = &acpi_aml_io.in_crc;
- char *p;
- ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN);
- if (ret < 0)
- return ret;
- /* sync head before removing cmds */
- smp_rmb();
- p = &crc->buf[crc->tail];
- ret = (int)*p;
- /* sync tail before inserting cmds */
- smp_mb();
- crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1);
- acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true);
- return ret;
- }
- /*
- * acpi_aml_write_log() - Capture debugger output
- * @msg: the debugger output
- *
- * This function should be used to implement acpi_os_printf() to filter out
- * the debugger output and store the output into the debugger interface
- * buffer. Return the size of stored logs or errno.
- */
- static ssize_t acpi_aml_write_log(const char *msg)
- {
- int ret = 0;
- int count = 0, size = 0;
- if (!acpi_aml_initialized)
- return -ENODEV;
- if (msg)
- count = strlen(msg);
- while (count > 0) {
- again:
- ret = acpi_aml_write_kern(msg + size, count);
- if (ret == -EAGAIN) {
- ret = wait_event_interruptible(acpi_aml_io.wait,
- acpi_aml_kern_writable());
- /*
- * We need to retry when the condition
- * becomes true.
- */
- if (ret == 0)
- goto again;
- break;
- }
- if (ret < 0)
- break;
- size += ret;
- count -= ret;
- }
- return size > 0 ? size : ret;
- }
- /*
- * acpi_aml_read_cmd() - Capture debugger input
- * @msg: the debugger input
- * @size: the size of the debugger input
- *
- * This function should be used to implement acpi_os_get_line() to capture
- * the debugger input commands and store the input commands into the
- * debugger interface buffer. Return the size of stored commands or errno.
- */
- static ssize_t acpi_aml_read_cmd(char *msg, size_t count)
- {
- int ret = 0;
- int size = 0;
- /*
- * This is ensured by the running fact of the debugger thread
- * unless a bug is introduced.
- */
- BUG_ON(!acpi_aml_initialized);
- while (count > 0) {
- again:
- /*
- * Check each input byte to find the end of the command.
- */
- ret = acpi_aml_readb_kern();
- if (ret == -EAGAIN) {
- ret = wait_event_interruptible(acpi_aml_io.wait,
- acpi_aml_kern_readable());
- /*
- * We need to retry when the condition becomes
- * true.
- */
- if (ret == 0)
- goto again;
- }
- if (ret < 0)
- break;
- *(msg + size) = (char)ret;
- size++;
- count--;
- if (ret == '\n') {
- /*
- * acpi_os_get_line() requires a zero terminated command
- * string.
- */
- *(msg + size - 1) = '\0';
- break;
- }
- }
- return size > 0 ? size : ret;
- }
- static int acpi_aml_thread(void *unsed)
- {
- acpi_osd_exec_callback function = NULL;
- void *context;
- mutex_lock(&acpi_aml_io.lock);
- if (acpi_aml_io.function) {
- acpi_aml_io.usages++;
- function = acpi_aml_io.function;
- context = acpi_aml_io.context;
- }
- mutex_unlock(&acpi_aml_io.lock);
- if (function)
- function(context);
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.usages--;
- if (!__acpi_aml_used()) {
- acpi_aml_io.thread = NULL;
- wake_up(&acpi_aml_io.wait);
- }
- mutex_unlock(&acpi_aml_io.lock);
- return 0;
- }
- /*
- * acpi_aml_create_thread() - Create AML debugger thread
- * @function: the debugger thread callback
- * @context: the context to be passed to the debugger thread
- *
- * This function should be used to implement acpi_os_execute() which is
- * used by the ACPICA debugger to create the debugger thread.
- */
- static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
- {
- struct task_struct *t;
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.function = function;
- acpi_aml_io.context = context;
- mutex_unlock(&acpi_aml_io.lock);
- t = kthread_create(acpi_aml_thread, NULL, "aml");
- if (IS_ERR(t)) {
- pr_err("Failed to create AML debugger thread.\n");
- return PTR_ERR(t);
- }
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.thread = t;
- acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t);
- wake_up_process(t);
- mutex_unlock(&acpi_aml_io.lock);
- return 0;
- }
- static int acpi_aml_wait_command_ready(bool single_step,
- char *buffer, size_t length)
- {
- acpi_status status;
- if (single_step)
- acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
- else
- acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
- status = acpi_os_get_line(buffer, length, NULL);
- if (ACPI_FAILURE(status))
- return -EINVAL;
- return 0;
- }
- static int acpi_aml_notify_command_complete(void)
- {
- return 0;
- }
- static int acpi_aml_open(struct inode *inode, struct file *file)
- {
- int ret = 0;
- acpi_status status;
- mutex_lock(&acpi_aml_io.lock);
- /*
- * The debugger interface is being closed, no new user is allowed
- * during this period.
- */
- if (acpi_aml_io.flags & ACPI_AML_CLOSED) {
- ret = -EBUSY;
- goto err_lock;
- }
- if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
- /*
- * Only one reader is allowed to initiate the debugger
- * thread.
- */
- if (acpi_aml_active_reader) {
- ret = -EBUSY;
- goto err_lock;
- } else {
- pr_debug("Opening debugger reader.\n");
- acpi_aml_active_reader = file;
- }
- } else {
- /*
- * No writer is allowed unless the debugger thread is
- * ready.
- */
- if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) {
- ret = -ENODEV;
- goto err_lock;
- }
- }
- if (acpi_aml_active_reader == file) {
- pr_debug("Opening debugger interface.\n");
- mutex_unlock(&acpi_aml_io.lock);
- pr_debug("Initializing debugger thread.\n");
- status = acpi_initialize_debugger();
- if (ACPI_FAILURE(status)) {
- pr_err("Failed to initialize debugger.\n");
- ret = -EINVAL;
- goto err_exit;
- }
- pr_debug("Debugger thread initialized.\n");
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.flags |= ACPI_AML_OPENED;
- acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0;
- acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0;
- pr_debug("Debugger interface opened.\n");
- }
- acpi_aml_io.users++;
- err_lock:
- if (ret < 0) {
- if (acpi_aml_active_reader == file)
- acpi_aml_active_reader = NULL;
- }
- mutex_unlock(&acpi_aml_io.lock);
- err_exit:
- return ret;
- }
- static int acpi_aml_release(struct inode *inode, struct file *file)
- {
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.users--;
- if (file == acpi_aml_active_reader) {
- pr_debug("Closing debugger reader.\n");
- acpi_aml_active_reader = NULL;
- pr_debug("Closing debugger interface.\n");
- acpi_aml_io.flags |= ACPI_AML_CLOSED;
- /*
- * Wake up all user space/kernel space blocked
- * readers/writers.
- */
- wake_up_interruptible(&acpi_aml_io.wait);
- mutex_unlock(&acpi_aml_io.lock);
- /*
- * Wait all user space/kernel space readers/writers to
- * stop so that ACPICA command loop of the debugger thread
- * should fail all its command line reads after this point.
- */
- wait_event(acpi_aml_io.wait, !acpi_aml_busy());
- /*
- * Then we try to terminate the debugger thread if it is
- * not terminated.
- */
- pr_debug("Terminating debugger thread.\n");
- acpi_terminate_debugger();
- wait_event(acpi_aml_io.wait, !acpi_aml_used());
- pr_debug("Debugger thread terminated.\n");
- mutex_lock(&acpi_aml_io.lock);
- acpi_aml_io.flags &= ~ACPI_AML_OPENED;
- }
- if (acpi_aml_io.users == 0) {
- pr_debug("Debugger interface closed.\n");
- acpi_aml_io.flags &= ~ACPI_AML_CLOSED;
- }
- mutex_unlock(&acpi_aml_io.lock);
- return 0;
- }
- static int acpi_aml_read_user(char __user *buf, int len)
- {
- int ret;
- struct circ_buf *crc = &acpi_aml_io.out_crc;
- int n;
- char *p;
- ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER);
- if (ret < 0)
- return ret;
- /* sync head before removing logs */
- smp_rmb();
- p = &crc->buf[crc->tail];
- n = min(len, circ_count_to_end(crc));
- if (copy_to_user(buf, p, n)) {
- ret = -EFAULT;
- goto out;
- }
- /* sync tail after removing logs */
- smp_mb();
- crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1);
- ret = n;
- out:
- acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, ret >= 0);
- return ret;
- }
- static ssize_t acpi_aml_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
- {
- int ret = 0;
- int size = 0;
- if (!count)
- return 0;
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
- while (count > 0) {
- again:
- ret = acpi_aml_read_user(buf + size, count);
- if (ret == -EAGAIN) {
- if (file->f_flags & O_NONBLOCK)
- break;
- else {
- ret = wait_event_interruptible(acpi_aml_io.wait,
- acpi_aml_user_readable());
- /*
- * We need to retry when the condition
- * becomes true.
- */
- if (ret == 0)
- goto again;
- }
- }
- if (ret < 0) {
- if (!acpi_aml_running())
- ret = 0;
- break;
- }
- if (ret) {
- size += ret;
- count -= ret;
- *ppos += ret;
- break;
- }
- }
- return size > 0 ? size : ret;
- }
- static int acpi_aml_write_user(const char __user *buf, int len)
- {
- int ret;
- struct circ_buf *crc = &acpi_aml_io.in_crc;
- int n;
- char *p;
- ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER);
- if (ret < 0)
- return ret;
- /* sync tail before inserting cmds */
- smp_mb();
- p = &crc->buf[crc->head];
- n = min(len, circ_space_to_end(crc));
- if (copy_from_user(p, buf, n)) {
- ret = -EFAULT;
- goto out;
- }
- /* sync head after inserting cmds */
- smp_wmb();
- crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
- ret = n;
- out:
- acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0);
- return n;
- }
- static ssize_t acpi_aml_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
- {
- int ret = 0;
- int size = 0;
- if (!count)
- return 0;
- if (!access_ok(VERIFY_READ, buf, count))
- return -EFAULT;
- while (count > 0) {
- again:
- ret = acpi_aml_write_user(buf + size, count);
- if (ret == -EAGAIN) {
- if (file->f_flags & O_NONBLOCK)
- break;
- else {
- ret = wait_event_interruptible(acpi_aml_io.wait,
- acpi_aml_user_writable());
- /*
- * We need to retry when the condition
- * becomes true.
- */
- if (ret == 0)
- goto again;
- }
- }
- if (ret < 0) {
- if (!acpi_aml_running())
- ret = 0;
- break;
- }
- if (ret) {
- size += ret;
- count -= ret;
- *ppos += ret;
- }
- }
- return size > 0 ? size : ret;
- }
- static unsigned int acpi_aml_poll(struct file *file, poll_table *wait)
- {
- int masks = 0;
- poll_wait(file, &acpi_aml_io.wait, wait);
- if (acpi_aml_user_readable())
- masks |= POLLIN | POLLRDNORM;
- if (acpi_aml_user_writable())
- masks |= POLLOUT | POLLWRNORM;
- return masks;
- }
- static const struct file_operations acpi_aml_operations = {
- .read = acpi_aml_read,
- .write = acpi_aml_write,
- .poll = acpi_aml_poll,
- .open = acpi_aml_open,
- .release = acpi_aml_release,
- .llseek = generic_file_llseek,
- };
- static const struct acpi_debugger_ops acpi_aml_debugger = {
- .create_thread = acpi_aml_create_thread,
- .read_cmd = acpi_aml_read_cmd,
- .write_log = acpi_aml_write_log,
- .wait_command_ready = acpi_aml_wait_command_ready,
- .notify_command_complete = acpi_aml_notify_command_complete,
- };
- int __init acpi_aml_init(void)
- {
- int ret = 0;
- if (!acpi_debugfs_dir) {
- ret = -ENOENT;
- goto err_exit;
- }
- /* Initialize AML IO interface */
- mutex_init(&acpi_aml_io.lock);
- init_waitqueue_head(&acpi_aml_io.wait);
- acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf;
- acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf;
- acpi_aml_dentry = debugfs_create_file("acpidbg",
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_debugfs_dir, NULL,
- &acpi_aml_operations);
- if (acpi_aml_dentry == NULL) {
- ret = -ENODEV;
- goto err_exit;
- }
- ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger);
- if (ret)
- goto err_fs;
- acpi_aml_initialized = true;
- err_fs:
- if (ret) {
- debugfs_remove(acpi_aml_dentry);
- acpi_aml_dentry = NULL;
- }
- err_exit:
- return ret;
- }
- void __exit acpi_aml_exit(void)
- {
- if (acpi_aml_initialized) {
- acpi_unregister_debugger(&acpi_aml_debugger);
- if (acpi_aml_dentry) {
- debugfs_remove(acpi_aml_dentry);
- acpi_aml_dentry = NULL;
- }
- acpi_aml_initialized = false;
- }
- }
- module_init(acpi_aml_init);
- module_exit(acpi_aml_exit);
- MODULE_AUTHOR("Lv Zheng");
- MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
- MODULE_LICENSE("GPL");
|