免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 978 | 回复: 0
打印 上一主题 下一主题

字符驱动随记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-09-09 10:44 |只看该作者 |倒序浏览

                                                驱动所涉及的一些要素:1.主次编号: 下面的列表显示了一个典型系统上出现的几个设备. 它们的主编号是 1, 4, 7, 和 10, 而次编号是 1, 3, 5, 64, 65, 和 129. crw-rw-rw- 1 root  root  1,  3 Apr 11  2002 null
crw------- 1 root  root  10, 1 Apr 11  2002 psaux
crw------- 1 root  root  4,  1 Oct 28 03:04 tty1
crw-rw-rw- 1 root  tty   4, 64 Apr 11  2002 ttys0
crw-rw---- 1 root  uucp  4, 65 Apr 11  2002 ttyS1
crw--w---- 1 vcsa  tty   7,  1 Apr 11  2002 vcs1
crw--w---- 1 vcsa  tty   7,129 Apr 11  2002 vcsa1
crw-rw-rw- 1 root  root  1,  5 Apr 11  2002 zero  
主编号标识设备相连的驱动. 例如, /dev/null 和 /dev/zero 都由驱动 1 来管理,
而虚拟控制台和串口终端都由驱动 4 管理; 同样, vcs1 和 vcsa1 设备都由驱动 7 管理. 现代 Linux
内核允许多个驱动共享主编号, 但是你看到的大部分设备仍然按照一个主编号一个驱动的原则来组织.
次编号被内核用来决定引用哪个设备. 依据你的驱动是如何编写的(如同我们下面见到的), 你可以从内核得到一个你的设备的直接指针,
或者可以自己使用次编号作为本地设备数组的索引. 不论哪个方法, 内核自己几乎不知道次编号的任何事情, 除了它们指向你的驱动实现的设备.
设备编号的内部表示为获得一个 dev_t 的主或者次编号, 使用:
MAJOR(dev_t dev);MINOR(dev_t dev);
相反, 如果你有主次编号, 需要将其转换为一个 dev_t, 使用:MKDEV(int major, int minor);
分配和释放设备编号获取一个或多个设备编号int register_chrdev_region(dev_t first, unsigned int count, char *name);
主要用这个:
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
设备编号的释放使用:
void unregister_chrdev_region(dev_t first, unsigned int count);
主编号的动态分配 对于新驱动, 我们强烈建议你使用动态分配来获取你的主设备编号, 而不是随机选取一个当前空闲的编号. 换句话说, 你的驱动应当几乎肯定地使用 alloc_chrdev_region, 不是 register_chrdev_region.
动态分配的缺点是你无法提前创建设备节点, 因为分配给你的模块的主编号会变化. 对于驱动的正常使用, 这不是问题, 因为一旦编号分配了, 你可从 /proc/devices 中读取它.
[/url]
为使用动态主编号来加载一个驱动, 因此, 可使用一个简单的脚本来代替调用 insmod, 在调用 insmod 后, 读取 /proc/devices 来创建特殊文件.
scull_load.sh :
#!/bin/sh
module="scull"
device="scull"
mode="664"
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.ko $* || exit 1
# remove stale nodes
rm -f /dev/${device}[0-3]
major=$(awk "\\$2==\"$module\" {print \\$1}" /proc/devices)
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
# give appropriate group/permissions, and change the group.
# Not all distributions have staff, some have "wheel" instead.
group="staff"
grep -q '^staff:' /etc/group || group="wheel"
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
2.一些重要数据结构大部分的基础性的驱动操作包括 3 个重要的内核数据结构, 称为 file_operations, file, 和 inode.
文件操作     到现在, 我们已经保留了一些设备编号给我们使用, 但是我们还没有连接任何我们设备操作到这些编号上. file_operation 结构是一个字符驱动如何建立这个连接
     这个结构是一个函数指针的集合. 每个打开文件(内部用一个 file 结构来代表)与它自身的函数集合相关连( 通过包含一个称为 f_op 的成员, 它指向一个 file_operations 结构).
这些操作大部分负责实现系统调用, 因此, 命名为 open, read, 等等.
我们可以认为文件是一个"对象"并且其上的函数操作称为它的"方法", 使用面向对象编程的术语来表示一个对象声明的用来操作对象的动作. 这是我们在
Linux 内核中看到的第一个面向对象编程的现象
    file_operation 结构或者其一个指针称为 fops( 或者它的一些变体). 结构中的每个成员必须指向驱动中的函数,
这些函数实现一个特别的操作, 或者对于不支持的操作留置为 NULL. 当指定为 NULL 指针时内核的确切的行为是每个函数不同的
文件结构struct file是设备驱动中第二个最重要的数据结构.
文件结构代表一个打开的文件.它由内核在
open 时创建, 并传递给在文件上操作的任何函数, 直到最后的关闭. 在文件的所有实例都关闭后, 内核释放这个数据结构.
inode 结构
inode 结构由内核在内部用来表示文件. 因此, 它和代表打开文件描述符的文件结构是不同的. 可能有代表单个文件的多个打开描述符的许多文件结构, 但是它们都指向一个单个 inode 结构.inode 结构包含大量关于文件的信息. 作为一个通用的规则, 这个结构只有 2 个成员对于编写驱动代码有用:
    dev_t i_rdev: 对于代表设备文件的节点, 这个成员包含实际的设备编号.    struct cdev *i_cdev: struct cdev 是内核的内部结构, 代表字符设备; 这个成员包含一个指针, 指向这个结构, 当节点指的是一个字符设备文件时.
从一个 inode 中获取主次编号:unsigned int iminor(struct inode *inode);unsigned int imajor(struct inode *inode);
3.字符设备注册
内核在内部使用类型 struct cdev 的结构来代表字符设备.
在内核调用你的设备操作前, 你编写分配并注册一个或几个这些结构
有 2 种方法来分配和初始化一个这些结构. 如果你想在运行时获得一个独立的 cdev 结构, 你可以为此使用这样的代码:
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
但是, 偶尔你会想将 cdev 结构嵌入一个你自己的设备特定的结构; scull 这样做了. 在这种情况下, 你应当初始化你已经分配的结构, 使用:
void cdev_init(struct cdev *cdev, struct file_operations *fops);一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
scull 中的设备注册注册一个字符设备的经典方法是使用:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
从系统中去除你的设备的正确的函数是:
int unregister_chrdev(unsigned int major, const char *name);
major 和 name 必须和传递给 register_chrdev 的相同, 否则调用会失败.
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:[url]http://blog.chinaunix.net/u3/96294/showart_2048799.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP