[LOG] fix ordering of overall logs including kernel
authorChristophe Guerard <christophe.guerard@intel.com>
Mon, 19 Dec 2011 16:37:36 +0000 (17:37 +0100)
committerbuildbot <buildbot@intel.com>
Fri, 27 Jan 2012 12:14:19 +0000 (04:14 -0800)
BZ: 11070

To be able to flush the kernel logs into logcat buffer
and having the correct timestamp of any logs, a new
console logk0 is created to redirect the kernel logs into
a new logcat buffer named kernel. This implementation
also provides also the ability to have multiple instance
of logcat -b kernel

The new kernel log buffer fixes the drawback of logcat -k.
which are:

1/ The timestamp of kernel logs are added when these
logs are flushed into the file system (for example) and
not when the kernel log is created leading to have logs
in an incorrect order compared to the other OS logs

2/ If there are multiple instances of logcat -k, some
instances do not have the complete kernel logs since each
reading operation of /proc/kmsg changes the dmesg pointer

For legacy usage of logcat, logcat -k still reads /proc/kmsg
To benefit of the new buffer, use logcat -b kernel

This patch provides also some changes to optimize logs sent
to PTI (Parallel Trace Interface) without buffering.
Any log (whatever the buffer) is directly sent from the driver.

Change-Id: I80a79c0c1a4519ca5c78b9a960f24ce81f1f919b
Signed-off-by: Christophe Guerard <christophe.guerard@intel.com>
Reviewed-on: http://android.intel.com:8080/29147
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/configs/i386_mfld_defconfig
drivers/misc/pti.c
drivers/staging/android/Kconfig
drivers/staging/android/Makefile
drivers/staging/android/logger.c
drivers/staging/android/logger.h
drivers/staging/android/logger_pti.c [new file with mode: 0644]
drivers/staging/android/logger_pti.h [new file with mode: 0644]
include/linux/pti.h

index 1dab549..21b5f0d 100644 (file)
@@ -2317,6 +2317,7 @@ CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_LOGGER_PTI=y
 # CONFIG_ANDROID_RAM_CONSOLE is not set
 CONFIG_ANDROID_TIMED_OUTPUT=y
 # CONFIG_ANDROID_TIMED_GPIO is not set
index fa58d1a..e0b0d36 100644 (file)
@@ -159,7 +159,8 @@ static void pti_write_to_aperture(struct pti_masterchannel *mc,
  *  in 32 byte chunks.
  */
 
-static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc)
+static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
+                                       const char *thread_name)
 {
        struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
                                              .channel = 0};
@@ -171,10 +172,12 @@ static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc)
         * we only need to be as large as what 'comm' in that
         * structure is.
         */
-       char comm[TASK_COMM_LEN];
 
+       char comm[TASK_COMM_LEN];
        /* task information */
-       if (in_irq())
+       if (thread_name)
+               strncpy(comm, thread_name, sizeof(comm));
+       else if (in_irq())
                strncpy(comm, "hardirq", sizeof(comm));
        else if (in_softirq())
                strncpy(comm, "softirq", sizeof(comm));
@@ -210,7 +213,7 @@ static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,
                                                const unsigned char *buf,
                                                int len)
 {
-       pti_control_frame_built_and_sent(mc);
+       pti_control_frame_built_and_sent(mc, NULL);
        pti_write_to_aperture(mc, (u8 *)buf, len);
 }
 
@@ -231,7 +234,8 @@ static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,
  * channel id. The bit is one if the id is taken and 0 if free. For
  * every master there are 128 channel id's.
  */
-static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)
+static struct pti_masterchannel *get_id(u8 *id_array, int max_ids,
+                                       int base_id, const char *thread_name)
 {
        struct pti_masterchannel *mc;
        int i, j, mask;
@@ -261,13 +265,13 @@ static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)
        mc->master  = base_id;
        mc->channel = ((i & 0xf)<<3) + j;
        /* write new master Id / channel Id allocation to channel control */
-       pti_control_frame_built_and_sent(mc);
+       pti_control_frame_built_and_sent(mc, thread_name);
        return mc;
 }
 
 /*
  * The following three functions:
- * pti_request_mastercahannel(), mipi_release_masterchannel()
+ * pti_request_masterchannel(), mipi_release_masterchannel()
  * and pti_writedata() are an API for other kernel drivers to
  * access PTI.
  */
