Linux设备驱动程序(第三版) 作者科波特(Corbet, j.)书本的示例代码比较零乱,而且网站上给的示例代码是旧版或者是比较完整的代码,且没有单独成章。初学者学习起来比较困难,所以笔者分享一下在学习过程中调试过的模块,供有需要的读者参阅。由于侧重书本每章的知识,所以模块仅反映每章的知识点,不是一个全面的驱动模块,但对学习驱动的编写可能比看书本本身网站提供的代码会更有侧重点。仅仅是每一章相对前一章增加一些代码,而不是一个全面的代码。希望能够交流学习。也可以通过 https://gitee.com/sanzhouzi/ldd3ex.git 下载, 其他章节的代码不再一一写文章显示。直接放到gitee仓库中。
第四章主要是说如何调试内核驱动代码,其中包括增加debug宏,在proc目录下创建自己的文件。增加的代码如下:
scull/main.c
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#ifdef SCULL_DEBUG
/*page 88*/
int scull_read_procmem(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int i, j, len = 0;
int limit = count - 80;
for (i = 0; i < scull_nr_devs && len <= limit; i++) {
struct scull_dev *d = &sculldev[i];
struct scull_qset *qs = d->data;
if (down_interruptible(&d->sem))
return -ERESTARTSYS;
len += sprintf(buf+len, "\nDevice %i: qset %i, q %i, sz %li\n",
i, d->qset, d->quantum, d->size);
for (; qs && len <= limit; qs = qs->next) {
len += sprintf(buf + len, " item at %p, qset at %p\n",
qs, qs->data);
if (qs->data && !qs->next)
for (j = 0; j < d->qset; j++) {
if (qs->data[j])
len += sprintf(buf + len,
" %4i: %8p\n",
j, qs->data[j]);
}
}
up(&sculldev[i].sem);
}
*eof = 1;
return len;
}
/*page 90*/
static void *scull_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos >= scull_nr_devs)
return NULL;
return sculldev + *pos;
}
/*page 91*/
static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (*pos >= scull_nr_devs)
return NULL;
return sculldev + *pos;
}
/*page 91*/
static void scull_seq_stop(struct seq_file *sfile, void *v)
{
}
/*page 92*/
static int scull_seq_show(struct seq_file *s, void *v)
{
struct scull_dev *dev = (struct scull_dev *)v;
struct scull_qset *d;
int i;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
seq_printf(s, "\nDevice %i, qset %i, q %i, sz %li\n",
(int)(dev - sculldev), dev->qset, dev->quantum, dev->size);
for (d = dev->data; d; d = d->next) {
seq_printf(s, " item at %p, qset at %p\n", d, d->data);
if (d->data && !d->next)
for (i = 0; i < dev->qset; i++) {
if (d->data[i])
seq_printf(s, " %4i: %8p\n",
i, d->data[i]);
}
}
up(&dev->sem);
return 0;
}
static struct seq_operations scull_seq_ops = {
.start = scull_seq_start,
.next = scull_seq_next,
.stop = scull_seq_stop,
.show = scull_seq_show,
};
static int scull_proc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &scull_seq_ops);
}
static struct file_operations scull_proc_ops = {
.owner = THIS_MODULE,
.open = scull_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
static void scull_create_proc(void)
{
struct proc_dir_entry *entry;
/*page 89*/
create_proc_read_entry("scullmem", 0,
NULL, scull_read_procmem, NULL);
/*page 93*/
entry = create_proc_entry("scullseq", 0, NULL);
if (entry)
entry->proc_fops = &scull_proc_ops;
}
static void scull_remove_proc(void)
{
remove_proc_entry("scullmem", NULL);
remove_proc_entry("scullseq", NULL);
}
#endif /*SCULL_DEBUG*/
/**********************************************/
static int __init scull_init(void)增加:
#ifdef SCULL_DEBUG
scull_create_proc();
#endif /*SCULL_DEBUG*/
static void scull_exit(void)增加:
#ifdef SCULL_DEBUG
scull_remove_proc();
#endif /*SCULL_DEBUG*/
scull/scull.h
#undef PDEBUG
#ifdef SCULL_DEBUG
#ifdef __KERNEL__
#define PDEBUG(fmt, args...) printk(KERN_NOTICE "scull: " fmt, ##args);
#else
#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args)
#endif
#else
#define PDEBUG(fmt, args...)
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args...)
scull/Makefile
DEBUG = y
ifeq ($(DEBUG), y)
DEBFLAGS = -O -g -DSCULL_DEBUG
else
DEBFLAGS = -O2
endif
EXTRA_CFLAGS += $(DEBFLAGS)
clean:
rm -fr *.o *.ko *.mod.c *.mod.o *.order *.symvers
具体参见代码仓库。