【1】配置Kconfig,添加要调试驱动模块的DEBUG选项
如在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
[*] 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;
-
}