In LDD3's (Linux Device Drivers 3rd Edition book) scullpipe
, what do the parameters in static int scull_read_p_mem(char *buf, char **start, off_t offset, int count, int *eof, void *data)
mean? Specifically, I don't understand the difference between start
, page
, and offset
.
There are a number of questions I have regarding the actual implementation itself (which can be found below):
struct scull_pipe {
wait_queue_head_t inq, outq; /* read and write queues */
char *buffer, *end; /* begin of buf, end of buf */
int buffersize; /* used in pointer arithmetic */
char *rp, *wp; /* where to read, where to write */
int nreaders, nwriters; /* number of openings for r/w */
struct fasync_struct *async_queue; /* asynchronous readers */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
int scull_p_nr_devs; /* the number of scull_pipe devices */
scull_pipe *scull_p_devices; /* scull_pipe devices to be malloc'ed */
/* ...... */
/* our proc read implementation */
static int scull_read_p_mem(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
int i, len;
struct scull_pipe *p;
#define LIMIT (PAGE_SIZE-200) /* don't print any more after this size */
*start = buf;
len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer);
for(i = 0; i < scull_p_nr_devs && len <= LIMIT; i++) {
p = &scull_p_devices[i];
if (down_interruptible(&p->sem))
return -ERESTARTSYS;
len += sprintf(buf+len, "\nDevice %i: %p\n", i, p);
len += sprintf(buf+len, " Buffer: %p to %p (%i bytes)\n",
p->buffer, p->end, p->buffersize);
len += sprintf(buf+len, " rp %p wp %p\n", p->rp, p->wp);
len += sprintf(buf+len, " readers %i writers %i\n",
p->nreaders, p->nwriters);
up(&p->sem);
scullp_proc_offset(buf, start, &offset, &len);
}
*eof = (len <= LIMIT);
return len;
}
static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len)
{
/* QUESTION: what does this function do? */
if (*offset == 0)
return;
if (*offset >= *len) {
*offset -= *len; /* QUESTION: what is the purpose of this? */
*len = 0;
}
else {
*start = buf + *offset; /* QUESTION: why do you need to change "start"? */
*offset = 0;
}
}