ldd3代码分析(高级字符驱动)

/**//* * main.c -- the bare scull char module * * 此代码为ldd3例子,自己加了些注释;希望可以和更多和我同样有兴趣的鸟儿们一块学习讨论。 * 哪有注释的不对的地方请发mail给我,或留言; * * author : liyangth@gmail.com  * * date: 2007-2-7 *  * Note:注释的每一个关键的段都以[ta
摘要由CSDN通过智能技术生成
/*
 * 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 */
/*
 * 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 *= &scull_devices[i];
        
struct scull_qset *qs = d->data;
        
if (down_interruptible(&d->sem))
            
return -ERESTARTSYS;
        len 
+= sprintf(buf+len," Device %i: qset %i, q %i, sz %li ",
                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 ",
                    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 ",
                                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, 
" Device %i: qset %i, q %i, sz %li ",
            (
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 ", 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 ",
                            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)
{
  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值