Last active
November 25, 2019 16:13
-
-
Save digetx/b24e38ed7c10dcaea0a1bda39c406c0a to your computer and use it in GitHub Desktop.
ramconsole
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From ffea1cc88d7480d0cd4e1ead196ff53555ccc5a4 Mon Sep 17 00:00:00 2001 | |
From: Dmitry Osipenko <digetx@gmail.com> | |
Date: Thu, 4 Oct 2018 16:46:38 +0300 | |
Subject: [PATCH] ramconsole | |
--- | |
drivers/staging/android/Kconfig | 2 + | |
drivers/staging/android/Makefile | 2 + | |
drivers/staging/android/ramconsole/Kconfig | 63 +++ | |
drivers/staging/android/ramconsole/Makefile | 1 + | |
.../staging/android/ramconsole/ram_console.c | 487 ++++++++++++++++++ | |
.../staging/android/ramconsole/ram_console.h | 22 + | |
6 files changed, 577 insertions(+) | |
create mode 100644 drivers/staging/android/ramconsole/Kconfig | |
create mode 100644 drivers/staging/android/ramconsole/Makefile | |
create mode 100644 drivers/staging/android/ramconsole/ram_console.c | |
create mode 100644 drivers/staging/android/ramconsole/ram_console.h | |
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig | |
index d6d605d5cbde..de5cd0966ec1 100644 | |
--- a/drivers/staging/android/Kconfig | |
+++ b/drivers/staging/android/Kconfig | |
@@ -27,3 +27,5 @@ source "drivers/staging/android/ion/Kconfig" | |
endif # if ANDROID | |
endmenu | |
+ | |
+source "drivers/staging/android/ramconsole/Kconfig" | |
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile | |
index 14bd9c6ce10d..8c9404af0f2b 100644 | |
--- a/drivers/staging/android/Makefile | |
+++ b/drivers/staging/android/Makefile | |
@@ -5,3 +5,5 @@ obj-y += ion/ | |
obj-$(CONFIG_ASHMEM) += ashmem.o | |
obj-$(CONFIG_ANDROID_VSOC) += vsoc.o | |
+ | |
+obj-y += ramconsole/ | |
diff --git a/drivers/staging/android/ramconsole/Kconfig b/drivers/staging/android/ramconsole/Kconfig | |
new file mode 100644 | |
index 000000000000..db03dca04572 | |
--- /dev/null | |
+++ b/drivers/staging/android/ramconsole/Kconfig | |
@@ -0,0 +1,63 @@ | |
+config ANDROID_RAM_CONSOLE | |
+ bool "Android RAM buffer console" | |
+ default n | |
+ | |
+config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE | |
+ bool "Enable verbose console messages on Android RAM console" | |
+ default y | |
+ depends on ANDROID_RAM_CONSOLE | |
+ | |
+menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ bool "Android RAM Console Enable error correction" | |
+ default n | |
+ depends on ANDROID_RAM_CONSOLE | |
+ depends on !ANDROID_RAM_CONSOLE_EARLY_INIT | |
+ select REED_SOLOMON | |
+ select REED_SOLOMON_ENC8 | |
+ select REED_SOLOMON_DEC8 | |
+ | |
+if ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ | |
+config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE | |
+ int "Android RAM Console Data data size" | |
+ default 128 | |
+ help | |
+ Must be a power of 2. | |
+ | |
+config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE | |
+ int "Android RAM Console ECC size" | |
+ default 16 | |
+ | |
+config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE | |
+ int "Android RAM Console Symbol size" | |
+ default 8 | |
+ | |
+config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL | |
+ hex "Android RAM Console Polynomial" | |
+ default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4) | |
+ default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5) | |
+ default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6) | |
+ default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7) | |
+ default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8) | |
+ | |
+endif # ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ | |
+config ANDROID_RAM_CONSOLE_EARLY_INIT | |
+ bool "Start Android RAM console early" | |
+ default n | |
+ depends on ANDROID_RAM_CONSOLE | |
+ | |
+config ANDROID_RAM_CONSOLE_EARLY_ADDR | |
+ hex "Android RAM console virtual address" | |
+ default 0 | |
+ depends on ANDROID_RAM_CONSOLE_EARLY_INIT | |
+ | |
+config ANDROID_RAM_CONSOLE_EARLY_SIZE | |
+ hex "Android RAM console buffer size" | |
+ default 0 | |
+ depends on ANDROID_RAM_CONSOLE_EARLY_INIT | |
+ | |
+config ANDROID_RAM_CONSOLE_DEBUG_CONSOLE_SUSPENDED | |
+ bool "Resume console in case of kernel panic" | |
+ default n | |
+ depends on ANDROID_RAM_CONSOLE | |
diff --git a/drivers/staging/android/ramconsole/Makefile b/drivers/staging/android/ramconsole/Makefile | |
new file mode 100644 | |
index 000000000000..1125854a955b | |
--- /dev/null | |
+++ b/drivers/staging/android/ramconsole/Makefile | |
@@ -0,0 +1 @@ | |
+obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o | |
diff --git a/drivers/staging/android/ramconsole/ram_console.c b/drivers/staging/android/ramconsole/ram_console.c | |
new file mode 100644 | |
index 000000000000..bb3c6f07fc7a | |
--- /dev/null | |
+++ b/drivers/staging/android/ramconsole/ram_console.c | |
@@ -0,0 +1,487 @@ | |
+/* drivers/android/ram_console.c | |
+ * | |
+ * Copyright (C) 2007-2008 Google, Inc. | |
+ * | |
+ * This software is licensed under the terms of the GNU General Public | |
+ * License version 2, as published by the Free Software Foundation, and | |
+ * may be copied, distributed, and modified under those terms. | |
+ * | |
+ * This program is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU General Public License for more details. | |
+ * | |
+ */ | |
+ | |
+#include <linux/console.h> | |
+#include <linux/init.h> | |
+#include <linux/module.h> | |
+#include <linux/platform_device.h> | |
+#include <linux/proc_fs.h> | |
+#include <linux/string.h> | |
+#include <linux/uaccess.h> | |
+#include <linux/io.h> | |
+#include <linux/of_device.h> | |
+#include <linux/memblock.h> | |
+#include <linux/slab.h> | |
+ | |
+#include "ram_console.h" | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+#include <linux/rslib.h> | |
+#endif | |
+ | |
+struct ram_console_buffer { | |
+ __le32 sig; | |
+ __le32 start; | |
+ __le32 size; | |
+ uint8_t data[0]; | |
+}; | |
+ | |
+#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */ | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT | |
+static char __initdata | |
+ ram_console_old_log_init_buffer[CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE]; | |
+#endif | |
+static char *ram_console_old_log; | |
+static size_t ram_console_old_log_size; | |
+ | |
+static struct ram_console_buffer *ram_console_buffer; | |
+static size_t ram_console_buffer_size; | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+static char *ram_console_par_buffer; | |
+static struct rs_control *ram_console_rs_decoder; | |
+static int ram_console_corrected_bytes; | |
+static int ram_console_bad_blocks; | |
+#define ECC_BLOCK_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE | |
+#define ECC_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE | |
+#define ECC_SYMSIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE | |
+#define ECC_POLY CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL | |
+#endif | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+static void ram_console_encode_rs8(uint8_t *data, size_t len, uint8_t *ecc) | |
+{ | |
+ int i; | |
+ uint16_t par[ECC_SIZE]; | |
+ /* Initialize the parity buffer */ | |
+ memset(par, 0, sizeof(par)); | |
+ encode_rs8(ram_console_rs_decoder, data, len, par, 0); | |
+ for (i = 0; i < ECC_SIZE; i++) | |
+ ecc[i] = par[i]; | |
+} | |
+ | |
+static int ram_console_decode_rs8(void *data, size_t len, uint8_t *ecc) | |
+{ | |
+ int i; | |
+ uint16_t par[ECC_SIZE]; | |
+ for (i = 0; i < ECC_SIZE; i++) | |
+ par[i] = ecc[i]; | |
+ return decode_rs8(ram_console_rs_decoder, data, par, len, | |
+ NULL, 0, NULL, 0, NULL); | |
+} | |
+#endif | |
+ | |
+static void ram_console_update(const char *s, unsigned int count) | |
+{ | |
+ struct ram_console_buffer *buffer = ram_console_buffer; | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ uint8_t *buffer_end = buffer->data + ram_console_buffer_size; | |
+ uint8_t *block; | |
+ uint8_t *par; | |
+ int size = ECC_BLOCK_SIZE; | |
+#endif | |
+ memcpy(buffer->data + le32_to_cpu(buffer->start), s, count); | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ block = buffer->data + (le32_to_cpu(buffer->start) & ~(ECC_BLOCK_SIZE - 1)); | |
+ par = ram_console_par_buffer + | |
+ (le32_to_cpu(buffer->start) / ECC_BLOCK_SIZE) * ECC_SIZE; | |
+ do { | |
+ if (block + ECC_BLOCK_SIZE > buffer_end) | |
+ size = buffer_end - block; | |
+ ram_console_encode_rs8(block, size, par); | |
+ block += ECC_BLOCK_SIZE; | |
+ par += ECC_SIZE; | |
+ } while (block < buffer->data + le32_to_cpu(buffer->start) + count); | |
+#endif | |
+} | |
+ | |
+static void ram_console_update_header(void) | |
+{ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ struct ram_console_buffer *buffer = ram_console_buffer; | |
+ uint8_t *par; | |
+ par = ram_console_par_buffer + | |
+ DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE; | |
+ ram_console_encode_rs8((uint8_t *)buffer, sizeof(*buffer), par); | |
+#endif | |
+} | |
+ | |
+static void | |
+ram_console_write(struct console *console, const char *s, unsigned int count) | |
+{ | |
+ int rem; | |
+ struct ram_console_buffer *buffer = ram_console_buffer; | |
+ | |
+ if (count > ram_console_buffer_size) { | |
+ s += count - ram_console_buffer_size; | |
+ count = ram_console_buffer_size; | |
+ } | |
+ rem = ram_console_buffer_size - le32_to_cpu(buffer->start); | |
+ if (rem < count) { | |
+ ram_console_update(s, rem); | |
+ s += rem; | |
+ count -= rem; | |
+ buffer->start = 0; | |
+ buffer->size = cpu_to_le32(ram_console_buffer_size); | |
+ } | |
+ ram_console_update(s, count); | |
+ | |
+ buffer->start = cpu_to_le32(le32_to_cpu(buffer->start) + count); | |
+ if (le32_to_cpu(buffer->size) < ram_console_buffer_size) | |
+ buffer->size = cpu_to_le32(le32_to_cpu(buffer->size) + count); | |
+ ram_console_update_header(); | |
+} | |
+ | |
+static struct console ram_console = { | |
+ .name = "ram", | |
+ .write = ram_console_write, | |
+ .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, | |
+ .index = -1, | |
+}; | |
+ | |
+void ram_console_enable_console(int enabled) | |
+{ | |
+ if (enabled) | |
+ ram_console.flags |= CON_ENABLED; | |
+ else | |
+ ram_console.flags &= ~CON_ENABLED; | |
+} | |
+ | |
+static void __init | |
+ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo, | |
+ char *dest) | |
+{ | |
+ size_t old_log_size = buffer->size; | |
+ size_t bootinfo_size = 0; | |
+ size_t total_size = old_log_size; | |
+ char *ptr; | |
+ const char *bootinfo_label = "Boot info:\n"; | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ uint8_t *block; | |
+ uint8_t *par; | |
+ char strbuf[80]; | |
+ int strbuf_len = 0; | |
+ | |
+ block = buffer->data; | |
+ par = ram_console_par_buffer; | |
+ while (block < buffer->data + buffer->size) { | |
+ int numerr; | |
+ int size = ECC_BLOCK_SIZE; | |
+ if (block + size > buffer->data + ram_console_buffer_size) | |
+ size = buffer->data + ram_console_buffer_size - block; | |
+ numerr = ram_console_decode_rs8(block, size, par); | |
+ if (numerr > 0) { | |
+#if 0 | |
+ printk(KERN_INFO "ram_console: error in block %p, %d\n", | |
+ block, numerr); | |
+#endif | |
+ ram_console_corrected_bytes += numerr; | |
+ } else if (numerr < 0) { | |
+#if 0 | |
+ printk(KERN_INFO "ram_console: uncorrectable error in " | |
+ "block %p\n", block); | |
+#endif | |
+ ram_console_bad_blocks++; | |
+ } | |
+ block += ECC_BLOCK_SIZE; | |
+ par += ECC_SIZE; | |
+ } | |
+ if (ram_console_corrected_bytes || ram_console_bad_blocks) | |
+ strbuf_len = snprintf(strbuf, sizeof(strbuf), | |
+ "\n%d Corrected bytes, %d unrecoverable blocks\n", | |
+ ram_console_corrected_bytes, ram_console_bad_blocks); | |
+ else | |
+ strbuf_len = snprintf(strbuf, sizeof(strbuf), | |
+ "\nNo errors detected\n"); | |
+ if (strbuf_len >= sizeof(strbuf)) | |
+ strbuf_len = sizeof(strbuf) - 1; | |
+ total_size += strbuf_len; | |
+#endif | |
+ | |
+ if (bootinfo) | |
+ bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label); | |
+ total_size += bootinfo_size; | |
+ | |
+ if (dest == NULL) { | |
+ dest = kmalloc(total_size, GFP_KERNEL); | |
+ if (dest == NULL) { | |
+ printk(KERN_ERR | |
+ "ram_console: failed to allocate buffer\n"); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ ram_console_old_log = dest; | |
+ ram_console_old_log_size = total_size; | |
+ memcpy(ram_console_old_log, | |
+ &buffer->data[le32_to_cpu(buffer->start)], buffer->size - le32_to_cpu(buffer->start)); | |
+ memcpy(ram_console_old_log + buffer->size - le32_to_cpu(buffer->start), | |
+ &buffer->data[0], le32_to_cpu(buffer->start)); | |
+ ptr = ram_console_old_log + old_log_size; | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ memcpy(ptr, strbuf, strbuf_len); | |
+ ptr += strbuf_len; | |
+#endif | |
+ if (bootinfo) { | |
+ memcpy(ptr, bootinfo_label, strlen(bootinfo_label)); | |
+ ptr += strlen(bootinfo_label); | |
+ memcpy(ptr, bootinfo, bootinfo_size); | |
+ ptr += bootinfo_size; | |
+ } | |
+} | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_DEBUG_CONSOLE_SUSPENDED | |
+static int ram_panic_event(struct notifier_block *this, | |
+ unsigned long event, void *ptr) | |
+{ | |
+ resume_console(); | |
+ return NOTIFY_DONE; | |
+} | |
+ | |
+static struct notifier_block ram_panic_blk = { | |
+ .notifier_call = ram_panic_event, | |
+}; | |
+#endif | |
+ | |
+static int __init ram_console_init(struct ram_console_buffer *buffer, | |
+ size_t buffer_size, const char *bootinfo, | |
+ char *old_buf) | |
+{ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ int numerr; | |
+ uint8_t *par; | |
+#endif | |
+ ram_console_buffer = buffer; | |
+ ram_console_buffer_size = | |
+ buffer_size - sizeof(struct ram_console_buffer); | |
+ | |
+ if (ram_console_buffer_size > buffer_size) { | |
+ pr_err("ram_console: buffer %p, invalid size %zu, " | |
+ "datasize %zu\n", buffer, buffer_size, | |
+ ram_console_buffer_size); | |
+ return 0; | |
+ } | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION | |
+ ram_console_buffer_size -= (DIV_ROUND_UP(ram_console_buffer_size, | |
+ ECC_BLOCK_SIZE) + 1) * ECC_SIZE; | |
+ | |
+ if (ram_console_buffer_size > buffer_size) { | |
+ pr_err("ram_console: buffer %p, invalid size %zu, " | |
+ "non-ecc datasize %zu\n", | |
+ buffer, buffer_size, ram_console_buffer_size); | |
+ return 0; | |
+ } | |
+ | |
+ ram_console_par_buffer = buffer->data + ram_console_buffer_size; | |
+ | |
+ | |
+ /* first consecutive root is 0 | |
+ * primitive element to generate roots = 1 | |
+ */ | |
+ ram_console_rs_decoder = init_rs(ECC_SYMSIZE, ECC_POLY, 0, 1, ECC_SIZE); | |
+ if (ram_console_rs_decoder == NULL) { | |
+ printk(KERN_INFO "ram_console: init_rs failed\n"); | |
+ return 0; | |
+ } | |
+ | |
+ ram_console_corrected_bytes = 0; | |
+ ram_console_bad_blocks = 0; | |
+ | |
+ par = ram_console_par_buffer + | |
+ DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE; | |
+ | |
+ numerr = ram_console_decode_rs8(buffer, sizeof(*buffer), par); | |
+ if (numerr > 0) { | |
+ printk(KERN_INFO "ram_console: error in header, %d\n", numerr); | |
+ ram_console_corrected_bytes += numerr; | |
+ } else if (numerr < 0) { | |
+ printk(KERN_INFO | |
+ "ram_console: uncorrectable error in header\n"); | |
+ ram_console_bad_blocks++; | |
+ } | |
+#endif | |
+ | |
+ // ignore start corruption | |
+ buffer->start = 0; | |
+ | |
+ if (buffer->sig == RAM_CONSOLE_SIG) { | |
+ if (buffer->size > ram_console_buffer_size | |
+ || le32_to_cpu(buffer->start) > buffer->size) { | |
+ printk(KERN_INFO "ram_console: found existing invalid " | |
+ "buffer, size %d, start %d\n", | |
+ buffer->size, le32_to_cpu(buffer->start)); | |
+ memset(buffer, 0, buffer_size); | |
+ } | |
+ else { | |
+ printk(KERN_INFO "ram_console: found existing buffer, " | |
+ "size %d, start %d\n", | |
+ buffer->size, le32_to_cpu(buffer->start)); | |
+ ram_console_save_old(buffer, bootinfo, old_buf); | |
+ } | |
+ } else { | |
+ printk(KERN_INFO "ram_console: no valid data in buffer " | |
+ "(sig = 0x%08x)\n", buffer->sig); | |
+ memset(buffer, 0, buffer_size); | |
+ } | |
+ | |
+ buffer->sig = RAM_CONSOLE_SIG; | |
+ buffer->start = 0; | |
+ buffer->size = 0; | |
+ | |
+ register_console(&ram_console); | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE | |
+ console_verbose(); | |
+#endif | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_DEBUG_CONSOLE_SUSPENDED | |
+ atomic_notifier_chain_register(&panic_notifier_list, | |
+ &ram_panic_blk); | |
+#endif | |
+ return 0; | |
+} | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT | |
+static int __init ram_console_early_init(void) | |
+{ | |
+ return ram_console_init((struct ram_console_buffer *) | |
+ CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR, | |
+ CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE, | |
+ NULL, | |
+ ram_console_old_log_init_buffer); | |
+} | |
+#else | |
+static int ram_console_driver_probe(struct platform_device *pdev) | |
+{ | |
+ struct resource *res = pdev->resource; | |
+ size_t start; | |
+ size_t buffer_size; | |
+ void *buffer; | |
+ const char *bootinfo = NULL; | |
+ struct ram_console_platform_data *pdata = pdev->dev.platform_data; | |
+ | |
+ if (res == NULL || pdev->num_resources != 1 || | |
+ !(res->flags & IORESOURCE_MEM)) { | |
+ printk(KERN_ERR "ram_console: invalid resource, %p %d flags " | |
+ "%lx\n", res, pdev->num_resources, res ? res->flags : 0); | |
+ return -ENXIO; | |
+ } | |
+ buffer_size = resource_size(res); | |
+ start = res->start; | |
+ printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n", | |
+ start, buffer_size); | |
+ | |
+ memblock_remove(res->start, buffer_size); | |
+ | |
+ buffer = ioremap(res->start, buffer_size); | |
+ if (buffer == NULL) { | |
+ printk(KERN_ERR "ram_console: failed to map memory\n"); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ if (pdata) | |
+ bootinfo = pdata->bootinfo; | |
+ | |
+ return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */); | |
+} | |
+ | |
+static struct of_device_id ram_console_of_match[] = { | |
+ { .compatible = "android,ram-console", }, | |
+ { }, | |
+}; | |
+MODULE_DEVICE_TABLE(of, ram_console_of_match); | |
+ | |
+static struct platform_driver ram_console_driver = { | |
+ .probe = ram_console_driver_probe, | |
+ .driver = { | |
+ .name = "ram_console", | |
+ .of_match_table = of_match_ptr(ram_console_of_match), | |
+ }, | |
+}; | |
+ | |
+static int __init ram_console_module_init(void) | |
+{ | |
+ int err; | |
+ err = platform_driver_register(&ram_console_driver); | |
+ return err; | |
+} | |
+#endif | |
+ | |
+#ifndef CONFIG_PRINTK | |
+#define dmesg_restrict 0 | |
+#endif | |
+ | |
+static ssize_t ram_console_read_old(struct file *file, char __user *buf, | |
+ size_t len, loff_t *offset) | |
+{ | |
+ loff_t pos = *offset; | |
+ ssize_t count; | |
+ | |
+ if (dmesg_restrict && !capable(CAP_SYSLOG)) | |
+ return -EPERM; | |
+ | |
+ if (pos >= ram_console_old_log_size) | |
+ return 0; | |
+ | |
+ count = min(len, (size_t)(ram_console_old_log_size - pos)); | |
+ if (copy_to_user(buf, ram_console_old_log + pos, count)) | |
+ return -EFAULT; | |
+ | |
+ *offset += count; | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations ram_console_file_ops = { | |
+ .owner = THIS_MODULE, | |
+ .read = ram_console_read_old, | |
+}; | |
+ | |
+static int __init ram_console_late_init(void) | |
+{ | |
+ struct proc_dir_entry *entry; | |
+ | |
+// if (ram_console_old_log == NULL) | |
+// return 0; | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT | |
+ ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL); | |
+ if (ram_console_old_log == NULL) { | |
+ printk(KERN_ERR | |
+ "ram_console: failed to allocate buffer for old log\n"); | |
+ ram_console_old_log_size = 0; | |
+ return 0; | |
+ } | |
+ memcpy(ram_console_old_log, | |
+ ram_console_old_log_init_buffer, ram_console_old_log_size); | |
+#endif | |
+ entry = proc_create("last_kmsg", S_IFREG | S_IRUGO, NULL, | |
+ &ram_console_file_ops); | |
+ if (!entry) { | |
+ printk(KERN_ERR "ram_console: failed to create proc entry\n"); | |
+ kfree(ram_console_old_log); | |
+ ram_console_old_log = NULL; | |
+ return 0; | |
+ } | |
+ | |
+ proc_set_size(entry, ram_console_old_log_size); | |
+ return 0; | |
+} | |
+ | |
+#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT | |
+console_initcall(ram_console_early_init); | |
+#else | |
+postcore_initcall(ram_console_module_init); | |
+#endif | |
+late_initcall(ram_console_late_init); | |
+ | |
diff --git a/drivers/staging/android/ramconsole/ram_console.h b/drivers/staging/android/ramconsole/ram_console.h | |
new file mode 100644 | |
index 000000000000..9f1125c11066 | |
--- /dev/null | |
+++ b/drivers/staging/android/ramconsole/ram_console.h | |
@@ -0,0 +1,22 @@ | |
+/* | |
+ * Copyright (C) 2010 Google, Inc. | |
+ * | |
+ * This software is licensed under the terms of the GNU General Public | |
+ * License version 2, as published by the Free Software Foundation, and | |
+ * may be copied, distributed, and modified under those terms. | |
+ * | |
+ * This program is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU General Public License for more details. | |
+ * | |
+ */ | |
+ | |
+#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ | |
+#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ | |
+ | |
+struct ram_console_platform_data { | |
+ const char *bootinfo; | |
+}; | |
+ | |
+#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */ | |
-- | |
2.23.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment