Linux内核动态调试信息的打开pr_debug(基于按键驱动,全过程记录)
2011-12-18 15:15:25
如在driver/char目录下的Kconfig中添加如下代码:
- config MY_KEY //该部分配置驱动是否编译进内核/编译为内核模块/不编译
- tristate "Key driver for FriendlyARM Tiny6410 development boards"
- depends on CPU_S3C6410
- default m
- help
- this is buttons driver, add by Jason
-
- config MY_KEY_DEBUG //该部分是调试时添加,配置是否打印调试信息,如果不需要可不添加
- bool "Support MY_KEY DEBUG"
- help
- this is DEBUG function, add by Jason
- depends on MY_KEY
【2】配置Makefile,添加编译支持驱动模块 EXTRA_CFLAGS += -DDEBUG
如在driver/char目录下的Makefile中添加如下代码:
- obj-$(CONFIG_MY_KEY) += my_key.o
- ifeq ($(CONFIG_MY_KEY_DEBUG), y) //判断是否调试驱动
- EXTRA_CFLAGS += -DDEBUG
- endif
【3】配置内核,使支持动态调试
Kernel hacking --->
[*] Tracers --->
[*] Trace max stack
Kernel hacking --->
[*] Enable dynamic printk() support
【4】如果驱动选择的是动态加载,则重新编译模块(make modules);否则,重新编译内核(make uImage -j4)。
【5】如果驱动选择的是动态加载,则传*.ko文件到板子的文件系统;否则,重烧内核。然后改变控制台debug消息显示级别7-->8,可以打印printk(DEBUG ...)信息。
【6】驱动源码:蓝绿色部分是pr_debug,有了这个,就可以在配置内核时通过选择或取消DEBUG选项,控制调试信息的开和关;绿色部分是在代码里通过修改DRIVER_DEBUG的值,控制调试信息的开和关,相比较,很显然是pr_debug比较方便。
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/cdev.h>
- #include <linux/types.h>
- #include <linux/device.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/poll.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include <mach/map.h>
- #include <mach/regs-clock.h>
- #include <mach/regs-gpio.h>
- #include <mach/irqs.h>
- #include <mach/gpio-bank-n.h>
- #include <plat/gpio-cfg.h>
-
- #define DRIVER_DEBUG 1
- #define DEVICE_NAME "mykey"
-
- /* parameters */
-
- static int major;
- static int minor = 0;
- static int nr_devs = 1; /* number of devices */
-
- static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
-
- static struct fasync_struct *button_async;
-
- /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
- static volatile int ev_press = 0;
-
- /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
- /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
- struct pin_desc{
- unsigned int pin_num;
- unsigned int key_val;
- };
-
- struct pin_desc pins_desc[4] = {
- {0x00, 0x01},
- {0x01, 0x02},
- {0x02, 0x03},
- {0x03, 0x04},
- };
-
- static unsigned char key_val;
-
- struct class *mykey_class;
-
- struct mykey_dev {
- struct cdev cdev; /* char device structure */
- }*mykey_devp; /* device structure pointer */
-
- /*
- * 确定按键值
- */
- static irqreturn_t buttons_irq(int irq, void *dev_id, struct pt_regs *regs)
- {
- struct pin_desc * pindesc = (struct pin_desc *)dev_id;
- unsigned int pinval;
-
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- pinval = (~readl(S3C64XX_GPNDAT)) & (1 << pindesc->pin_num);
-
- if (pinval) //one of the key is pressed
- key_val = pindesc->key_val;
- else
- key_val = 0x80 | pindesc->key_val;
-
- ev_press = 1; /* 表示中断发生了 */
-
- wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
-
- kill_fasync (&button_async, SIGIO, POLL_IN);
-
- return IRQ_RETVAL(IRQ_HANDLED);
- }
-
-
- /*
- * The fasync function of device driver.
- */
- static int mykey_fasync (int fd, struct file *filp, int on)
- {
- pr_debug("driver: mykey_fasync!\n");
-
- return fasync_helper (fd, filp, on, &button_async);
- }
-
-
- /*
- * The open function of device driver.
- */
-
- static int mykey_open(struct inode *inode, struct file *filp)
- {
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- request_irq(IRQ_EINT(0), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S1", &pins_desc[0]);
- request_irq(IRQ_EINT(1), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[1]);
- request_irq(IRQ_EINT(2), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[2]);
- request_irq(IRQ_EINT(3), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[3]);
-
- return 0;
- }
-
-
- /*
- * The release function of device driver.
- */
- static int mykey_release(struct inode *inode, struct file *filp)
- {
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- free_irq(IRQ_EINT(0), &pins_desc[0]);
- free_irq(IRQ_EINT(1), &pins_desc[1]);
- free_irq(IRQ_EINT(2), &pins_desc[2]);
- free_irq(IRQ_EINT(3), &pins_desc[3]);
-
- return 0;
- }
-
-
- /*
- * The read function of device driver.
- */
- static int mykey_read(struct file *filp, char __user *buff,
- size_t count, loff_t *offp)
- {
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- /* 如果没有按键动作, 休眠 */
- wait_event_interruptible(button_waitq, ev_press);
-
- pr_debug("Starting to read data in the %s function!\n", __FUNCTION__);
-
- /* 如果有按键动作, 返回键值 */
- copy_to_user(buff, &key_val, 1);
-
- ev_press = 0;
-
- return 1;
- }
-
-
- /*
- * The file operations for the device
- */
- static struct file_operations mykey_fops = {
- .owner = THIS_MODULE,
- .open = mykey_open,
- .release = mykey_release,
- .read = mykey_read,
- .fasync = mykey_fasync,
- };
-
-
- /*
- * Set up a cdev entry.
- */
- static void mykey_setup_cdev(struct mykey_dev *dev, int index)
- {
- int err, devno;
-
- devno= MKDEV(major, minor + index);
- cdev_init(&dev->cdev, &mykey_fops);
- dev->cdev.owner = THIS_MODULE;
- err = cdev_add (&dev->cdev, devno, 1);
- if (err)
- printk(KERN_NOTICE "Error %d adding mykey%d", err, index);
- }
-
-
- /*
- * Initialize the pipe devs; return how many we did.
- */
- static int __init mykey_init_module(void)
- {
- int ret;
-
- dev_t devno = MKDEV(major, minor);
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- if (major)
- ret = register_chrdev_region(devno, nr_devs, DEVICE_NAME);
- else {
- ret = alloc_chrdev_region(&devno, minor, nr_devs, DEVICE_NAME);
- major = MAJOR(devno);
- }
- if (ret < 0) {
- printk(KERN_WARNING "%s: can't get major %d\n", \
- DEVICE_NAME, major);
- return ret;
- }
-
- pr_debug("After \"alloc_chrdev_region()\"\n");
-
- mykey_devp = kzalloc(sizeof(struct mykey_dev), GFP_KERNEL);
- if (!mykey_devp) {
- ret = - ENOMEM;
- goto fail_malloc;
- }
-
- pr_debug("After \"kzalloc()\"\n");
-
- /* The following step must after kmalloc() and memset() */
- mykey_setup_cdev(mykey_devp, 0);
-
- pr_debug("After \"mykey_setup_cdev()\"\n");
-
- /* 1. create your own class under /sys
- * 2. register your own device in sys
- * this will cause udev to create corresponding device node
- */
- mykey_class = class_create(THIS_MODULE, "mykey_class");
- if (IS_ERR(mykey_class)) {
- printk(DEVICE_NAME " failed in creating class./n");
- return -1;
- }
- device_create(mykey_class, NULL, devno, NULL, "mykey""%d", 0);
-
- pr_debug("After \"class_create()\" and \"device_create\"\n");
#ifdef DRIVER_DEBUG
- printk(DEVICE_NAME "\tinitialized, major = %d, minor = %d.\n",
- major, minor);
- #endif
- return 0;
-
- fail_malloc:
- unregister_chrdev_region(devno, 1);
-
- return ret;
- }
-
-
- /*
- * This is called by cleanup_module or on failure.
- */
-
- static void __exit mykey_exit_module(void)
- {
- pr_debug("In the %s function!\n", __FUNCTION__);
-
- device_destroy(mykey_class, MKDEV(major, minor));
- class_destroy(mykey_class);
- cdev_del(&mykey_devp->cdev);
- kfree(mykey_devp);
- unregister_chrdev_region(MKDEV(major, minor), 1);
-
#ifdef DRIVER_DEBUG
- printk(DEVICE_NAME "\texited!\n");
- #endif
- }
-
- module_init(mykey_init_module);
- module_exit(mykey_exit_module);
-
- MODULE_AUTHOR("Jason Lu");
- MODULE_VERSION("0.1.0");
- MODULE_DESCRIPTION("Jason's blog: http://blog.chinaunix.net/space.php?\
- uid=20746260");
- MODULE_LICENSE("Dual MPL/GPL");
【7】以下是【3】里Support MY_KEY DEBUG未选中时的运行情况。
【8】keytest.c源码
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <poll.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <fcntl.h>
-
- int fd;
-
- void my_signal_fun(int signum)
- {
- unsigned char key_val;
- read(fd, &key_val, 1);
- printf("key_val: 0x%x\n", key_val);
- }
-
- int main(int argc, char **argv)
- {
- int Oflags;
-
- signal(SIGIO, my_signal_fun);
-
- fd = open("/dev/mykey0", O_RDWR);
- if (fd < 0)
- {
- printf("can't open!\n");
- }
-
- fcntl(fd, F_SETOWN, getpid());
- Oflags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, Oflags | FASYNC);
-
- while (1)
- {
- sleep(1000);
- }
-
- return 0;
- }