@@ -288,7 +292,7 @@ static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)
  *     pti_masterchannel struct
  *     0 for error
  */
-struct pti_masterchannel *pti_request_masterchannel(u8 type)
+struct pti_masterchannel *pti_request_masterchannel(u8 type, const char *name)
 {
        struct pti_masterchannel *mc;
 
@@ -297,15 +301,16 @@ struct pti_masterchannel *pti_request_masterchannel(u8 type)
        switch (type) {
 
        case 0:
-               mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID);
+               mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID, name);
                break;
 
        case 1:
-               mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID);
+               mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID, name);
                break;
 
        case 2:
-               mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, MODEM_BASE_ID);
+               mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS,
+                                               MODEM_BASE_ID, name);
                break;
        default:
                mc = NULL;
@@ -476,9 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
                        return -ENOMEM;
 
                if (idx == PTITTY_MINOR_START)
-                       pti_tty_data->mc = pti_request_masterchannel(0);
+                       pti_tty_data->mc = pti_request_masterchannel(0, NULL);
                else
-                       pti_tty_data->mc = pti_request_masterchannel(2);
+                       pti_tty_data->mc = pti_request_masterchannel(2, NULL);
 
                if (pti_tty_data->mc == NULL) {
                        kfree(pti_tty_data);
@@ -567,7 +572,7 @@ static int pti_char_open(struct inode *inode, struct file *filp)
         * before assigning the value to filp->private_data.
         * Slightly easier to debug if this driver needs debugging.
         */
-       mc = pti_request_masterchannel(0);
+       mc = pti_request_masterchannel(0, NULL);
        if (mc == NULL)
                return -ENOMEM;
        filp->private_data = mc;
index 2471949..3af8a15 100644 (file)
@@ -16,6 +16,10 @@ config ANDROID_LOGGER
        tristate "Android log driver"
        default n
 
+config ANDROID_LOGGER_PTI
+       tristate "Android log driber on PTI"
+       default n
+
 config ANDROID_RAM_CONSOLE
        bool "Android RAM buffer console"
        default n
index 8e057e6..1737829 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_ANDROID_BINDER_IPC)       += binder.o
 obj-$(CONFIG_ANDROID_LOGGER)           += logger.o
+obj-$(CONFIG_ANDROID_LOGGER_PTI)       += logger_pti.o
 obj-$(CONFIG_ANDROID_RAM_CONSOLE)      += ram_console.o
 obj-$(CONFIG_ANDROID_TIMED_OUTPUT)     += timed_output.o
 obj-$(CONFIG_ANDROID_TIMED_GPIO)       += timed_gpio.o
index 0f45d3c..6f9b00a 100755 (executable)
  * GNU General Public License for more details.
  */
 
+#include <linux/console.h>
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include "logger.h"
-
 #include <asm/ioctls.h>
 
+#include "logger.h"
+#include "logger_pti.h"
+
+static DEFINE_SPINLOCK(log_lock);
+static struct work_struct write_console_wq;
 /*
  * file_get_log - Given a file structure, return the associated log
  *
@@ -58,7 +61,7 @@ static inline struct logger_log *file_get_log(struct file *file)
  *
  * Caller needs to hold log->mutex.
  */
-static __u32 get_entry_len(struct logger_log *log, size_t off)
+__u32 get_entry_len(struct logger_log *log, size_t off)
 {
        __u16 val;
 
@@ -110,6 +113,37 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
 }
 
 /*
+ * do_read_log - reads exactly 'count' bytes from 'log' into the
+ * kernel buffer 'buf'.
+ *
+ * Caller must hold log->mutex.
+ */
+void do_read_log(struct logger_log *log,
+                       struct logger_reader *reader,
+                       char *buf,
+                       size_t count)
+{
+       size_t len;
+
+       /*
+        * We read from the log in two disjoint operations. First, we read from
+        * the current read head offset up to 'count' bytes or to the end of
+        * the log, whichever comes first.
+        */
+       len = min(count, log->size - reader->r_off);
+       memcpy(buf, log->buffer + reader->r_off, len);
+
+       /*
+        * Second, we read any remaining bytes, starting back at the head of
+        * the log.
+        */
+       if (count != len)
+               memcpy(buf + len, log->buffer, count - len);
+
+       reader->r_off = logger_offset(reader->r_off + count);
+}
+
+/*
  * logger_read - our log's read() method
  *
  * Behavior:
@@ -295,7 +329,7 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        size_t orig = log->w_off;
        struct logger_entry header;
        struct timespec now;
-       ssize_t ret = 0;
+       ssize_t len, ret = 0;
 
        now = current_kernel_time();
 
@@ -303,7 +337,8 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        header.tid = current->pid;
        header.sec = now.tv_sec;
        header.nsec = now.tv_nsec;
-       header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
+       header.len = min_t(size_t, iocb->ki_left,
+                                       LOGGER_ENTRY_MAX_PAYLOAD);
 
        /* null writes succeed, return zero */
        if (unlikely(!header.len))
