/*
* main.c -- the bare scull char module
*
* 此代码为ldd3例子,自己加了些注释;希望可以和更多有着同样兴趣的鸟儿们一块学习讨论。
* 哪有注释的不对的地方请发mail给我,或留言;
*
* author : liyangth@gmail.com
*
* date: 2007-2-7
*
* Note:注释的每一个关键的段都以[tag00]作了标签,大家可以按照tag的顺序阅读;
* e.g: 搜索 "Tag000"
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_*_user */
#include "scull.h" /* local definitions */
/*
* Our parameters which can be set at load time.
*/
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS; /* number of bare scull devices */
int scull_quantum = SCULL_QUANTUM;
int scull_qset = SCULL_QSET;
/*
* 模块参数,可在模块转载时赋值,很灵活方便;
* e.g:
* insmod scull.ko scull_major=111 scull_nr_devs=3 scull_quantum=1000
*
*[形参说明]
* 1 -- 变量名;
* 2 -- 变量类型;
* 3 -- sysfs入口项的访问许可掩码(一般用S_IRUGO就成);
*/
module_param(scull_major, int, S_IRUGO);
module_param(scull_nr_devs, int, S_IRUGO);
module_param(scull_quantum, int, S_IRUGO);
module_param(scull_qset, int, S_IRUGO);
MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");
struct scull_dev *scull_devices; /* allocated in scull_init_module */
/* Note: 不要把它理解成一个指向scull_dev结构的指针, 它其实是一个scull_dev结构数组,等待下面kmalloc分配多个我们scull设备空间 */
/*
* Empty out the scull device; 就像销毁链表,和理解如何编写一个字符驱动没有关系,可以不看;
*
* must be called with the device semaphore held. 要注意一下了,肯定是要同步的;
*
*/
int scull_trim(struct scull_dev *dev)
{
struct scull_qset *next, *dptr;
int qset = dev->qset; /* "dev" is not-null */
int i;
for (dptr = dev->data; dptr; dptr = next) { /* all the list items */
if (dptr->data) {
for (i = 0; i < qset; i++)
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data = NULL;
}
next = dptr->next;
kfree(dptr);
}
dev->size = 0;
dev->quantum = scull_quantum;
dev->qset = scull_qset;
dev->data = NULL;
return 0;
}
//Start: [Tag003] proc的实现,可以先不看;
#ifdef SCULL_DEBUG /* use proc only if debugging */
//这个是老方法实现的proc
/*
* The proc filesystem: function to read and entry
*/
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; /* Don't print more than this */
for (i = 0; i < scull_nr_devs && len <= limit; i++) {
struct scull_dev *d = &scull_devices[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) { /* scan the list */
len += sprintf(buf + len, " item at %p, qset at %p\n",
qs, qs->data);
if (qs->data && !qs->next) /* dump only the last item */
for (j = 0; j < d->qset; j++) {
if (qs->data[j])
len += sprintf(buf + len,
" % 4i: %8p\n",
j, qs->data[j]);
}
}
up(&scull_devices[i].sem);
}
*eof = 1;
return len;
}
//下面的是用新方法实现的
/*
* For now, the seq_file implementation will exist in parallel. The
* older read_procmem function should maybe go away, though.
*/
/*
* Here are our sequence iteration methods. Our "position" is
* simply the device number.
*/
static void *scull_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos >= scull_nr_devs)
return NULL; /* No more to read */
return scull_devices + *pos;
}
static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (*pos >= scull_nr_devs)
return NULL;
return scull_devices + *pos;
}
static void scull_seq_stop(struct seq_file *s, void *v)
{
/* Actually, there's nothing to do here */
}
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 - scull_devices), dev->qset,
dev->quantum, dev->size);
for (d = dev->data; d; d = d->next) { /* scan the list */
seq_printf(s, " item at %p, qset at %p\n", d, d->data);
if (d->data && !d->next) /* dump only the last item */
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;
}
/*
* Tie the sequence operators up.
*/
static struct seq_operations scull_seq_ops = {
.start = scull_seq_start,
.next = scull_seq_next,
.stop = scull_seq_stop,
.show = scull_seq_show
};
/*
* Now to implement the /proc file we need only make an open
* method which sets up the sequence operators.
*/
static int scull_proc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &scull_seq_ops);
}
/*
* Create a set of file operations for our proc file.
*/
static struct file_operations scull_proc_ops = {
.owner = THIS_MODULE,
.open = scull_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/*
* Actually create (and remove) the /proc file(s).
*/
//分别用新老方法实现了二个proc文件
static void scull_create_proc(void)
{
struct proc_dir_entry *entry;
create_proc_read_entry("scullmem", 0 /* default mode */,
NULL /* parent dir */, scull_read_procmem,
NULL /* client data */);
entry = create_proc_entry("scullseq", 0, NULL);
if (entry)
entry->proc_fops = &scull_proc_ops;
}
static void scull_remove_proc(void)
{
/* no problem if it was not registered */
remove_proc_entry("scullmem", NULL /* parent dir */);
remove_proc_entry("scullseq", NULL);
}
#endif /* SCULL_DEBUG */
//End
/* 开始实现对设备操作的方法集了,关键!!! */
/*
* Open and close
*/
//[Tag004]
/*
open应完成的工作有:
1.检查设备特定的错误(诸如设备未就绪或类似的硬件问题)
2.如果设备是首次打开,则对其进行初始化;
3.如有必要,更新f_op指针;
4.分配并填写filp->private_data;(在这里我们只实现这项即可)
*/
/*
[形参说明]
struct inode *inode -- 用它的i_cdev成员得到dev;
struct file *filp -- 将得到的dev存放到他的成员private_data中;
*/
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
/*
[说明]
1.我们要填充的应该是我们自己的特殊设备,而不是钳在他里面的字符设备结构;
2.inode结构的i_cdev成员这能提供基本字符设备结构;
3.这里利用了定义在<linux/kernel.h>中的宏来实现通过cdev得到dev;
*/
/*
以后read , write ,等操作的实现中就靠他来得到dev了;
*/
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
scull_trim(dev); /* ignore errors */
up(&dev->sem);
}
return 0; /* success */
}
/* close device file, in here we do nothing */
/*
* [Tag005]
* close应完成的工作有:
* 1.释放由open分配的,保存在filp->private_data中的所有内容;
* 2.在最后一次关闭操作时关闭设备;
* [注意:]并不是每次的close系统调用都会去调用到release. 在open时,也仅在open时才会创建
* 一个新的数据结构;在fork, dup时只是增加了这个结构中维护的一个引用计数;
* 所以当这个引用计数为0时,调用的close才意味着要释放设备数据结构,此时release才会被调用;
*/
int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*
* Follow the list
*
* 第一次调用时用于创建链表;
* 然后就是找到第n个节点;
没有合适的资源?快使用搜索试试~ 我知道了~
LinuxDeviceDrivers3(包括源码注解)
共98个文件
c:47个
makefile:18个
h:9个
5星 · 超过95%的资源 需积分: 10 72 下载量 50 浏览量
2007-10-12
17:17:20
上传
评论
收藏 1.38MB RAR 举报
温馨提示
英文版,源码有注解(中文的),难得的驱动学习教材
资源详情
资源评论
资源推荐
收起资源包目录
LinuxDeviceDrivers3.rar (98个子文件)
LinuxDeviceDrivers3
ldd3_examples
skull
skull_init.c 6KB
Makefile 5B
skull_clean.c 336B
simple
simple.c 6KB
simple_load 737B
simple_unload 170B
Makefile 696B
pci
pci_skel.c 1KB
Makefile 208B
LICENSE 1KB
include
lddbus.h 855B
tty
tiny_serial.c 6KB
tiny_tty.c 15KB
Makefile 699B
shortprint
shortprint.c 14KB
shortprint_unload 174B
shortprint_load 624B
Makefile 507B
shortprint.h 1KB
sculld
main.c 15KB
sculld_load 755B
mmap.c 3KB
sculld.h 4KB
sculld_unload 182B
Makefile 739B
short
short_unload 237B
short.c 17KB
short_load 2KB
Makefile 681B
snull
snull_unload 77B
snull.c 18KB
snull.h 1KB
Makefile 682B
snull_load 171B
sbull
sbull.h 2KB
sbull.c 10KB
sbull_unload 184B
Makefile 682B
sbull_load 1KB
scullv
main.c 14KB
mmap.c 3KB
scullv_load 755B
scullv_unload 182B
Makefile 739B
scullv.h 3KB
scull
pipe.c 11KB
main.c 20KB
scull.init 3KB
scull_load 2KB
scull.h 5KB
access.c 11KB
scull_unload 335B
Makefile 933B
usb
usb-skeleton.c 9KB
Makefile 212B
misc-modules
kdatasize.c 1KB
complete.c 2KB
jit.c 7KB
hello.c 463B
kdataalign.c 2KB
seq.c 2KB
silly.c 6KB
faulty.c 2KB
Makefile 987B
hellop.c 1KB
jiq.c 6KB
sleepy.c 2KB
misc-progs
gdbline 417B
setconsole.c 1KB
netifdebug.c 2KB
dataalign.c 2KB
load50.c 925B
asynctest.c 1KB
inp.c 3KB
polltest.c 1KB
datasize.c 1KB
mapper.c 2KB
outp.c 4KB
mapcmp.c 2KB
nbtest.c 1KB
setlevel.c 2KB
Makefile 297B
Makefile 289B
scullp
main.c 14KB
scullp_load 755B
scullp.h 3KB
mmap.c 3KB
scullp_unload 182B
Makefile 739B
lddbus
lddbus.c 4KB
Makefile 710B
scullc
main.c 14KB
mmap.c 3KB
scullc_load 755B
scullc_unload 182B
scullc.h 3KB
Makefile 732B
LinuxDeviceDrivers3.chm 1.32MB
共 98 条
- 1
skylucifer
- 粉丝: 1
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论4