所用到源码:
【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;
-
}