文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux-2.6.35.7字符设备驱动程序源代码分析

linux-2.6.35.7字符设备驱动程序源代码分析

时间:2010-10-13  来源:yangqingsx

字符设备驱动是学习驱动开发的基础,下面就接合一个简单的字符设备驱动程序分析linux内核源代码。在字符设备初始化时,首先由主设备号合次设备号得到字符设备的设备号。该函数为:MKDEV,其源码为:
#define MINORBITS 20
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
在cdev结构体的dev_t成员定义了设备号为32位,其中高12位为主设备号,低20位为次设备号,经过以上两步运算,巧妙的得到了字符设备的设备号。可以用与此类似的方法在已知设备号的情况下计算出主设备号和次设备号。
在有了设备号之后,就是使用register_chrdev_region申请设备号。在这里有一个问题:在linux系统中每一类设备用主设备号来唯一标识,已经注册的设备号不能重复使用。系统中提供了alloc_chrdev_region用于动态申请设备号。
1)register_chrdev_region
linux/fs/char_dev.c
/** 188 * register_chrdev_region() - register a range of device numbers
189 * @from: the first in the desired range of device numbers; must include
190 * the major number.
191 * @count: the number of consecutive device numbers required
 192 * @name: the name of the device or driver.
 193 *
194 * Return value is zero on success, a negative error code on failure.
 195 */
 196int register_chrdev_region(dev_t from, unsigned count, const char *name) 197{
198 struct char_device_struct *cd;
 199 dev_t to = from + count; 200 dev_t n, next;
201
202 for (n = from; n < to; n = next) {
203 next = MKDEV(MAJOR(n)+1, 0);
204 if (next > to)
205 next = to;
206 cd = __register_chrdev_region(MAJOR(n), MINOR(n),
207 next - n, name);
 208 if (IS_ERR(cd))
209 goto fail;
210 }
211 return 0;
212fail:
213 to = n;
214 for (n = from; n < to; n = next) {
215 next = MKDEV(MAJOR(n)+1, 0);
216 kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
 217 }
218 return PTR_ERR(cd);
219} 有上述代码可以看出,它运用了面向对象中方法的重载技术。在注册成功时,返回0.否则释放掉已注册的设备。
2)alloc_chrdev_region
linux/fs/char_dev.c
/**
 222 * alloc_chrdev_region() - register a range of char device numbers
223 * @dev: output parameter for first assigned number
224 * @baseminor: first of the requested range of minor numbers
225 * @count: the number of minor numbers required
 226 * @name: the name of the associated device or driver
 227 *
228 * Allocates a range of char device numbers. The major number will be
229 * chosen dynamically, and returned (along with the first minor number)
230 * in @dev. Returns zero or a negative error code.
231 */
 232int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
233 const char *name)
 234{
235 struct char_device_struct *cd;
236 cd = __register_chrdev_region(0, baseminor, count, name);
237 if (IS_ERR(cd))
238 return PTR_ERR(cd);
239 *dev = MKDEV(cd->major, cd->baseminor); 2
40 return 0;
241}
由上述代码可以看出,在成功申请后,设备号存储在dev中。如果申请失败,则返回错误码。
在完成设备注册之后接下来就是为设备分配内存了,在驱动程序中使用kmalloc函数来为设备分配内存空间。当申请失败时,切记一定要释放已申请的设备号。当申请成功时,接下来就是设备初始化了!
1)cdev结构体初始化
/** 546 * cdev_init() - initialize a cdev structure
547 * @cdev: the structure to initialize
548 * @fops: the file_operations for this device
549 *
550 * Initializes @cdev, remembering @fops, making it ready to add to the
 551 * system with cdev_add().
552 */
553void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 554{
555 memset(cdev, 0, sizeof *cdev);
556 INIT_LIST_HEAD(&cdev->list);
 557 kobject_init(&cdev->kobj, &ktype_cdev_default);
558 cdev->ops = fops;
559}
由上述代码可以看出,cdev_init()函数完成cdev的成员初始化,并建立cdev合file_operations之间的联系。同时INIT_LIST_HEAD函数可以出,cdev结构体使用list_head结构体将所有cdev设备用双向链表链接起来!
至此,字符设备初始化模块便完成。与此相对,有了模块加载函数,也要有模块卸载函数,用户释放设备号和内存空间,以便其他用户可以使用。
在模块卸载函数中使用cdev_del来删除字符设备双向链表中的cdev结构体,使用kfree来释放字符设备所占用的内存空间,与此类似使用unregister_chrdev_region来释放设备号。
至此,一个简单字符设备驱动便完成了。
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载