@@ -322,7 +357,6 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        do_write_log(log, &header, sizeof(struct logger_entry));
 
        while (nr_segs-- > 0) {
-               size_t len;
                ssize_t nr;
 
                /* figure out how much of this vector we can keep */
@@ -340,6 +374,8 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
                ret += nr;
        }
 
+       log_write_to_pti(log);
+
        mutex_unlock(&log->mutex);
 
        /* wake up any blocked readers */
@@ -348,8 +384,6 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        return ret;
 }
 
-static struct logger_log *get_log_from_minor(int);
-
 /*
  * logger_open - the log's open() file operation
  *
@@ -522,18 +556,121 @@ static struct logger_log VAR = { \
        .size = SIZE, \
 };
 
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
 DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
+DEFINE_LOGGER_DEVICE(log_kernel, LOGGER_LOG_KERNEL, 256*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
+
+DEFINE_LOGGER_DEVICE(log_kernel_bottom, LOGGER_LOG_KERNEL_BOT, 64*1024)
 
 static struct logger_log *log_list[] = {       \
        &log_main,      \
        &log_events,    \
        &log_radio,     \
+       &log_kernel,    \
        &log_system,    \
 };
 
+static void flush_to_bottom_log(struct logger_log *log,
+                                       const char *buf, unsigned int count)
+{
+       struct logger_entry header;
+       char extendedtag[8] = "\4KERNEL";
+       struct timespec now;
+       unsigned long flags;
+
+       now = current_kernel_time();
+
+       header.pid = pid_nr(task_pid(current));
+       header.tid = current->tgid;
+       header.sec = now.tv_sec;
+       header.nsec = now.tv_nsec;
+
+       /* length is computed like this:
+        * 1 byte for the log priority (harcoded to 4 meaning INFO)
+        * 6 bytes for the tag string (harcoded to KERNEL)
+        * 1 byte added at the end of the tag required by logcat
+        * the length of the buf added into the kernel log buffer
+        * 1 byte added at the end of the buf required by logcat
+        */
+       header.len = min_t(size_t, sizeof(extendedtag) + count + 1,
+                                       LOGGER_ENTRY_MAX_PAYLOAD);
+
+       /* null writes succeed, return zero */
+       if (unlikely(!header.len))
+               return;
+
+       spin_lock_irqsave(&log_lock, flags);
+
+       fix_up_readers(log, sizeof(struct logger_entry) + header.len);
+
+       do_write_log(log, &header, sizeof(struct logger_entry));
+       do_write_log(log, &extendedtag, sizeof(extendedtag));
+       do_write_log(log, buf, header.len - (sizeof(extendedtag)) - 1);
+
+       /* the write offset is updated to add the final extra byte */
+       log->w_off = logger_offset(log->w_off + 1);
+       spin_unlock_irqrestore(&log_lock, flags);
+};
+
+
+/*
+ * update_log_from_bottom - copy bottom log buffer into a log buffer
+ */
+static void update_log_from_bottom(struct logger_log *log_dst,
+                                       struct logger_log *log)
+{
+       struct logger_reader *reader;
+       size_t len, ret;
+       unsigned long flags;
+
+       mutex_lock(&log_dst->mutex);
+       spin_lock_irqsave(&log_lock, flags);
+
+       list_for_each_entry(reader, &log->readers, list)
+               while (log->w_off != reader->r_off) {
+
+                       ret = get_entry_len(log, reader->r_off);
+
+                       fix_up_readers(log_dst, ret);
+
+                       /*
+                        * We read from the log in two disjoint operations.
+                        * First, we read from the current read head offset
+                        * up to 'count' bytes or to the end of the log,
+                        * whichever comes first.
+                        */
+                       len = min(ret, log->size - reader->r_off);
+                       do_write_log(log_dst, log->buffer + reader->r_off, len);
+
+                       /*
+                        * Second, we read any remaining bytes, starting back at
+                        * the head of the log.
+                        */
+                       if (ret != len)
+                               do_write_log(log_dst, log->buffer, ret - len);
+
+                       reader->r_off = logger_offset(reader->r_off + ret);
+               }
+       spin_unlock_irqrestore(&log_lock, flags);
+       mutex_unlock(&log_dst->mutex);
+
+       /* wake up any blocked readers */
+       wake_up_interruptible(&log_dst->wq);
+}
+
+/*
+ * write_console - a write method for kernel logs
+ */
+static void write_console(struct work_struct *work)
+{
+       struct logger_log *log_bottom = &log_kernel_bottom;
+       struct logger_log *log = &log_kernel;
+
+       update_log_from_bottom(log, log_bottom);
+}
+
 struct logger_log *get_log_from_minor(int minor)
 {
        int i;
@@ -549,7 +686,26 @@ struct logger_log **get_log_list(void)
        return log_list;
 }
 
