diff options
Diffstat (limited to 'drivers/staging/batman-adv/log.c')
-rw-r--r-- | drivers/staging/batman-adv/log.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/staging/batman-adv/log.c b/drivers/staging/batman-adv/log.c new file mode 100644 index 00000000000..f37c7f01a9f --- /dev/null +++ b/drivers/staging/batman-adv/log.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors: + * + * Marek Lindner, Simon Wunderlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "log.h" + +#define LOG_BUF_MASK (log_buf_len-1) +#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) + +static char log_buf[LOG_BUF_LEN]; +static int log_buf_len = LOG_BUF_LEN; +static unsigned long log_start; +static unsigned long log_end; +uint8_t log_level; + +static DEFINE_SPINLOCK(logbuf_lock); + +const struct file_operations proc_log_operations = { + .open = log_open, + .release = log_release, + .read = log_read, + .write = log_write, + .poll = log_poll, +}; + +static DECLARE_WAIT_QUEUE_HEAD(log_wait); + +static void emit_log_char(char c) +{ + LOG_BUF(log_end) = c; + log_end++; + + if (log_end - log_start > log_buf_len) + log_start = log_end - log_buf_len; +} + +static int fdebug_log(char *fmt, ...) +{ + int printed_len; + char *p; + va_list args; + static char debug_log_buf[256]; + unsigned long flags; + + spin_lock_irqsave(&logbuf_lock, flags); + va_start(args, fmt); + printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, + args); + va_end(args); + + for (p = debug_log_buf; *p != 0; p++) + emit_log_char(*p); + + spin_unlock_irqrestore(&logbuf_lock, flags); + + wake_up(&log_wait); + + return 0; +} + +int debug_log(int type, char *fmt, ...) +{ + va_list args; + int retval = 0; + char tmp_log_buf[256]; + + /* only critical information get into the official kernel log */ + if (type == LOG_TYPE_CRIT) { + va_start(args, fmt); + vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); + printk(KERN_ERR "batman-adv: %s", tmp_log_buf); + va_end(args); + } + + if ((type == LOG_TYPE_CRIT) || (log_level & type)) { + va_start(args, fmt); + vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); + fdebug_log("[%10u] %s", (jiffies / HZ), tmp_log_buf); + va_end(args); + } + + return retval; +} + +int log_open(struct inode *inode, struct file *file) +{ + inc_module_count(); + return 0; +} + +int log_release(struct inode *inode, struct file *file) +{ + dec_module_count(); + return 0; +} + +ssize_t log_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + int error, i = 0; + char c; + unsigned long flags; + + if ((file->f_flags & O_NONBLOCK) && !(log_end - log_start)) + return -EAGAIN; + + if ((!buf) || (count < 0)) + return -EINVAL; + + if (count == 0) + return 0; + + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; + + error = wait_event_interruptible(log_wait, (log_start - log_end)); + + if (error) + return error; + + spin_lock_irqsave(&logbuf_lock, flags); + + while ((!error) && (log_start != log_end) && (i < count)) { + c = LOG_BUF(log_start); + + log_start++; + + spin_unlock_irqrestore(&logbuf_lock, flags); + + error = __put_user(c, buf); + + spin_lock_irqsave(&logbuf_lock, flags); + + buf++; + i++; + + } + + spin_unlock_irqrestore(&logbuf_lock, flags); + + if (!error) + return i; + + return error; +} + +ssize_t log_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + return count; +} + +unsigned int log_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &log_wait, wait); + + if (log_end - log_start) + return POLLIN | POLLRDNORM; + + return 0; +} |