0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) "ACPI: AML: " fmt
0011
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/wait.h>
0015 #include <linux/poll.h>
0016 #include <linux/sched.h>
0017 #include <linux/kthread.h>
0018 #include <linux/proc_fs.h>
0019 #include <linux/debugfs.h>
0020 #include <linux/circ_buf.h>
0021 #include <linux/acpi.h>
0022 #include "internal.h"
0023
0024 #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size))
0025 #define ACPI_AML_BUF_SIZE PAGE_SIZE
0026
0027 #define circ_count(circ) \
0028 (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
0029 #define circ_count_to_end(circ) \
0030 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
0031 #define circ_space(circ) \
0032 (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
0033 #define circ_space_to_end(circ) \
0034 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
0035
0036 #define ACPI_AML_OPENED 0x0001
0037 #define ACPI_AML_CLOSED 0x0002
0038 #define ACPI_AML_IN_USER 0x0004
0039 #define ACPI_AML_IN_KERN 0x0008
0040 #define ACPI_AML_OUT_USER 0x0010
0041 #define ACPI_AML_OUT_KERN 0x0020
0042 #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER)
0043 #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN)
0044 #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN)
0045 #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED)
0046
0047 struct acpi_aml_io {
0048 wait_queue_head_t wait;
0049 unsigned long flags;
0050 unsigned long users;
0051 struct mutex lock;
0052 struct task_struct *thread;
0053 char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
0054 struct circ_buf out_crc;
0055 char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
0056 struct circ_buf in_crc;
0057 acpi_osd_exec_callback function;
0058 void *context;
0059 unsigned long usages;
0060 };
0061
0062 static struct acpi_aml_io acpi_aml_io;
0063 static bool acpi_aml_initialized;
0064 static struct file *acpi_aml_active_reader;
0065 static struct dentry *acpi_aml_dentry;
0066
0067 static inline bool __acpi_aml_running(void)
0068 {
0069 return acpi_aml_io.thread ? true : false;
0070 }
0071
0072 static inline bool __acpi_aml_access_ok(unsigned long flag)
0073 {
0074
0075
0076
0077
0078
0079
0080
0081 if (!(acpi_aml_io.flags & ACPI_AML_OPENED) ||
0082 (acpi_aml_io.flags & ACPI_AML_CLOSED) ||
0083 !__acpi_aml_running())
0084 return false;
0085 if ((flag & ACPI_AML_KERN) &&
0086 current != acpi_aml_io.thread)
0087 return false;
0088 return true;
0089 }
0090
0091 static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag)
0092 {
0093
0094
0095
0096
0097 if (!(acpi_aml_io.flags & flag) && circ_count(circ))
0098 return true;
0099 return false;
0100 }
0101
0102 static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag)
0103 {
0104
0105
0106
0107
0108 if (!(acpi_aml_io.flags & flag) && circ_space(circ))
0109 return true;
0110 return false;
0111 }
0112
0113 static inline bool __acpi_aml_busy(void)
0114 {
0115 if (acpi_aml_io.flags & ACPI_AML_BUSY)
0116 return true;
0117 return false;
0118 }
0119
0120 static inline bool __acpi_aml_used(void)
0121 {
0122 return acpi_aml_io.usages ? true : false;
0123 }
0124
0125 static inline bool acpi_aml_running(void)
0126 {
0127 bool ret;
0128
0129 mutex_lock(&acpi_aml_io.lock);
0130 ret = __acpi_aml_running();
0131 mutex_unlock(&acpi_aml_io.lock);
0132 return ret;
0133 }
0134
0135 static bool acpi_aml_busy(void)
0136 {
0137 bool ret;
0138
0139 mutex_lock(&acpi_aml_io.lock);
0140 ret = __acpi_aml_busy();
0141 mutex_unlock(&acpi_aml_io.lock);
0142 return ret;
0143 }
0144
0145 static bool acpi_aml_used(void)
0146 {
0147 bool ret;
0148
0149
0150
0151
0152
0153 mutex_lock(&acpi_aml_io.lock);
0154 ret = __acpi_aml_used();
0155 mutex_unlock(&acpi_aml_io.lock);
0156 return ret;
0157 }
0158
0159 static bool acpi_aml_kern_readable(void)
0160 {
0161 bool ret;
0162
0163 mutex_lock(&acpi_aml_io.lock);
0164 ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) ||
0165 __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN);
0166 mutex_unlock(&acpi_aml_io.lock);
0167 return ret;
0168 }
0169
0170 static bool acpi_aml_kern_writable(void)
0171 {
0172 bool ret;
0173
0174 mutex_lock(&acpi_aml_io.lock);
0175 ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) ||
0176 __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN);
0177 mutex_unlock(&acpi_aml_io.lock);
0178 return ret;
0179 }
0180
0181 static bool acpi_aml_user_readable(void)
0182 {
0183 bool ret;
0184
0185 mutex_lock(&acpi_aml_io.lock);
0186 ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) ||
0187 __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER);
0188 mutex_unlock(&acpi_aml_io.lock);
0189 return ret;
0190 }
0191
0192 static bool acpi_aml_user_writable(void)
0193 {
0194 bool ret;
0195
0196 mutex_lock(&acpi_aml_io.lock);
0197 ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) ||
0198 __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER);
0199 mutex_unlock(&acpi_aml_io.lock);
0200 return ret;
0201 }
0202
0203 static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag)
0204 {
0205 int ret = 0;
0206
0207 mutex_lock(&acpi_aml_io.lock);
0208 if (!__acpi_aml_access_ok(flag)) {
0209 ret = -EFAULT;
0210 goto out;
0211 }
0212 if (!__acpi_aml_writable(circ, flag)) {
0213 ret = -EAGAIN;
0214 goto out;
0215 }
0216 acpi_aml_io.flags |= flag;
0217 out:
0218 mutex_unlock(&acpi_aml_io.lock);
0219 return ret;
0220 }
0221
0222 static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag)
0223 {
0224 int ret = 0;
0225
0226 mutex_lock(&acpi_aml_io.lock);
0227 if (!__acpi_aml_access_ok(flag)) {
0228 ret = -EFAULT;
0229 goto out;
0230 }
0231 if (!__acpi_aml_readable(circ, flag)) {
0232 ret = -EAGAIN;
0233 goto out;
0234 }
0235 acpi_aml_io.flags |= flag;
0236 out:
0237 mutex_unlock(&acpi_aml_io.lock);
0238 return ret;
0239 }
0240
0241 static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup)
0242 {
0243 mutex_lock(&acpi_aml_io.lock);
0244 acpi_aml_io.flags &= ~flag;
0245 if (wakeup)
0246 wake_up_interruptible(&acpi_aml_io.wait);
0247 mutex_unlock(&acpi_aml_io.lock);
0248 }
0249
0250 static int acpi_aml_write_kern(const char *buf, int len)
0251 {
0252 int ret;
0253 struct circ_buf *crc = &acpi_aml_io.out_crc;
0254 int n;
0255 char *p;
0256
0257 ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN);
0258 if (ret < 0)
0259 return ret;
0260
0261 smp_mb();
0262 p = &crc->buf[crc->head];
0263 n = min(len, circ_space_to_end(crc));
0264 memcpy(p, buf, n);
0265
0266 smp_wmb();
0267 crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
0268 acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true);
0269 return n;
0270 }
0271
0272 static int acpi_aml_readb_kern(void)
0273 {
0274 int ret;
0275 struct circ_buf *crc = &acpi_aml_io.in_crc;
0276 char *p;
0277
0278 ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN);
0279 if (ret < 0)
0280 return ret;
0281
0282 smp_rmb();
0283 p = &crc->buf[crc->tail];
0284 ret = (int)*p;
0285
0286 smp_mb();
0287 crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1);
0288 acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true);
0289 return ret;
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300 static ssize_t acpi_aml_write_log(const char *msg)
0301 {
0302 int ret = 0;
0303 int count = 0, size = 0;
0304
0305 if (!acpi_aml_initialized)
0306 return -ENODEV;
0307 if (msg)
0308 count = strlen(msg);
0309 while (count > 0) {
0310 again:
0311 ret = acpi_aml_write_kern(msg + size, count);
0312 if (ret == -EAGAIN) {
0313 ret = wait_event_interruptible(acpi_aml_io.wait,
0314 acpi_aml_kern_writable());
0315
0316
0317
0318
0319 if (ret == 0)
0320 goto again;
0321 break;
0322 }
0323 if (ret < 0)
0324 break;
0325 size += ret;
0326 count -= ret;
0327 }
0328 return size > 0 ? size : ret;
0329 }
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 static ssize_t acpi_aml_read_cmd(char *msg, size_t count)
0341 {
0342 int ret = 0;
0343 int size = 0;
0344
0345
0346
0347
0348
0349 BUG_ON(!acpi_aml_initialized);
0350 while (count > 0) {
0351 again:
0352
0353
0354
0355 ret = acpi_aml_readb_kern();
0356 if (ret == -EAGAIN) {
0357 ret = wait_event_interruptible(acpi_aml_io.wait,
0358 acpi_aml_kern_readable());
0359
0360
0361
0362
0363 if (ret == 0)
0364 goto again;
0365 }
0366 if (ret < 0)
0367 break;
0368 *(msg + size) = (char)ret;
0369 size++;
0370 count--;
0371 if (ret == '\n') {
0372
0373
0374
0375
0376 *(msg + size - 1) = '\0';
0377 break;
0378 }
0379 }
0380 return size > 0 ? size : ret;
0381 }
0382
0383 static int acpi_aml_thread(void *unused)
0384 {
0385 acpi_osd_exec_callback function = NULL;
0386 void *context;
0387
0388 mutex_lock(&acpi_aml_io.lock);
0389 if (acpi_aml_io.function) {
0390 acpi_aml_io.usages++;
0391 function = acpi_aml_io.function;
0392 context = acpi_aml_io.context;
0393 }
0394 mutex_unlock(&acpi_aml_io.lock);
0395
0396 if (function)
0397 function(context);
0398
0399 mutex_lock(&acpi_aml_io.lock);
0400 acpi_aml_io.usages--;
0401 if (!__acpi_aml_used()) {
0402 acpi_aml_io.thread = NULL;
0403 wake_up(&acpi_aml_io.wait);
0404 }
0405 mutex_unlock(&acpi_aml_io.lock);
0406
0407 return 0;
0408 }
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
0419 {
0420 struct task_struct *t;
0421
0422 mutex_lock(&acpi_aml_io.lock);
0423 acpi_aml_io.function = function;
0424 acpi_aml_io.context = context;
0425 mutex_unlock(&acpi_aml_io.lock);
0426
0427 t = kthread_create(acpi_aml_thread, NULL, "aml");
0428 if (IS_ERR(t)) {
0429 pr_err("Failed to create AML debugger thread.\n");
0430 return PTR_ERR(t);
0431 }
0432
0433 mutex_lock(&acpi_aml_io.lock);
0434 acpi_aml_io.thread = t;
0435 acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t);
0436 wake_up_process(t);
0437 mutex_unlock(&acpi_aml_io.lock);
0438 return 0;
0439 }
0440
0441 static int acpi_aml_wait_command_ready(bool single_step,
0442 char *buffer, size_t length)
0443 {
0444 acpi_status status;
0445
0446 if (single_step)
0447 acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
0448 else
0449 acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
0450
0451 status = acpi_os_get_line(buffer, length, NULL);
0452 if (ACPI_FAILURE(status))
0453 return -EINVAL;
0454 return 0;
0455 }
0456
0457 static int acpi_aml_notify_command_complete(void)
0458 {
0459 return 0;
0460 }
0461
0462 static int acpi_aml_open(struct inode *inode, struct file *file)
0463 {
0464 int ret = 0;
0465 acpi_status status;
0466
0467 mutex_lock(&acpi_aml_io.lock);
0468
0469
0470
0471
0472 if (acpi_aml_io.flags & ACPI_AML_CLOSED) {
0473 ret = -EBUSY;
0474 goto err_lock;
0475 }
0476 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
0477
0478
0479
0480
0481 if (acpi_aml_active_reader) {
0482 ret = -EBUSY;
0483 goto err_lock;
0484 } else {
0485 pr_debug("Opening debugger reader.\n");
0486 acpi_aml_active_reader = file;
0487 }
0488 } else {
0489
0490
0491
0492
0493 if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) {
0494 ret = -ENODEV;
0495 goto err_lock;
0496 }
0497 }
0498 if (acpi_aml_active_reader == file) {
0499 pr_debug("Opening debugger interface.\n");
0500 mutex_unlock(&acpi_aml_io.lock);
0501
0502 pr_debug("Initializing debugger thread.\n");
0503 status = acpi_initialize_debugger();
0504 if (ACPI_FAILURE(status)) {
0505 pr_err("Failed to initialize debugger.\n");
0506 ret = -EINVAL;
0507 goto err_exit;
0508 }
0509 pr_debug("Debugger thread initialized.\n");
0510
0511 mutex_lock(&acpi_aml_io.lock);
0512 acpi_aml_io.flags |= ACPI_AML_OPENED;
0513 acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0;
0514 acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0;
0515 pr_debug("Debugger interface opened.\n");
0516 }
0517 acpi_aml_io.users++;
0518 err_lock:
0519 if (ret < 0) {
0520 if (acpi_aml_active_reader == file)
0521 acpi_aml_active_reader = NULL;
0522 }
0523 mutex_unlock(&acpi_aml_io.lock);
0524 err_exit:
0525 return ret;
0526 }
0527
0528 static int acpi_aml_release(struct inode *inode, struct file *file)
0529 {
0530 mutex_lock(&acpi_aml_io.lock);
0531 acpi_aml_io.users--;
0532 if (file == acpi_aml_active_reader) {
0533 pr_debug("Closing debugger reader.\n");
0534 acpi_aml_active_reader = NULL;
0535
0536 pr_debug("Closing debugger interface.\n");
0537 acpi_aml_io.flags |= ACPI_AML_CLOSED;
0538
0539
0540
0541
0542
0543 wake_up_interruptible(&acpi_aml_io.wait);
0544 mutex_unlock(&acpi_aml_io.lock);
0545
0546
0547
0548
0549
0550 wait_event(acpi_aml_io.wait, !acpi_aml_busy());
0551
0552
0553
0554
0555
0556 pr_debug("Terminating debugger thread.\n");
0557 acpi_terminate_debugger();
0558 wait_event(acpi_aml_io.wait, !acpi_aml_used());
0559 pr_debug("Debugger thread terminated.\n");
0560
0561 mutex_lock(&acpi_aml_io.lock);
0562 acpi_aml_io.flags &= ~ACPI_AML_OPENED;
0563 }
0564 if (acpi_aml_io.users == 0) {
0565 pr_debug("Debugger interface closed.\n");
0566 acpi_aml_io.flags &= ~ACPI_AML_CLOSED;
0567 }
0568 mutex_unlock(&acpi_aml_io.lock);
0569 return 0;
0570 }
0571
0572 static int acpi_aml_read_user(char __user *buf, int len)
0573 {
0574 int ret;
0575 struct circ_buf *crc = &acpi_aml_io.out_crc;
0576 int n;
0577 char *p;
0578
0579 ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER);
0580 if (ret < 0)
0581 return ret;
0582
0583 smp_rmb();
0584 p = &crc->buf[crc->tail];
0585 n = min(len, circ_count_to_end(crc));
0586 if (copy_to_user(buf, p, n)) {
0587 ret = -EFAULT;
0588 goto out;
0589 }
0590
0591 smp_mb();
0592 crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1);
0593 ret = n;
0594 out:
0595 acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, ret >= 0);
0596 return ret;
0597 }
0598
0599 static ssize_t acpi_aml_read(struct file *file, char __user *buf,
0600 size_t count, loff_t *ppos)
0601 {
0602 int ret = 0;
0603 int size = 0;
0604
0605 if (!count)
0606 return 0;
0607 if (!access_ok(buf, count))
0608 return -EFAULT;
0609
0610 while (count > 0) {
0611 again:
0612 ret = acpi_aml_read_user(buf + size, count);
0613 if (ret == -EAGAIN) {
0614 if (file->f_flags & O_NONBLOCK)
0615 break;
0616 else {
0617 ret = wait_event_interruptible(acpi_aml_io.wait,
0618 acpi_aml_user_readable());
0619
0620
0621
0622
0623 if (ret == 0)
0624 goto again;
0625 }
0626 }
0627 if (ret < 0) {
0628 if (!acpi_aml_running())
0629 ret = 0;
0630 break;
0631 }
0632 if (ret) {
0633 size += ret;
0634 count -= ret;
0635 *ppos += ret;
0636 break;
0637 }
0638 }
0639 return size > 0 ? size : ret;
0640 }
0641
0642 static int acpi_aml_write_user(const char __user *buf, int len)
0643 {
0644 int ret;
0645 struct circ_buf *crc = &acpi_aml_io.in_crc;
0646 int n;
0647 char *p;
0648
0649 ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER);
0650 if (ret < 0)
0651 return ret;
0652
0653 smp_mb();
0654 p = &crc->buf[crc->head];
0655 n = min(len, circ_space_to_end(crc));
0656 if (copy_from_user(p, buf, n)) {
0657 ret = -EFAULT;
0658 goto out;
0659 }
0660
0661 smp_wmb();
0662 crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
0663 ret = n;
0664 out:
0665 acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0);
0666 return n;
0667 }
0668
0669 static ssize_t acpi_aml_write(struct file *file, const char __user *buf,
0670 size_t count, loff_t *ppos)
0671 {
0672 int ret = 0;
0673 int size = 0;
0674
0675 if (!count)
0676 return 0;
0677 if (!access_ok(buf, count))
0678 return -EFAULT;
0679
0680 while (count > 0) {
0681 again:
0682 ret = acpi_aml_write_user(buf + size, count);
0683 if (ret == -EAGAIN) {
0684 if (file->f_flags & O_NONBLOCK)
0685 break;
0686 else {
0687 ret = wait_event_interruptible(acpi_aml_io.wait,
0688 acpi_aml_user_writable());
0689
0690
0691
0692
0693 if (ret == 0)
0694 goto again;
0695 }
0696 }
0697 if (ret < 0) {
0698 if (!acpi_aml_running())
0699 ret = 0;
0700 break;
0701 }
0702 if (ret) {
0703 size += ret;
0704 count -= ret;
0705 *ppos += ret;
0706 }
0707 }
0708 return size > 0 ? size : ret;
0709 }
0710
0711 static __poll_t acpi_aml_poll(struct file *file, poll_table *wait)
0712 {
0713 __poll_t masks = 0;
0714
0715 poll_wait(file, &acpi_aml_io.wait, wait);
0716 if (acpi_aml_user_readable())
0717 masks |= EPOLLIN | EPOLLRDNORM;
0718 if (acpi_aml_user_writable())
0719 masks |= EPOLLOUT | EPOLLWRNORM;
0720
0721 return masks;
0722 }
0723
0724 static const struct file_operations acpi_aml_operations = {
0725 .read = acpi_aml_read,
0726 .write = acpi_aml_write,
0727 .poll = acpi_aml_poll,
0728 .open = acpi_aml_open,
0729 .release = acpi_aml_release,
0730 .llseek = generic_file_llseek,
0731 };
0732
0733 static const struct acpi_debugger_ops acpi_aml_debugger = {
0734 .create_thread = acpi_aml_create_thread,
0735 .read_cmd = acpi_aml_read_cmd,
0736 .write_log = acpi_aml_write_log,
0737 .wait_command_ready = acpi_aml_wait_command_ready,
0738 .notify_command_complete = acpi_aml_notify_command_complete,
0739 };
0740
0741 static int __init acpi_aml_init(void)
0742 {
0743 int ret;
0744
0745 if (acpi_disabled)
0746 return -ENODEV;
0747
0748
0749 mutex_init(&acpi_aml_io.lock);
0750 init_waitqueue_head(&acpi_aml_io.wait);
0751 acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf;
0752 acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf;
0753
0754 acpi_aml_dentry = debugfs_create_file("acpidbg",
0755 S_IFREG | S_IRUGO | S_IWUSR,
0756 acpi_debugfs_dir, NULL,
0757 &acpi_aml_operations);
0758
0759 ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger);
0760 if (ret) {
0761 debugfs_remove(acpi_aml_dentry);
0762 acpi_aml_dentry = NULL;
0763 return ret;
0764 }
0765
0766 acpi_aml_initialized = true;
0767 return 0;
0768 }
0769
0770 static void __exit acpi_aml_exit(void)
0771 {
0772 if (acpi_aml_initialized) {
0773 acpi_unregister_debugger(&acpi_aml_debugger);
0774 debugfs_remove(acpi_aml_dentry);
0775 acpi_aml_dentry = NULL;
0776 acpi_aml_initialized = false;
0777 }
0778 }
0779
0780 module_init(acpi_aml_init);
0781 module_exit(acpi_aml_exit);
0782
0783 MODULE_AUTHOR("Lv Zheng");
0784 MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
0785 MODULE_LICENSE("GPL");