先看一下每个scull_dev的数据结构的定义:
struct scull_qset {
void **data;
struct scull_qset *next;
};
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
每个scull设备都有一个数据指针,每个指针都指向下一个scull_qset数据结构。每个内存区成为一个量子quantum,这个指针数组即它的长度成为量子集qset,这个两个值可以在scull.h定义初始值,也可以通过ioctl函数自定义其大小,在此例子的源码中每个scull_qset的data里定义了1000个指针(qset)的数组,每个指针都指向一个4000字节的区域(quantum)。
这个内存使用图在《linux驱动程序》上作了说明,可以比较一下第三版和第二版对这个图解释的区别,以下我的应用的程序都是针对第三版发布的源代码。
我们要对这个内存作读取访问,首先传到内核空间的是一个loff_t *offp指针,表示用户对这个文件的读或写操作的位置。首先可以通过这个offp可以获取一个信息,这个loff_t *offp指针指在哪个struct scull_qset上,看源码,在ssize_t scull_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos):
..........................................
/* find listitem, qset index, and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
/* follow the list up to the right position (defined elsewhere) */
dptr = scull_follow(dev, item);
通过scull_follow()函数定位offp指针所在的scull_qset,而在读取数据的时候是针对某一块内存quantum来读取;
item = (long)*f_pos / itemsize:数据在链表的哪个scull_qset里面?
rest = (long)*f_pos % itemsize:在这个scull_qset里面数据偏移量为多少?
s_pos = rest / quantum:在这个scull_qset里面的哪一个quantum?
q_pos = rest % quantum:在这个quantum里面偏移量多少?
指针loff_t *f_pos成功定位!
if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)),内核数据到用户空间的拷贝,成功之后更新偏移指针:*f_pos += count。
下篇文章就介绍对scull源码的简单移植,并提供所有源码 ,赫赫,今天先到这里,休息休息......