Chinaunix首页 | 论坛 | 博客
  • 博客访问: 449080
  • 博文数量: 40
  • 博客积分: 1410
  • 博客等级: 军士长
  • 技术积分: 1396
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-22 19:26
个人简介

嵌入式系统工程师,从事视频、图像、网络、虚拟化等方面的底层软件开发与优化。

文章存档

2014年(4)

2013年(10)

2012年(14)

2011年(12)

分类: LINUX

2011-12-18 15:15:25

所用到源码: source.zip   

【1】配置Kconfig,添加要调试驱动模块的DEBUG选项
如在driver/char目录下的Kconfig中添加如下代码:
  1. config MY_KEY //该部分配置驱动是否编译进内核/编译为内核模块/不编译
  2.     tristate "Key driver for FriendlyARM Tiny6410 development boards"
  3.     depends on CPU_S3C6410
  4.     default m
  5.     help
  6.      this is buttons driver, add by Jason

  7. config MY_KEY_DEBUG //该部分是调试时添加,配置是否打印调试信息,如果不需要可不添加
  8.     bool "Support MY_KEY DEBUG"
  9.     help
  10.      this is DEBUG function, add by Jason
  11. depends on MY_KEY

【2】配置Makefile,添加编译支持驱动模块 EXTRA_CFLAGS += -DDEBUG 
如在driver/char目录下的Makefile中添加如下代码:
  1. obj-$(CONFIG_MY_KEY)        += my_key.o
  2. ifeq ($(CONFIG_MY_KEY_DEBUG), y)             //判断是否调试驱动
  3.     EXTRA_CFLAGS += -DDEBUG
  4. 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比较方便。
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/cdev.h>
  7. #include <linux/types.h>
  8. #include <linux/device.h>
  9. #include <linux/mm.h>
  10. #include <linux/slab.h>
  11. #include <linux/sched.h>
  12. #include <linux/poll.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/irq.h>
  15. #include <asm/uaccess.h>
  16. #include <asm/irq.h>
  17. #include <asm/io.h>
  18. #include <asm/system.h>
  19. #include <mach/map.h>
  20. #include <mach/regs-clock.h>
  21. #include <mach/regs-gpio.h>
  22. #include <mach/irqs.h>
  23. #include <mach/gpio-bank-n.h>
  24. #include <plat/gpio-cfg.h>

  25. #define DRIVER_DEBUG    1
  26. #define DEVICE_NAME        "mykey"

  27. /* parameters */

  28. static int major;
  29. static int minor = 0;
  30. static int nr_devs = 1;            /* number of devices */

  31. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  32. static struct fasync_struct *button_async;

  33. /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
  34. static volatile int ev_press = 0;

  35. /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
  36. /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
  37. struct pin_desc{
  38.     unsigned int pin_num;
  39.     unsigned int key_val;
  40. };

  41. struct pin_desc pins_desc[4] = {
  42.     {0x00, 0x01},
  43.     {0x01, 0x02},
  44.     {0x02, 0x03},
  45.     {0x03, 0x04},
  46. };

  47. static unsigned char key_val;

  48. struct class *mykey_class;

  49. struct mykey_dev {
  50.     struct cdev cdev;        /* char device structure */
  51. }*mykey_devp;            /* device structure pointer */

  52. /*
  53.  * 确定按键值
  54.  */
  55. static irqreturn_t buttons_irq(int irq, void *dev_id, struct pt_regs *regs)
  56. {
  57.     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
  58.     unsigned int pinval;

  59.     pr_debug("In the %s function!\n", __FUNCTION__);

  60.     pinval = (~readl(S3C64XX_GPNDAT)) & (1 << pindesc->pin_num);

  61.     if (pinval)    //one of the key is pressed
  62.         key_val = pindesc->key_val;
  63.     else
  64.         key_val = 0x80 | pindesc->key_val;

  65.     ev_press = 1;         /* 表示中断发生了 */

  66.     wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */

  67.     kill_fasync (&button_async, SIGIO, POLL_IN);

  68.     return IRQ_RETVAL(IRQ_HANDLED);
  69. }


  70. /*
  71.  * The fasync function of device driver.
  72.  */
  73. static int mykey_fasync (int fd, struct file *filp, int on)
  74. {
  75.     pr_debug("driver: mykey_fasync!\n");

  76.     return fasync_helper (fd, filp, on, &button_async);
  77. }


  78. /*
  79.  * The open function of device driver.
  80.  */

  81. static int mykey_open(struct inode *inode, struct file *filp)
  82. {
  83.     pr_debug("In the %s function!\n", __FUNCTION__);

  84.     request_irq(IRQ_EINT(0), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S1", &pins_desc[0]);
  85.     request_irq(IRQ_EINT(1), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[1]);
  86.     request_irq(IRQ_EINT(2), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[2]);
  87.     request_irq(IRQ_EINT(3), buttons_irq, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[3]);

  88.     return 0;
  89. }


  90. /*
  91. * The release function of device driver.
  92. */
  93. static int mykey_release(struct inode *inode, struct file *filp)
  94. {
  95.     pr_debug("In the %s function!\n", __FUNCTION__);

  96.     free_irq(IRQ_EINT(0), &pins_desc[0]);
  97.     free_irq(IRQ_EINT(1), &pins_desc[1]);
  98.     free_irq(IRQ_EINT(2), &pins_desc[2]);
  99.     free_irq(IRQ_EINT(3), &pins_desc[3]);

  100.     return 0;
  101. }


  102. /*
  103. * The read function of device driver. 
  104. */
  105. static int mykey_read(struct file *filp, char __user *buff,
  106.         size_t count, loff_t *offp)
  107. {
  108.     pr_debug("In the %s function!\n", __FUNCTION__);

  109.     /* 如果没有按键动作, 休眠 */
  110.     wait_event_interruptible(button_waitq, ev_press);

  111.     pr_debug("Starting to read data in the %s function!\n", __FUNCTION__);

  112.     /* 如果有按键动作, 返回键值 */
  113.     copy_to_user(buff, &key_val, 1);

  114.     ev_press = 0;

  115.     return 1;
  116. }


  117. /*
  118.  * The file operations for the device
  119.  */
  120. static struct file_operations mykey_fops = {
  121. .owner = THIS_MODULE,
  122. .open = mykey_open,
  123. .release = mykey_release,
  124. .read = mykey_read,
  125. .fasync = mykey_fasync,
  126. };


  127. /*
  128.  * Set up a cdev entry.
  129.  */
  130. static void mykey_setup_cdev(struct mykey_dev *dev, int index)
  131. {
  132.     int err, devno;

  133.     devno= MKDEV(major, minor + index);
  134.     cdev_init(&dev->cdev, &mykey_fops);
  135.     dev->cdev.owner = THIS_MODULE;
  136.     err = cdev_add (&dev->cdev, devno, 1);
  137.     if (err)
  138.         printk(KERN_NOTICE "Error %d adding mykey%d", err, index);
  139. }


  140. /*
  141.  * Initialize the pipe devs; return how many we did.
  142.  */
  143. static int __init mykey_init_module(void)
  144. {
  145.     int ret;

  146.     dev_t devno = MKDEV(major, minor);
  147.      
  148.     pr_debug("In the %s function!\n", __FUNCTION__);

  149.     if (major)
  150.         ret = register_chrdev_region(devno, nr_devs, DEVICE_NAME);
  151.     else {
  152.         ret = alloc_chrdev_region(&devno, minor, nr_devs, DEVICE_NAME);
  153.         major = MAJOR(devno);
  154.     }
  155.     if (ret < 0) {
  156.         printk(KERN_WARNING "%s: can't get major %d\n", \
  157.             DEVICE_NAME, major);
  158.         return ret;
  159.     }

  160.     pr_debug("After \"alloc_chrdev_region()\"\n");

  161.     mykey_devp = kzalloc(sizeof(struct mykey_dev), GFP_KERNEL);
  162.     if (!mykey_devp) {
  163.         ret = - ENOMEM;
  164.         goto fail_malloc;
  165.     }

  166.     pr_debug("After \"kzalloc()\"\n");

  167.     /* The following step must after kmalloc() and memset() */
  168.     mykey_setup_cdev(mykey_devp, 0);

  169.     pr_debug("After \"mykey_setup_cdev()\"\n");

  170.     /* 1. create your own class under /sys
  171.     * 2. register your own device in sys
  172.     * this will cause udev to create corresponding device node 
  173.     */
  174.     mykey_class = class_create(THIS_MODULE, "mykey_class");
  175.     if (IS_ERR(mykey_class)) {
  176.         printk(DEVICE_NAME " failed in creating class./n");
  177.         return -1; 
  178.     }
  179.     device_create(mykey_class, NULL, devno, NULL, "mykey""%d", 0);

  180.     pr_debug("After \"class_create()\" and \"device_create\"\n");

 #ifdef DRIVER_DEBUG
  1. printk(DEVICE_NAME "\tinitialized, major = %d, minor = %d.\n",
  2.          major, minor);
  3. #endif
  1.     return 0;

  2. fail_malloc:
  3.     unregister_chrdev_region(devno, 1);

  4.     return ret;
  5. }


  6. /*
  7.  * This is called by cleanup_module or on failure.
  8.  */

  9. static void __exit mykey_exit_module(void)
  10. {
  11.     pr_debug("In the %s function!\n", __FUNCTION__);

  12.     device_destroy(mykey_class, MKDEV(major, minor));
  13.     class_destroy(mykey_class);
  14.     cdev_del(&mykey_devp->cdev);
  15.     kfree(mykey_devp);
  16.     unregister_chrdev_region(MKDEV(major, minor), 1);    

  #ifdef DRIVER_DEBUG
  1.     printk(DEVICE_NAME "\texited!\n");
  2.  #endif
  3. }

  4. module_init(mykey_init_module);
  5. module_exit(mykey_exit_module);

  6. MODULE_AUTHOR("Jason Lu");
  7. MODULE_VERSION("0.1.0");
  8. MODULE_DESCRIPTION("Jason's blog: http://blog.chinaunix.net/space.php?\
  9.         uid=20746260");
  10. MODULE_LICENSE("Dual MPL/GPL");

【7】以下是【3】里Support MY_KEY DEBUG未选中时的运行情况。

【8】keytest.c源码
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <poll.h>
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>

  10. int fd;

  11. void my_signal_fun(int signum)
  12. {
  13.     unsigned char key_val;
  14.     read(fd, &key_val, 1);
  15.     printf("key_val: 0x%x\n", key_val);
  16. }

  17. int main(int argc, char **argv)
  18. {
  19.     int Oflags;

  20.     signal(SIGIO, my_signal_fun);
  21.     
  22.     fd = open("/dev/mykey0", O_RDWR);
  23.     if (fd < 0)
  24.     {
  25.         printf("can't open!\n");
  26.     }

  27.     fcntl(fd, F_SETOWN, getpid());    
  28.     Oflags = fcntl(fd, F_GETFL);     
  29.     fcntl(fd, F_SETFL, Oflags | FASYNC);

  30.     while (1)
  31.     {
  32.         sleep(1000);
  33.     }
  34.     
  35.     return 0;
  36. }
阅读(27223) | 评论(1) | 转发(7) |
给主人留下些什么吧!~~

edaplayer2015-10-14 14:29:20

实际上pr_debug不是由DEBUG宏控制的,所以加EXTRA_CFLAGS += -DDEBUG没有意义。
想要在终端查看pr_debug的打印信息,只要修改打印级别为8即可。
实际上,可以通过cat /proc/kmsg查看pr_debug的打印信息,完全不需要任何设置。