linux/drivers/acpi/acpi_dbg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ACPI AML interfacing support
   4 *
   5 * Copyright (C) 2015, Intel Corporation
   6 * Authors: Lv Zheng <lv.zheng@intel.com>
   7 */
   8
   9/* #define DEBUG */
  10#define pr_fmt(fmt) "ACPI: AML: " fmt
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/wait.h>
  15#include <linux/poll.h>
  16#include <linux/sched.h>
  17#include <linux/kthread.h>
  18#include <linux/proc_fs.h>
  19#include <linux/debugfs.h>
  20#include <linux/circ_buf.h>
  21#include <linux/acpi.h>
  22#include "internal.h"
  23
  24#define ACPI_AML_BUF_ALIGN      (sizeof (acpi_size))
  25#define ACPI_AML_BUF_SIZE       PAGE_SIZE
  26
  27#define circ_count(circ) \
  28        (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
  29#define circ_count_to_end(circ) \
  30        (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
  31#define circ_space(circ) \
  32        (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
  33#define circ_space_to_end(circ) \
  34        (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
  35
  36#define ACPI_AML_OPENED         0x0001
  37#define ACPI_AML_CLOSED         0x0002
  38#define ACPI_AML_IN_USER        0x0004 /* user space is writing cmd */
  39#define ACPI_AML_IN_KERN        0x0008 /* kernel space is reading cmd */
  40#define ACPI_AML_OUT_USER       0x0010 /* user space is reading log */
  41#define ACPI_AML_OUT_KERN       0x0020 /* kernel space is writing log */
  42#define ACPI_AML_USER           (ACPI_AML_IN_USER | ACPI_AML_OUT_USER)
  43#define ACPI_AML_KERN           (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN)
  44#define ACPI_AML_BUSY           (ACPI_AML_USER | ACPI_AML_KERN)
  45#define ACPI_AML_OPEN           (ACPI_AML_OPENED | ACPI_AML_CLOSED)
  46
  47struct acpi_aml_io {
  48        wait_queue_head_t wait;
  49        unsigned long flags;
  50        unsigned long users;
  51        struct mutex lock;
  52        struct task_struct *thread;
  53        char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
  54        struct circ_buf out_crc;
  55        char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN);
  56        struct circ_buf in_crc;
  57        acpi_osd_exec_callback function;
  58        void *context;
  59        unsigned long usages;
  60};
  61
  62static struct acpi_aml_io acpi_aml_io;
  63static bool acpi_aml_initialized;
  64static struct file *acpi_aml_active_reader;
  65static struct dentry *acpi_aml_dentry;
  66
  67static inline bool __acpi_aml_running(void)
  68{
  69        return acpi_aml_io.thread ? true : false;
  70}
  71
  72static inline bool __acpi_aml_access_ok(unsigned long flag)
  73{
  74        /*
  75         * The debugger interface is in opened state (OPENED && !CLOSED),
  76         * then it is allowed to access the debugger buffers from either
  77         * user space or the kernel space.
  78         * In addition, for the kernel space, only the debugger thread
  79         * (thread ID matched) is allowed to access.
  80         */
  81        if (!(acpi_aml_io.flags & ACPI_AML_OPENED) ||
  82            (acpi_aml_io.flags & ACPI_AML_CLOSED) ||
  83            !__acpi_aml_running())
  84                return false;
  85        if ((flag & ACPI_AML_KERN) &&
  86            current != acpi_aml_io.thread)
  87                return false;
  88        return true;
  89}
  90
  91static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag)
  92{
  93        /*
  94         * Another read is not in progress and there is data in buffer
  95         * available for read.
  96         */
  97        if (!(acpi_aml_io.flags & flag) && circ_count(circ))
  98                return true;
  99        return false;
 100}
 101
 102static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag)
 103{
 104        /*
 105         * Another write is not in progress and there is buffer space
 106         * available for write.
 107         */
 108        if (!(acpi_aml_io.flags & flag) && circ_space(circ))
 109                return true;
 110        return false;
 111}
 112
 113static inline bool __acpi_aml_busy(void)
 114{
 115        if (acpi_aml_io.flags & ACPI_AML_BUSY)
 116                return true;
 117        return false;
 118}
 119
 120static inline bool __acpi_aml_used(void)
 121{
 122        return acpi_aml_io.usages ? true : false;
 123}
 124
 125static inline bool acpi_aml_running(void)
 126{
 127        bool ret;
 128
 129        mutex_lock(&acpi_aml_io.lock);
 130        ret = __acpi_aml_running();
 131        mutex_unlock(&acpi_aml_io.lock);
 132        return ret;
 133}
 134
 135static bool acpi_aml_busy(void)
 136{
 137        bool ret;
 138
 139        mutex_lock(&acpi_aml_io.lock);
 140        ret = __acpi_aml_busy();
 141        mutex_unlock(&acpi_aml_io.lock);
 142        return ret;
 143}
 144
 145static bool acpi_aml_used(void)
 146{
 147        bool ret;
 148
 149        /*
 150         * The usage count is prepared to avoid race conditions between the
 151         * starts and the stops of the debugger thread.
 152         */
 153        mutex_lock(&acpi_aml_io.lock);
 154        ret = __acpi_aml_used();
 155        mutex_unlock(&acpi_aml_io.lock);
 156        return ret;
 157}
 158
 159static bool acpi_aml_kern_readable(void)
 160{
 161        bool ret;
 162
 163        mutex_lock(&acpi_aml_io.lock);
 164        ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) ||
 165              __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN);
 166        mutex_unlock(&acpi_aml_io.lock);
 167        return ret;
 168}
 169
 170static bool acpi_aml_kern_writable(void)
 171{
 172        bool ret;
 173
 174        mutex_lock(&acpi_aml_io.lock);
 175        ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) ||
 176              __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN);
 177        mutex_unlock(&acpi_aml_io.lock);
 178        return ret;
 179}
 180
 181static bool acpi_aml_user_readable(void)
 182{
 183        bool ret;
 184
 185        mutex_lock(&acpi_aml_io.lock);
 186        ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) ||
 187              __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER);
 188        mutex_unlock(&acpi_aml_io.lock);
 189        return ret;
 190}
 191
 192static bool acpi_aml_user_writable(void)
 193{
 194        bool ret;
 195
 196        mutex_lock(&acpi_aml_io.lock);
 197        ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) ||
 198              __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER);
 199        mutex_unlock(&acpi_aml_io.lock);
 200        return ret;
 201}
 202
 203static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag)
 204{
 205        int ret = 0;
 206
 207        mutex_lock(&acpi_aml_io.lock);
 208        if (!__acpi_aml_access_ok(flag)) {
 209                ret = -EFAULT;
 210                goto out;
 211        }
 212        if (!__acpi_aml_writable(circ, flag)) {
 213                ret = -EAGAIN;
 214                goto out;
 215        }
 216        acpi_aml_io.flags |= flag;
 217out:
 218        mutex_unlock(&acpi_aml_io.lock);
 219        return ret;
 220}
 221
 222static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag)
 223{
 224        int ret = 0;
 225
 226        mutex_lock(&acpi_aml_io.lock);
 227        if (!__acpi_aml_access_ok(flag)) {
 228                ret = -EFAULT;
 229                goto out;
 230        }
 231        if (!__acpi_aml_readable(circ, flag)) {
 232                ret = -EAGAIN;
 233                goto out;
 234        }
 235        acpi_aml_io.flags |= flag;
 236out:
 237        mutex_unlock(&acpi_aml_io.lock);
 238        return ret;
 239}
 240
 241static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup)
 242{
 243        mutex_lock(&acpi_aml_io.lock);
 244        acpi_aml_io.flags &= ~flag;
 245        if (wakeup)
 246                wake_up_interruptible(&acpi_aml_io.wait);
 247        mutex_unlock(&acpi_aml_io.lock);
 248}
 249
 250static int acpi_aml_write_kern(const char *buf, int len)
 251{
 252        int ret;
 253        struct circ_buf *crc = &acpi_aml_io.out_crc;
 254        int n;
 255        char *p;
 256
 257        ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN);
 258        if (ret < 0)
 259                return ret;
 260        /* sync tail before inserting logs */
 261        smp_mb();
 262        p = &crc->buf[crc->head];
 263        n = min(len, circ_space_to_end(crc));
 264        memcpy(p, buf, n);
 265        /* sync head after inserting logs */
 266        smp_wmb();
 267        crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
 268        acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true);
 269        return n;
 270}
 271
 272static int acpi_aml_readb_kern(void)
 273{
 274        int ret;
 275        struct circ_buf *crc = &acpi_aml_io.in_crc;
 276        char *p;
 277
 278        ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN);
 279        if (ret < 0)
 280                return ret;
 281        /* sync head before removing cmds */
 282        smp_rmb();
 283        p = &crc->buf[crc->tail];
 284        ret = (int)*p;
 285        /* sync tail before inserting cmds */
 286        smp_mb();
 287        crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1);
 288        acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true);
 289        return ret;
 290}
 291
 292/*
 293 * acpi_aml_write_log() - Capture debugger output
 294 * @msg: the debugger output
 295 *
 296 * This function should be used to implement acpi_os_printf() to filter out
 297 * the debugger output and store the output into the debugger interface
 298 * buffer. Return the size of stored logs or errno.
 299 */
 300static ssize_t acpi_aml_write_log(const char *msg)
 301{
 302        int ret = 0;
 303        int count = 0, size = 0;
 304
 305        if (!acpi_aml_initialized)
 306                return -ENODEV;
 307        if (msg)
 308                count = strlen(msg);
 309        while (count > 0) {
 310again:
 311                ret = acpi_aml_write_kern(msg + size, count);
 312                if (ret == -EAGAIN) {
 313                        ret = wait_event_interruptible(acpi_aml_io.wait,
 314                                acpi_aml_kern_writable());
 315                        /*
 316                         * We need to retry when the condition
 317                         * becomes true.
 318                         */
 319                        if (ret == 0)
 320                                goto again;
 321                        break;
 322                }
 323                if (ret < 0)
 324                        break;
 325                size += ret;
 326                count -= ret;
 327        }
 328        return size > 0 ? size : ret;
 329}
 330
 331/*
 332 * acpi_aml_read_cmd() - Capture debugger input
 333 * @msg: the debugger input
 334 * @size: the size of the debugger input
 335 *
 336 * This function should be used to implement acpi_os_get_line() to capture
 337 * the debugger input commands and store the input commands into the
 338 * debugger interface buffer. Return the size of stored commands or errno.
 339 */
 340static ssize_t acpi_aml_read_cmd(char *msg, size_t count)
 341{
 342        int ret = 0;
 343        int size = 0;
 344
 345        /*
 346         * This is ensured by the running fact of the debugger thread
 347         * unless a bug is introduced.
 348         */
 349        BUG_ON(!acpi_aml_initialized);
 350        while (count > 0) {
 351again:
 352                /*
 353                 * Check each input byte to find the end of the command.
 354                 */
 355                ret = acpi_aml_readb_kern();
 356                if (ret == -EAGAIN) {
 357                        ret = wait_event_interruptible(acpi_aml_io.wait,
 358                                acpi_aml_kern_readable());
 359                        /*
 360                         * We need to retry when the condition becomes
 361                         * true.
 362                         */
 363                        if (ret == 0)
 364                                goto again;
 365                }
 366                if (ret < 0)
 367                        break;
 368                *(msg + size) = (char)ret;
 369                size++;
 370                count--;
 371                if (ret == '\n') {
 372                        /*
 373                         * acpi_os_get_line() requires a zero terminated command
 374                         * string.
 375                         */
 376                        *(msg + size - 1) = '\0';
 377                        break;
 378                }
 379        }
 380        return size > 0 ? size : ret;
 381}
 382
 383static int acpi_aml_thread(void *unused)
 384{
 385        acpi_osd_exec_callback function = NULL;
 386        void *context;
 387
 388        mutex_lock(&acpi_aml_io.lock);
 389        if (acpi_aml_io.function) {
 390                acpi_aml_io.usages++;
 391                function = acpi_aml_io.function;
 392                context = acpi_aml_io.context;
 393        }
 394        mutex_unlock(&acpi_aml_io.lock);
 395
 396        if (function)
 397                function(context);
 398
 399        mutex_lock(&acpi_aml_io.lock);
 400        acpi_aml_io.usages--;
 401        if (!__acpi_aml_used()) {
 402                acpi_aml_io.thread = NULL;
 403                wake_up(&acpi_aml_io.wait);
 404        }
 405        mutex_unlock(&acpi_aml_io.lock);
 406
 407        return 0;
 408}
 409
 410/*
 411 * acpi_aml_create_thread() - Create AML debugger thread
 412 * @function: the debugger thread callback
 413 * @context: the context to be passed to the debugger thread
 414 *
 415 * This function should be used to implement acpi_os_execute() which is
 416 * used by the ACPICA debugger to create the debugger thread.
 417 */
 418static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context)
 419{
 420        struct task_struct *t;
 421
 422        mutex_lock(&acpi_aml_io.lock);
 423        acpi_aml_io.function = function;
 424        acpi_aml_io.context = context;
 425        mutex_unlock(&acpi_aml_io.lock);
 426
 427        t = kthread_create(acpi_aml_thread, NULL, "aml");
 428        if (IS_ERR(t)) {
 429                pr_err("Failed to create AML debugger thread.\n");
 430                return PTR_ERR(t);
 431        }
 432
 433        mutex_lock(&acpi_aml_io.lock);
 434        acpi_aml_io.thread = t;
 435        acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t);
 436        wake_up_process(t);
 437        mutex_unlock(&acpi_aml_io.lock);
 438        return 0;
 439}
 440
 441static int acpi_aml_wait_command_ready(bool single_step,
 442                                       char *buffer, size_t length)
 443{
 444        acpi_status status;
 445
 446        if (single_step)
 447                acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
 448        else
 449                acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
 450
 451        status = acpi_os_get_line(buffer, length, NULL);
 452        if (ACPI_FAILURE(status))
 453                return -EINVAL;
 454        return 0;
 455}
 456
 457static int acpi_aml_notify_command_complete(void)
 458{
 459        return 0;
 460}
 461
 462static int acpi_aml_open(struct inode *inode, struct file *file)
 463{
 464        int ret = 0;
 465        acpi_status status;
 466
 467        mutex_lock(&acpi_aml_io.lock);
 468        /*
 469         * The debugger interface is being closed, no new user is allowed
 470         * during this period.
 471         */
 472        if (acpi_aml_io.flags & ACPI_AML_CLOSED) {
 473                ret = -EBUSY;
 474                goto err_lock;
 475        }
 476        if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
 477                /*
 478                 * Only one reader is allowed to initiate the debugger
 479                 * thread.
 480                 */
 481                if (acpi_aml_active_reader) {
 482                        ret = -EBUSY;
 483                        goto err_lock;
 484                } else {
 485                        pr_debug("Opening debugger reader.\n");
 486                        acpi_aml_active_reader = file;
 487                }
 488        } else {
 489                /*
 490                 * No writer is allowed unless the debugger thread is
 491                 * ready.
 492                 */
 493                if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) {
 494                        ret = -ENODEV;
 495                        goto err_lock;
 496                }
 497        }
 498        if (acpi_aml_active_reader == file) {
 499                pr_debug("Opening debugger interface.\n");
 500                mutex_unlock(&acpi_aml_io.lock);
 501
 502                pr_debug("Initializing debugger thread.\n");
 503                status = acpi_initialize_debugger();
 504                if (ACPI_FAILURE(status)) {
 505                        pr_err("Failed to initialize debugger.\n");
 506                        ret = -EINVAL;
 507                        goto err_exit;
 508                }
 509                pr_debug("Debugger thread initialized.\n");
 510
 511                mutex_lock(&acpi_aml_io.lock);
 512                acpi_aml_io.flags |= ACPI_AML_OPENED;
 513                acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0;
 514                acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0;
 515                pr_debug("Debugger interface opened.\n");
 516        }
 517        acpi_aml_io.users++;
 518err_lock:
 519        if (ret < 0) {
 520                if (acpi_aml_active_reader == file)
 521                        acpi_aml_active_reader = NULL;
 522        }
 523        mutex_unlock(&acpi_aml_io.lock);
 524err_exit:
 525        return ret;
 526}
 527
 528static int acpi_aml_release(struct inode *inode, struct file *file)
 529{
 530        mutex_lock(&acpi_aml_io.lock);
 531        acpi_aml_io.users--;
 532        if (file == acpi_aml_active_reader) {
 533                pr_debug("Closing debugger reader.\n");
 534                acpi_aml_active_reader = NULL;
 535
 536                pr_debug("Closing debugger interface.\n");
 537                acpi_aml_io.flags |= ACPI_AML_CLOSED;
 538
 539                /*
 540                 * Wake up all user space/kernel space blocked
 541                 * readers/writers.
 542                 */
 543                wake_up_interruptible(&acpi_aml_io.wait);
 544                mutex_unlock(&acpi_aml_io.lock);
 545                /*
 546                 * Wait all user space/kernel space readers/writers to
 547                 * stop so that ACPICA command loop of the debugger thread
 548                 * should fail all its command line reads after this point.
 549                 */
 550                wait_event(acpi_aml_io.wait, !acpi_aml_busy());
 551
 552                /*
 553                 * Then we try to terminate the debugger thread if it is
 554                 * not terminated.
 555                 */
 556                pr_debug("Terminating debugger thread.\n");
 557                acpi_terminate_debugger();
 558                wait_event(acpi_aml_io.wait, !acpi_aml_used());
 559                pr_debug("Debugger thread terminated.\n");
 560
 561                mutex_lock(&acpi_aml_io.lock);
 562                acpi_aml_io.flags &= ~ACPI_AML_OPENED;
 563        }
 564        if (acpi_aml_io.users == 0) {
 565                pr_debug("Debugger interface closed.\n");
 566                acpi_aml_io.flags &= ~ACPI_AML_CLOSED;
 567        }
 568        mutex_unlock(&acpi_aml_io.lock);
 569        return 0;
 570}
 571
 572static int acpi_aml_read_user(char __user *buf, int len)
 573{
 574        int ret;
 575        struct circ_buf *crc = &acpi_aml_io.out_crc;
 576        int n;
 577        char *p;
 578
 579        ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER);
 580        if (ret < 0)
 581                return ret;
 582        /* sync head before removing logs */
 583        smp_rmb();
 584        p = &crc->buf[crc->tail];
 585        n = min(len, circ_count_to_end(crc));
 586        if (copy_to_user(buf, p, n)) {
 587                ret = -EFAULT;
 588                goto out;
 589        }
 590        /* sync tail after removing logs */
 591        smp_mb();
 592        crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1);
 593        ret = n;
 594out:
 595        acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, ret >= 0);
 596        return ret;
 597}
 598
 599static ssize_t acpi_aml_read(struct file *file, char __user *buf,
 600                             size_t count, loff_t *ppos)
 601{
 602        int ret = 0;
 603        int size = 0;
 604
 605        if (!count)
 606                return 0;
 607        if (!access_ok(buf, count))
 608                return -EFAULT;
 609
 610        while (count > 0) {
 611again:
 612                ret = acpi_aml_read_user(buf + size, count);
 613                if (ret == -EAGAIN) {
 614                        if (file->f_flags & O_NONBLOCK)
 615                                break;
 616                        else {
 617                                ret = wait_event_interruptible(acpi_aml_io.wait,
 618                                        acpi_aml_user_readable());
 619                                /*
 620                                 * We need to retry when the condition
 621                                 * becomes true.
 622                                 */
 623                                if (ret == 0)
 624                                        goto again;
 625                        }
 626                }
 627                if (ret < 0) {
 628                        if (!acpi_aml_running())
 629                                ret = 0;
 630                        break;
 631                }
 632                if (ret) {
 633                        size += ret;
 634                        count -= ret;
 635                        *ppos += ret;
 636                        break;
 637                }
 638        }
 639        return size > 0 ? size : ret;
 640}
 641
 642static int acpi_aml_write_user(const char __user *buf, int len)
 643{
 644        int ret;
 645        struct circ_buf *crc = &acpi_aml_io.in_crc;
 646        int n;
 647        char *p;
 648
 649        ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER);
 650        if (ret < 0)
 651                return ret;
 652        /* sync tail before inserting cmds */
 653        smp_mb();
 654        p = &crc->buf[crc->head];
 655        n = min(len, circ_space_to_end(crc));
 656        if (copy_from_user(p, buf, n)) {
 657                ret = -EFAULT;
 658                goto out;
 659        }
 660        /* sync head after inserting cmds */
 661        smp_wmb();
 662        crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1);
 663        ret = n;
 664out:
 665        acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0);
 666        return n;
 667}
 668
 669static ssize_t acpi_aml_write(struct file *file, const char __user *buf,
 670                              size_t count, loff_t *ppos)
 671{
 672        int ret = 0;
 673        int size = 0;
 674
 675        if (!count)
 676                return 0;
 677        if (!access_ok(buf, count))
 678                return -EFAULT;
 679
 680        while (count > 0) {
 681again:
 682                ret = acpi_aml_write_user(buf + size, count);
 683                if (ret == -EAGAIN) {
 684                        if (file->f_flags & O_NONBLOCK)
 685                                break;
 686                        else {
 687                                ret = wait_event_interruptible(acpi_aml_io.wait,
 688                                        acpi_aml_user_writable());
 689                                /*
 690                                 * We need to retry when the condition
 691                                 * becomes true.
 692                                 */
 693                                if (ret == 0)
 694                                        goto again;
 695                        }
 696                }
 697                if (ret < 0) {
 698                        if (!acpi_aml_running())
 699                                ret = 0;
 700                        break;
 701                }
 702                if (ret) {
 703                        size += ret;
 704                        count -= ret;
 705                        *ppos += ret;
 706                }
 707        }
 708        return size > 0 ? size : ret;
 709}
 710
 711static __poll_t acpi_aml_poll(struct file *file, poll_table *wait)
 712{
 713        __poll_t masks = 0;
 714
 715        poll_wait(file, &acpi_aml_io.wait, wait);
 716        if (acpi_aml_user_readable())
 717                masks |= EPOLLIN | EPOLLRDNORM;
 718        if (acpi_aml_user_writable())
 719                masks |= EPOLLOUT | EPOLLWRNORM;
 720
 721        return masks;
 722}
 723
 724static const struct file_operations acpi_aml_operations = {
 725        .read           = acpi_aml_read,
 726        .write          = acpi_aml_write,
 727        .poll           = acpi_aml_poll,
 728        .open           = acpi_aml_open,
 729        .release        = acpi_aml_release,
 730        .llseek         = generic_file_llseek,
 731};
 732
 733static const struct acpi_debugger_ops acpi_aml_debugger = {
 734        .create_thread           = acpi_aml_create_thread,
 735        .read_cmd                = acpi_aml_read_cmd,
 736        .write_log               = acpi_aml_write_log,
 737        .wait_command_ready      = acpi_aml_wait_command_ready,
 738        .notify_command_complete = acpi_aml_notify_command_complete,
 739};
 740
 741static int __init acpi_aml_init(void)
 742{
 743        int ret;
 744
 745        if (acpi_disabled)
 746                return -ENODEV;
 747
 748        /* Initialize AML IO interface */
 749        mutex_init(&acpi_aml_io.lock);
 750        init_waitqueue_head(&acpi_aml_io.wait);
 751        acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf;
 752        acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf;
 753
 754        acpi_aml_dentry = debugfs_create_file("acpidbg",
 755                                              S_IFREG | S_IRUGO | S_IWUSR,
 756                                              acpi_debugfs_dir, NULL,
 757                                              &acpi_aml_operations);
 758
 759        ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger);
 760        if (ret) {
 761                debugfs_remove(acpi_aml_dentry);
 762                acpi_aml_dentry = NULL;
 763                return ret;
 764        }
 765
 766        acpi_aml_initialized = true;
 767        return 0;
 768}
 769
 770static void __exit acpi_aml_exit(void)
 771{
 772        if (acpi_aml_initialized) {
 773                acpi_unregister_debugger(&acpi_aml_debugger);
 774                debugfs_remove(acpi_aml_dentry);
 775                acpi_aml_dentry = NULL;
 776                acpi_aml_initialized = false;
 777        }
 778}
 779
 780module_init(acpi_aml_init);
 781module_exit(acpi_aml_exit);
 782
 783MODULE_AUTHOR("Lv Zheng");
 784MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
 785MODULE_LICENSE("GPL");
 786
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.