-static int __init init_log(struct logger_log *log)
+static int init_log_kernel_bottom(void)
+{
+       struct logger_log *log = &log_kernel_bottom;
+       struct logger_reader *reader;
+
+       reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
+       if (!reader)
+               return -ENOMEM;
+
+       reader->log = log;
+       INIT_LIST_HEAD(&reader->list);
+
+       mutex_lock(&log->mutex);
+       reader->r_off = log->head;
+       list_add_tail(&reader->list, &log->readers);
+       mutex_unlock(&log->mutex);
+       return 0;
+}
+
+static int init_log(struct logger_log *log)
 {
        int ret;
 
@@ -574,9 +730,48 @@ static int __init logger_init(void)
                ret = init_log(log_list[i]);
                if (unlikely(ret))
                        goto out;
+               ret = init_pti(log_list[i]);
+               if (unlikely(ret))
+                       goto out;
        }
 
+       ret = init_log_kernel_bottom();
+       if (unlikely(ret))
+               goto out;
+
 out:
        return ret;
 }
 device_initcall(logger_init);
+
+static void
+logger_console_write(struct console *console, const char *s, unsigned int count)
+{
+       struct logger_log *log = &log_kernel_bottom;
+       struct logger_log *log_dst = &log_kernel;
+
+       flush_to_bottom_log(log, s, count);
+       log_kernel_write_to_pti(log_dst, s, count);
+
+       if (unlikely(!keventd_up()))
+               return;
+       schedule_work(&write_console_wq);
+}
+
+static struct console logger_console = {
+       .name   = "logk",
+       .write  = logger_console_write,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+static int __init logger_console_init(void)
+{
+       INIT_WORK(&write_console_wq, write_console);
+
+       printk(KERN_INFO "register logcat console\n");
+       register_console(&logger_console);
+       return 0;
+}
+
+console_initcall(logger_console_init);
index 28b07d4..218e91c 100755 (executable)
@@ -37,6 +37,10 @@ struct logger_log {
        size_t                  w_off;  /* current write head offset */
        size_t                  head;   /* new readers start here */
        size_t                  size;   /* size of the log */
+#ifdef CONFIG_ANDROID_LOGGER_PTI
+       bool                    ptienable;
+       struct pti_reader       *pti_reader;
+#endif
 };
 
 /*
@@ -61,6 +65,12 @@ struct logger_entry {
        char            msg[0]; /* the entry's payload */
 };
 
+void do_read_log(struct logger_log *log,
+                       struct logger_reader *reader,
+                       char *buf,
+                       size_t count);
+__u32 get_entry_len(struct logger_log *log, size_t off);
+struct logger_log *get_log_from_minor(int minor);
 struct logger_log **get_log_list(void);
 
 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
@@ -69,9 +79,11 @@ struct logger_log **get_log_list(void);
 #define LOGGER_LOG_RADIO       "log_radio"     /* radio-related messages */
 #define LOGGER_LOG_EVENTS      "log_events"    /* system/hardware events */
 #define LOGGER_LOG_SYSTEM      "log_system"    /* system/framework messages */
+#define LOGGER_LOG_KERNEL      "log_kernel"    /* kernel */
+#define LOGGER_LOG_KERNEL_BOT  "log_kernel_bottom" /* kernel bottom */
 #define LOGGER_LOG_MAIN                "log_main"      /* everything else */
 
