Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48031
  • 博文数量: 37
  • 博客积分: 1800
  • 博客等级: 上尉
  • 技术积分: 451
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-29 19:56
文章存档

2011年(9)

2010年(28)

我的朋友

分类: LINUX

2010-12-21 20:25:05

 
源码:
文件: 03_scull.rar
大小: 83KB
下载: 下载
insmod my_dev.ko 之后发生了什么故事?
(1) /proc/devices 中有下面这一行:
 251 my_test_char_dev
 这里显示的设备名称---my_test_char_dev 是下面这条语句决定的:
  result = alloc_chrdev_region(&dev, scull_minor,
             1, "my_test_char_dev");
  参考 install.sh 是如何用 awk 命令取得动态分配的设备号的~~
  
(2) /proc/modules   和 lsmod 是相同的.
    这里也有个名称,但是就是 ko 文件的名称,由 Makefile 中的配置决定.
    这里我的设备名定义为:  my_dev
(3) /sys/module/my_dev/
    这目录下存放了加载该模块的信息,包括加载地址,版本等,有如下文件:
    # ls /sys/module/my_dev -l
        drwxr-xr-x 2 root root    0 2010-12-21 10:24 holders
        drwxr-xr-x 2 root root    0 2010-12-21 10:24 notes
        drwxr-xr-x 2 root root    0 2010-12-21 10:24 parameters
        drwxr-xr-x 2 root root    0 2010-12-21 10:24 sections
        -r--r--r-- 1 root root 4096 2010-12-21 10:24 initstate
        -r--r--r-- 1 root root 4096 2010-12-21 10:24 refcnt
        -r--r--r-- 1 root root 4096 2010-12-21 10:24 srcversion
       
(4) 字符设备驱动的几个要素: 参考 main.c 中修改的部分.
 1) 定义自己的扩展数据结构:
     struct t_my_dev {
        struct cdev cdev; //这个必须的.
        unsigned long size;
        struct semaphore sem;
        wait_queue_head_t inq;
      };
   struct t_my_dev my_dev;
   一般会扩展 信号量,queue等:这两个东西需要初始化.
 2) 初始化
 //1)取得设备号:所谓设备号就是个整数,其中包含了
  result = alloc_chrdev_region(&dev_no, 0, 1, "my_test_char_dev");
 //2)信号量一般是必须的
  //这是初始化信号量,不是创建(是静态声明的),因此没有对应的 free 函数~~
  init_MUTEX(&my_dev.sem);
  init_waitqueue_head(&my_dev.inq);
 //3)初始化设备结构体:一般会自己定义结构体.
  cdev_init(&my_dev.cdev, &my_dev_fops);
 //4)增加设备到内核 
  result = cdev_add (&my_dev.cdev, dev_no, 1);
 //5)如果失败,必须做好清理工作. 
  fail:
  unregister_chrdev_region(dev_no, 1);
3) 结束化
 //1)删除设备
  cdev_del(&my_dev.cdev);
 //2)删除设备号
  unregister_chrdev_region(dev_no, 1);
4) 函数指针:就是结构体 my_dev_fops 中提供的.
    //1) open的模板:
  struct t_my_dev *dev;
  dev = container_of(inode->i_cdev, struct t_my_dev, cdev);
  filp->private_data = dev; //这是技巧所在,在其他函数中,取得回来使用.
 //2) read/write中: PV操作 --- 同步
  P: down_interruptible(&dev->sem)
  V: up(&dev->sem);
  
 //3) read中等待queue,write中唤醒queue:
  Read:  wait_event_interruptible( dev->inq, (dev->size != 0)  )
  Write: wake_up_interruptible(&dev->inq); //唤醒读等待.  
5) 返回值解释
   read 的返回值:
     = count参数: 请求的字节数已经被传送. 这是最好的情况.
     < count参数: 有部分数据被传送. 这可能由于几个原因, 依赖于设备. 
            常常, 应用程序重新试着读取. 例如, 如果你使用 fread 函数来读取, 
            库函数重新发出系统调用直到请求的数据传送完成.
     =0 :到达了文件末尾(没有读取数据).
     <0: 一个负值表示有一个错误. 这个值指出了什么错误, 根据
        出错的典型返回值包括 -EINTR( 被打断的系统调用) 或者 -EFAULT( 坏地址 ).
     write返回值: 类似 read
  
   6) 老方法: int register_chrdev(unsigned int major, const char *name,
              struct file_operations *fops);
      慢慢会淡出视野.
阅读(404) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~