放开linux内核打印,设备驱动程序调试printk讲解和使用,打印到proc虚拟文件

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");

打印级别的相关解释

e88b62a95aa0

# cat proc/sys/kernel/printk

7 4 1 7

e88b62a95aa0

#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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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会发生什么情况呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值