Merge tag 'renesas-sh-drivers-for-v4.5' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / acpi / osl.c
index d0ecf4e..67da6fb 100644 (file)
@@ -220,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...)
        acpi_os_vprintf(fmt, args);
        va_end(args);
 }
+EXPORT_SYMBOL(acpi_os_printf);
 
 void acpi_os_vprintf(const char *fmt, va_list args)
 {
@@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args)
                printk(KERN_CONT "%s", buffer);
        }
 #else
-       printk(KERN_CONT "%s", buffer);
+       if (acpi_debugger_write_log(buffer) < 0)
+               printk(KERN_CONT "%s", buffer);
 #endif
 }
 
@@ -1128,6 +1130,200 @@ static void acpi_os_execute_deferred(struct work_struct *work)
        kfree(dpc);
 }
 
+#ifdef CONFIG_ACPI_DEBUGGER
+static struct acpi_debugger acpi_debugger;
+static bool acpi_debugger_initialized;
+
+int acpi_register_debugger(struct module *owner,
+                          const struct acpi_debugger_ops *ops)
+{
+       int ret = 0;
+
+       mutex_lock(&acpi_debugger.lock);
+       if (acpi_debugger.ops) {
+               ret = -EBUSY;
+               goto err_lock;
+       }
+
+       acpi_debugger.owner = owner;
+       acpi_debugger.ops = ops;
+
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+EXPORT_SYMBOL(acpi_register_debugger);
+
+void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
+{
+       mutex_lock(&acpi_debugger.lock);
+       if (ops == acpi_debugger.ops) {
+               acpi_debugger.ops = NULL;
+               acpi_debugger.owner = NULL;
+       }
+       mutex_unlock(&acpi_debugger.lock);
+}
+EXPORT_SYMBOL(acpi_unregister_debugger);
+
+int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context)
+{
+       int ret;
+       int (*func)(acpi_osd_exec_callback, void *);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->create_thread;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(function, context);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+ssize_t acpi_debugger_write_log(const char *msg)
+{
+       ssize_t ret;
+       ssize_t (*func)(const char *);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->write_log;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(msg);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length)
+{
+       ssize_t ret;
+       ssize_t (*func)(char *, size_t);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->read_cmd;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(buffer, buffer_length);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int acpi_debugger_wait_command_ready(void)
+{
+       int ret;
+       int (*func)(bool, char *, size_t);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->wait_command_ready;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func(acpi_gbl_method_executing,
+                  acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE);
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int acpi_debugger_notify_command_complete(void)
+{
+       int ret;
+       int (*func)(void);
+       struct module *owner;
+
+       if (!acpi_debugger_initialized)
+               return -ENODEV;
+       mutex_lock(&acpi_debugger.lock);
+       if (!acpi_debugger.ops) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       if (!try_module_get(acpi_debugger.owner)) {
+               ret = -ENODEV;
+               goto err_lock;
+       }
+       func = acpi_debugger.ops->notify_command_complete;
+       owner = acpi_debugger.owner;
+       mutex_unlock(&acpi_debugger.lock);
+
+       ret = func();
+
+       mutex_lock(&acpi_debugger.lock);
+       module_put(owner);
+err_lock:
+       mutex_unlock(&acpi_debugger.lock);
+       return ret;
+}
+
+int __init acpi_debugger_init(void)
+{
+       mutex_init(&acpi_debugger.lock);
+       acpi_debugger_initialized = true;
+       return 0;
+}
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_os_execute
@@ -1154,6 +1350,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
 
+       if (type == OSL_DEBUGGER_MAIN_THREAD) {
+               ret = acpi_debugger_create_thread(function, context);
+               if (ret) {
+                       pr_err("Call to kthread_create() failed.\n");
+                       status = AE_ERROR;
+               }
+               goto out_thread;
+       }
+
        /*
         * Allocate/initialize DPC structure.  Note that this memory will be
         * freed by the callee.  The kernel handles the work_struct list  in a
@@ -1178,11 +1383,17 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        if (type == OSL_NOTIFY_HANDLER) {
                queue = kacpi_notify_wq;
                INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-       } else {
+       } else if (type == OSL_GPE_HANDLER) {
                queue = kacpid_wq;
                INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+       } else {
+               pr_err("Unsupported os_execute type %d.\n", type);
+               status = AE_ERROR;
        }
 
+       if (ACPI_FAILURE(status))
+               goto err_workqueue;
+
        /*
         * On some machines, a software-initiated SMI causes corruption unless
         * the SMI runs on CPU 0.  An SMI can be initiated by any AML, but
@@ -1191,13 +1402,15 @@ acpi_status acpi_os_execute(acpi_execute_type type,
         * queueing on CPU 0.
         */
        ret = queue_work_on(0, queue, &dpc->work);
-
        if (!ret) {
                printk(KERN_ERR PREFIX
                          "Call to queue_work() failed.\n");
                status = AE_ERROR;
-               kfree(dpc);
        }
+err_workqueue:
+       if (ACPI_FAILURE(status))
+               kfree(dpc);
+out_thread:
        return status;
 }
 EXPORT_SYMBOL(acpi_os_execute);
@@ -1385,10 +1598,39 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
                chars = strlen(buffer) - 1;
                buffer[chars] = '\0';
        }
+#else
+       int ret;
+
+       ret = acpi_debugger_read_cmd(buffer, buffer_length);
+       if (ret < 0)
+               return AE_ERROR;
+       if (bytes_read)
+               *bytes_read = ret;
 #endif
 
        return AE_OK;
 }
+EXPORT_SYMBOL(acpi_os_get_line);
+
+acpi_status acpi_os_wait_command_ready(void)
+{
+       int ret;
+
+       ret = acpi_debugger_wait_command_ready();
+       if (ret < 0)
+               return AE_ERROR;
+       return AE_OK;
+}
+
+acpi_status acpi_os_notify_command_complete(void)
+{
+       int ret;
+
+       ret = acpi_debugger_notify_command_complete();
+       if (ret < 0)
+               return AE_ERROR;
+       return AE_OK;
+}
 
 acpi_status acpi_os_signal(u32 function, void *info)
 {