- u-boot参数 console = ttySAC0
UBOOT传入console=ttySAC0 console=tty1
__setup("console=", console_setup);
- console_setup
add_preferred_console(name, idx, options);
- add_preferred_console
c = &console_cmdline[i];
memcpy(c->name, name, sizeof(c->name));
console_cmdline在哪里调用
- register_console里使用
linux-2.6.22\trunk\drivers\serial\s3c2410.c
register_console(&s3c24xx_serial_console);
printk
r = vprintk(fmt, args);
void release_console_sem(void)
call_console_drivers(_con_start, _log_end);
_call_console_drivers
__call_console_drivers
con->write(con, &LOG_BUF(start), end - start);
打印有级别,默认的打印级别是4,可以用dmesg命令将log_buf的数据打印出来
printk("abc");
printk(KERNEL_WARING"abc");
打印级别的相关解释
# cat proc/sys/kernel/printk
7 4 1 7
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
因此修改第一个数字 7,就可以控制printk的打印信息开放或者关闭,将其改的特别小,就可以屏蔽所有打印,将其改的特别大,就能放开所有打印
u-boot可以设置loglevel=xx来更改参数,这样在启动内核时不用查看内核的打印信息,加快启动速度,以下是两种方法
1..---------------------------------------------
static int __init loglevel(char *str)
{
get_option(&str, &console_loglevel);
return 1;
}
__setup("loglevel=", loglevel);
2..------------------------------------------------
__setup("debug", debug_kernel);
__setup("quiet", quiet_kernel);
打印到proc虚拟文件
printk的信息一份存在缓冲区里(其实也是一个文件),一份打印到串口
# ls -l /proc/kmsg
-r-------- 1 0 0 0 Jan 1 00:11 /proc/kmsg
#
proc是一个虚拟文件系统
# cat /etc/init.d/rcS
#!/bin/sh
ifconfig eth0 192.168.0.90
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
if [ ! -e /etc/pointercal ]
then
/bin/ts_cal.sh
fi
/bin/qpe.sh &
#
mount -a挂接以下文件中所有的文件系统
# cat /etc/fstab
# device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
#
怎么把printk信息抽出来
仿照 my log_buf,/proc/mymsg
步骤一:先创建设备文件
static int __init mymsg_init(void)
{
myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root);
return 0;
}
static void __exit mymsg_exit(void)
{
remove_proc_entry("mymsg", &proc_root);
}
- cat新创建的文件时,会调用myentry->proc_fops里的read函数读取数据,实现环形缓冲区的操作函数
写:buf[w] = val; w = w + 1
读:val=buf[r], r = r + 1
满:先不写数据,判断一下下一次写的位置是不是等于读
- 缓冲区是否已经空了,如果读指针==写指针
static int mylogbuf_isempty()
{
return (mylogbuf_read == mylogbuf_read);
}
完全版的代码,export_sympol之后,就可以在别的文件里使用myprintk函数打印了,然后
cat /proc/mymsg就可以查看使用myprintk打印的信息
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/times.h>
#include <linux/profile.h>
#include <linux/utsname.h>
#include <linux/blkdev.h>
#include <linux/hugetlb.h>
#include <linux/jiffies.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/tlb.h>
#include <asm/div64.h>
#define LEN 7
static int mylogbuf_read;
static int mylogbuf_read_buffer;
static DECLARE_WAIT_QUEUE_HEAD(mywaitq);
static int mylogbuf_write;
static char my_logbuf[LEN] = {0};
static char tmp_buf[LEN] = {0};
static int myentry_open(struct inode *inode, struct file *file)
{
mylogbuf_read_buffer = mylogbuf_read;
return 0;
}
static int mylogbuf_isempty(void)
{
return (mylogbuf_read_buffer == mylogbuf_write);
}
static int mylogbuf_isfull(void)
{
return (((mylogbuf_write + 1) % LEN ) == mylogbuf_read);
}
static void mylogbuf_putc(unsigned char c)
{
if (mylogbuf_isfull()) {
/*
满了的话,舍弃掉后面的一个数据,如果不舍弃,写的话,读指针会等于写指针,误判缓冲区为空
所以将读指针往后挪一个,舍弃掉这个数据.
*/
mylogbuf_read = (mylogbuf_read + 1) % LEN;
}
my_logbuf[mylogbuf_write] = c;
mylogbuf_write = (mylogbuf_write + 1) % LEN;
printk("func:%s, line:%d, mylogbuf_write:%d, mylogbuf_read:%d\n",
__func__, __LINE__, mylogbuf_write, mylogbuf_read);
wake_up(&mywaitq);
}
static int mylogbuf_getc(unsigned char *p)
{
if (mylogbuf_isempty())
{
return 0;
}
*p = my_logbuf[mylogbuf_read];
printk("func:%s, line:%d, mylogbuf_read:%d, read_buffer:%d\n",
__func__, __LINE__, mylogbuf_read, mylogbuf_read_buffer);
mylogbuf_read_buffer = (mylogbuf_read_buffer + 1) % LEN;
return 1;
}
int myprintk(const char *fmt, ...)
{
va_list args;
int i, j;
va_start(args, fmt);
/*直接打印进去logbuf不会有读写指针*/
i=vsnprintf(tmp_buf, INT_MAX, fmt, args);
va_end(args);
for (j = 0; j < i; j++) {
mylogbuf_putc(tmp_buf[j]);
}
return i;
}
static struct proc_dir_entry *myentry = NULL;
static ssize_t myentry_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
unsigned char c;
int i = 0;
int error;
if ((file->f_flags & O_NONBLOCK) && mylogbuf_isempty()) {
return -EAGAIN;
}
error = wait_event_interruptible(mywaitq, !mylogbuf_isempty());//contion等于假的时候会休眠
printk("func:%s, line:%d, size:%d\n", __func__, __LINE__, size);
while (!error && mylogbuf_getc(&c) &&(i < size)) {
error = __put_user(c, buf);
buf++;
i++;
}
if (!error)
error = i;
return error;
}
static struct file_operations myentry_proc_fops = {
.open = myentry_open,
.read = myentry_read,
};
static int __init mymsg_init(void)
{
myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root);
if (myentry)
myentry->proc_fops = &myentry_proc_fops;
return 0;
}
static void __exit mymsg_exit(void)
{
remove_proc_entry("mymsg", &proc_root);
}
EXPORT_SYMBOL(myprintk);
module_init(mymsg_init);
module_exit(mymsg_exit);
MODULE_LICENSE("GPL");
- 这里附上我的自己的一些分析
每次读的时候,将mylogbuf_read_buffer更改为mylogbuf_read(实验后发现这样做不行,会不停大打印,见后面的分析)
每次 mylogbuf_getc 读取log_buf的时候,不能用mylogbuf_read,他变了的话(会一直读到和log_write指针相等),下次在获取数据就没有数据了.
一次的读取过程中总是读到log_buf里面没有数据为止,所以mylogbuf_isempty里面也要用read_buffer,有没有写满仍然需要使用buf_read来标志.
因为cat命令会循环执行 myentry_read 函数,所以不能这里面使用
mylogbuf_read_buffer = mylogbuf_read;
这样判断log_buf是不是空的时候,每次都不为空,尽管在mylogbuf_getc都将mylogbuf_read_buffer加1,第一次读取完,判断log为空成立时,又跑去执行myentry_read,所以赋值需要选在只执行一次的函数当中,比如open函数
mylogbuf_read_buffer = (mylogbuf_read_buffer + 1) % LEN;
如果我将LEN的长度缩小到7会怎么样
myprintk("11111111\n");
usbmouse.c总共打印9个字符,LEN = 7
0 1 2 3 4 5 6
log_write等于6的时候,这个时候程序已经判断环形缓冲区满了buf_read一开始为0,舍弃掉0数据,buf_read = 1,6号内存也已经将数据1填进去了.此时buf_write = 0.这时总共写了7个数据,在写两个数据之后,就会变成buf_write = 2(因为肯定写到1号内存,w然后加1),read_buf = 3,此时执行cat会发生什么情况呢?
网友评论