-#define LOGGER_LIST_SIZE 4
+#define LOGGER_LIST_SIZE 5
 
 #define LOGGER_ENTRY_MAX_LEN           (4*1024)
 #define LOGGER_ENTRY_MAX_PAYLOAD       \
diff --git a/drivers/staging/android/logger_pti.c b/drivers/staging/android/logger_pti.c
new file mode 100644 (file)
index 0000000..54b6373
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * logger_pti.c - logger messages redirection to PTI
+ *
+ *  Copyright (C) Intel 2010
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To active logger to PTI messages, configure 'out' parameter
+ * of 'logger_pti' module in sysfs with one or more values
+ *  # echo "main,system" > /sys/module/logger_pti/parameters/out
+ *
+ * To active logger to PTI messages from boot, add this
+ * commandline parameter to the boot commandline
+ *  logger_pti.out=main,system
+ *
+ * Possible log buffers are : main, system, radio, events, kernel
+ * See logger.h if others.
+ */
+
+#include <linux/slab.h>
+#include "logger_pti.h"
+
+/*
+ * init_pti - initialize the pti members with the 'log' passed in
+ * argument
+ */
+int init_pti(struct logger_log *log)
+{
+       struct pti_reader *pti_reader;
+       struct logger_reader *reader;
+       int ret = 0;
+
+       pti_reader = kmalloc(sizeof(struct pti_reader), GFP_KERNEL);
+
+       if (!pti_reader) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
+
+       if (!reader) {
+               kfree(pti_reader);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* entry init */
+       pti_reader->entry = kmalloc(sizeof(struct queued_entry), GFP_KERNEL);
+       if (!pti_reader->entry) {
+               kfree(pti_reader);
+               kfree(reader);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * masterchannel init
+        * request OS channel type : 1, see drivers/misc/pti.c
+        */
+       pti_reader->mc = pti_request_masterchannel(1, log->misc.name);
+       if (!pti_reader->mc) {
+               kfree(pti_reader);
+               kfree(reader);
+               ret = -ENODEV;
+               goto out;
+       }
+
+       pti_reader->reader = reader;
+       reader->r_off = log->w_off;
+       mutex_lock(&log->mutex);
+       log->pti_reader = pti_reader;
+       mutex_unlock(&log->mutex);
+
+       pr_info("logger_pti: %s, mc : %d %d\n", log->misc.name,
+                       pti_reader->mc->master, pti_reader->mc->channel);
+
+out:
+       if (unlikely(ret)) {
+               log->pti_reader = NULL;
+               pr_err("logger_pti: failed to init %s\n",
+                      log->misc.name);
+       }
+       return ret;
+}
+
+/*
+ * log_kernel_write_to_pti - write a kernel log to the pti master/channel
+ * Can be called in any context
+ *
+ */
+void log_kernel_write_to_pti(struct logger_log *log,
+                               const char *buf, size_t count)
+{
+       struct pti_reader *pti_reader = log->pti_reader;
+
+       /* kernel logs are not buffered */
+       if (log->ptienable && pti_reader && pti_reader->mc)
+               pti_writedata(pti_reader->mc, (unsigned char *) buf, count);
+}
+
+/*
+ * log_write_to_pti - write a buffer to the pti master/channel
+ * Can be called in any context
+ *
+ */
+void log_write_to_pti(struct logger_log *log)
+{
+       struct pti_reader *pti_reader;
+       struct logger_reader *reader;
+       size_t count;
+
+       /* other logs are buffered to add the tag from the header*/
+       pti_reader = log->pti_reader;
+       if (unlikely(!pti_reader))
+               return;
+
+       reader = pti_reader->reader;
+
+       /* get the size of the next entry */
+       count = get_entry_len(log, reader->r_off);
+
+       if (log->ptienable) {
+               /* copy exactly one entry from the log */
+               do_read_log(log, reader, pti_reader->entry->buf, count);
+
+               pti_writedata(pti_reader->mc,
+                               pti_reader->entry->entry.msg,
+                               pti_reader->entry->entry.len);
+       } else {
+               reader->r_off = logger_offset(reader->r_off + count);
+       }
+}
+
+/*
+ * set_out - 'out' parameter set function from 'logger_pti' module
+ *
+ * called when writing to 'out' parameter from 'logger_pti' module in sysfs
+ */
+static int set_out(const char *val, struct kernel_param *kp)
+{
+       int i;
+       const char *log_name;
+       struct logger_log *log;
+       struct logger_log **log_list;
+
+       log_list = get_log_list();
+       for (i = 0; i < LOGGER_LIST_SIZE; i++) {
+               log = log_list[i];
+               log_name = log->misc.name;
+               /* remove "log_" in the log_name string */
+               log_name += 4;
+               if (strstr(val, log_name))
+                       log->ptienable = true;
+               else
+                       log->ptienable = false;
+       }
+
+       return 0;
+}
+
+/*
+ * get_out - 'out' parameter get function from 'logger_pti' module
+ *
+ * called when reading 'out' parameter from 'logger_pti' module in sysfs
+ */
+static int get_out(char *buffer, struct kernel_param *kp)
+{
+       int i;
+       const char *log_name;
+       const char *k = ",";
+       struct logger_log *log;
+       struct logger_log **log_list;
+
+       log_list = get_log_list();
+       for (i = 0; i < LOGGER_LIST_SIZE; i++) {
+               if (log_list[i]->ptienable) {
+                       log = log_list[i];
+                       log_name = log->misc.name;
+                       /* remove "log_" in the log_name string */
+                       log_name += 4;
+                       strcat(buffer, log_name);
+                       strcat(buffer, k);
+               }
+       }
+       buffer[strlen(buffer)-1] = '\0';
+
+       return strlen(buffer);
+}
+
+module_param_call(out, set_out, get_out, NULL, 0644);
+MODULE_PARM_DESC(out, "configure logger to pti [main|events|radio|system|kernel]");
+
diff --git a/drivers/staging/android/logger_pti.h b/drivers/staging/android/logger_pti.h
new file mode 100644 (file)
index 0000000..959e7db
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * logger_pti.h - logger messages redirection to PTI
+ *
+ *  Copyright (C) Intel 2010
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To active logger to PTI messages, configure 'out' parameter
+ * of 'logger_pti' module in sysfs with one or more values
+ *  # echo "main,system" > /sys/module/logger_pti/parameters/out
+ *
+ * To active logger to PTI messages from boot, add this
+ * commandline parameter to the boot commandline
+ *  logger_pti.out=main,system
+ *
+ * Possible log buffers are : main, system, radio, events
+ * See logger.h if others.
+ */
+
+#ifndef _LINUX_LOGGER_PTI_H
+#define _LINUX_LOGGER_PTI_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pti.h>
+#include <linux/string.h>
+#include "logger.h"
+
+#ifdef CONFIG_ANDROID_LOGGER_PTI
+/*
+ * struct queued_entry - a logger entry with maximum space allocated
+ *
+ * This structure is necessary to retrieve a full logger entry
+ */
+struct queued_entry {
+       union {
+               unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1]
+                       __attribute__((aligned(4)));
+               struct logger_entry entry __attribute__((aligned(4)));
+       };
+};
+
+/*
+ * struct pti_reader - a specific reader associate to a pti master/channel
+ *
+ * This structure lives from module insertion until module removal, so it does
+ * not need additional reference counting.
+ */
+struct pti_reader {
+       struct  logger_reader *reader;
+       struct  pti_masterchannel *mc;
+       struct  queued_entry *entry;
+};
+
+extern int init_pti(struct logger_log *log);
+extern void log_write_to_pti(struct logger_log *log);
+extern void log_kernel_write_to_pti(struct logger_log *log,
+                                       const char *buf, size_t count);
+#else
+static inline int init_pti(struct logger_log *log) { return 0; }
+static inline int log_kernel_write_to_pti(struct logger_log *log,
+                               const char *buf, size_t count) { return 0; }
+static inline int log_write_to_pti(struct logger_log *log) { return 0; }
+#endif
+
+#endif /* _LINUX_LOGGER_PTI_H */
index 81af667..0c21c48 100644 (file)
@@ -36,7 +36,7 @@ struct pti_masterchannel {
 
 /* the following functions are defined in misc/pti.c */
 void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count);
-struct pti_masterchannel *pti_request_masterchannel(u8 type);
+struct pti_masterchannel *pti_request_masterchannel(u8 type, const char *name);
 void pti_release_masterchannel(struct pti_masterchannel *mc);
 
 #endif /*PTI_H_*/