文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>LDD3 read notes Chapter 1-3

LDD3 read notes Chapter 1-3

时间:2009-07-09  来源:hylpro

    
2009.5.21


chapter 1

what's driver
*separate policy and mechanism
*driver is a layer between hw and user space software
*been policy free: ansyc , syc ...

class
* char block network
*usb/serial/ scsi  firmware/i2o
*

chapter 2

module compile
* a configured and built tree
*at lest interface
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("Dual BSD/GPL");

module_init(hello_init);
module_exit(hello_exit);

* keep concurency in mind
* <linux/sched.h> for current
* no float,  4k/8k stack, double underscore function is internal to module...
*find the proper tools in  Documentation/Changes

*compile
obj-m := myh.o
myh-objs := file1.o file2.o

sudo make -C /lib/modules/2.6.28-11-generic/build/ M=$(pwd) modules_install

* version
UTS_RELEASE  ==>  "2.6.10".
LINUX_VERSION_CODE  ==> 132618  (2.6.10)
KERNEL_VERSION(major,minor,release)  ==> to the version code

vermagic.o ==> link with you modules do the version and platform check

* export symbol
EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);

* more information
MODULE_AUTHOR
MODULE_DESCRIPTION
MODULE_VERSION
MODULE_ALIAS
MODULE_DEVICE_TABLE

* init error process
<linux/errno.h>

* init internal , after ready to work , then you can  register stuff
* kernel will call your function immediately you register something

* module parameters
0) insmod hellop howmany=10 whom="Mom"
1) moduleparam.h
2) module_param(whom, charp, S_IRUGO);  /*variable, type, permition */
bool,  invbool, charp( sting pointer, atomaticlly mallc string for user provide), int, long, short, uint,ulong, ushort
3) array parameters
module_param_array(name,type,num,perm);
4) permition
If perm is set to 0, there is no sysfs entry at all; otherwise, it appears under /sys/module* with the given set of permissions : S_IRUGO: read, but can't change,  S_IRUGO|S_IWUSR: only root allow to change it.
NOTE: the parameter can be changed via sysfs but you get no notification

*user space driver limitation
 no interrupt; only  /dev/mem/ allow to access memory directly, access io port after ipperm or iopl but not avalible on some platform, mlock can help lock the program to memory, but many libs you reffrece
* user space driver example
SCSI genaric in kernel -> SANE package for scsi scaner;  libusb (gadgetfs in kernel);  X server

* sysfs file system
/sys/module
/proc/modules

chapter 3  char driver

* design of scull
device scull0 to scull3 : global (open many times) and persistent(unload and reload don't free) memory  for each device.
scullpipe0 to scullpipe3 :  block and non block read/write opration, if multiple process read one device, they contend  data
scullsingle : only one process can open
scullpriv : one for a X console
sculluid : for one uid , if another try open, return device busy
scullwuid :  for one uid, if another tyr, block

* one-major-one-driver principle, one minor one device

*dev_t  (defined in <linux/types.h>)
<linux/kdev_t.h>: MAJOR(dev_t dev);  MINOR(dev_t dev); MKDEV(int major, int minor);

* alloc /register device number
<linux/fs.h>: int register_chrdev_region(dev_t first, unsigned int count, char *name); /*name in /proc/devices and sysfs. */  知道major的情况下
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,count, char *name); /*动态分配major*/
void unregister_chrdev_region(dev_t first, unsigned int count);  /*same release */

*Documentation/devices.txt
*/proc/devices
* init script for your driver: start stop restart
* init script put in /etc/init.d, and put link to runleve directory...(based on LSB)

* file operation registion
<linux/fs.h>  : file_operations  (__user is no mean to gcc , but used by external sanity check for user space address derefrence )
 {
struct module *owner  :THIS_MODULE
loff_t (*llseek) (struct file *, loff_t, int); /*返回正值表示 loff_t(always 64 bit), 负值代表出错, 如果此值为NULL, 只有file结构的pos被修改, 结果不确定 */
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); /*正值代表实际读取的bytes, 负值出错. 此操作为空则 返回 -EINVAL*/
ssize_t (*aio_read)(struct kiocb *, char __user *, size_t, loff_t); /*发起异步io, 未实现则尝试用read*/
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); /*行为同read*/
ssize_t (*aio_write)(struct kiocb *, const char __user *, size_t, loff_t *); /*同aio_read*/
int (*readdir) (struct file *, void *, filldir_t); /*设备文件用不到, 文件系统才有意义*/
unsigned int (*poll) (struct file *, struct poll_table_struct *); /*for poll, epoll, and select, 返回bitmask 指示相应文件是否可以进行非block的io, 可以把进程加入合适的等待队列(poll 提供wait entry) , 如果没有此方法, 内核认为总是可以read /write的*/
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); /* 无此函数,如果不认识则返回-ENOTTY */
int (*mmap) (struct file *, struct vm_area_struct *); /*无此函数则mmap返回-ENODEV.*/
int (*open) (struct inode *, struct file *); /*如果此函数为NULL, 打开总是成功, 但是driver得不到通知*/
int (*flush) (struct file *); /*进程关闭其fd 的时候调用, 要完成(/等待)所有未完成的工作, (不是user space fsync 时候调用的哪个!!, 比较少用. 没有实现,就简单的不调用*/
int (*release) (struct inode *, struct file *); /*file structure被释放的时候调用, 可以为NULL*/
int (*fsync) (struct file *, struct dentry *, int); /*fsync system call, 如果未实现返回-EINVAL*/
int (*aio_fsync)(struct kiocb *, int); /*fsync 的异步模式*/
int (*fasync) (int, struct file *, int); /*异步通知, 不支持则可置为NULL*/
int (*lock) (struct file *, int, struct file_lock *); /*设备驱动几乎没有用这个的*/
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); /*缺失就用read/wite 代替*/
ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *); /*read side of sendfile system call, 一般驱动里不实现这个*/
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *,int); /*send file的发送端, driver 一般不用*/
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);  /*影射驱动内存到process, 一般不用实现, 主要用于实现一写对齐要求*/
int (*check_flags)(int) /*让模块自己检查传给fcntl(F_SETFL...)的参数*/
int (*dir_notify)(struct file *, unsigned long); /*文件系统专用, 实现目录改变通知机制*/

}

* the most important one
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};

*The file Structure, <linux/fs.h>  (each open make a file structure)
{
    mode_t f_mode; /*最终用户获得的权限: FMODE_READ and FMODE_WRITE, open ioctl 时驱动可以检查, read/write kernel已经代为*/
    loff_t f_pos; /*驱动的读写函数用最后一个参数更新这个值*/
    unsigned int f_flags; /*用户所打算的操作方式(open flags),O_RDONLY, O_NONBLOCK, and O_SYNC, 文件权限加查应该用f_mode, 驱动很少用, */
    struct file_operations *f_op; /*open中可以改变这个值, 比如类似/dev/mem /dev/null那样*/
    void *private_data; /*open中可以放置任何东西, 但记得在.release中清理下*/
    struct dentry *f_dentry; /*驱动一般也就用它找下inode*/
}

* The inode Structure
{
      dev_t i_rdev; /* 包含实际的设备编号*/
       struct cdev *i_cdev; /* struct cdev 是kernel 内部对cdev的抽象*/
      ...........
}
鼓励用下面的接口从inode 得到对应设备:
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);

*Char Device Registration <linux/cdev.h>
* stand alone cdev
struct cdev *my_cdev = cdev_alloc( );
my_cdev->ops = &my_fops;
* 用内嵌的cdev 
void cdev_init(struct cdev *cdev, struct file_operations *fops);

*然后cdev->onwer= THIS_MODULE; 
*最后一步 int cdev_add(struct cdev *dev, dev_t num, unsigned int count);  /*一旦注册就会被内核访问*/
*void cdev_del(struct cdev *dev);

* the older way to register the cdev
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
int unregister_chrdev(unsigned int major, const char *name);
这个接口强制分配256个minor 和其对应的cdev, 不能使用>255的minor . 这个函数内部给注册dev number, 就不用
调用哪个region注册了. 新code 无论如何不能用这个接口了

* open and release
inode 含有i_cdev就是设备注册的哪个, 从这个得到scull_dev可以用 <linux/kernel.h>: container_of(pointer, container_type, container_field);  一般吧filep->private 防上scull_dev指针,方便访问. open task:
1)第一次打开时初始化硬件,以及检查有无硬件错误
2) 也许要更新filep->fops
3) 初始化filp->private_data

用iminor宏也可以找到对应的device. 
release task:
1)最后一次关闭则shutdown,
2) 释放open中分配的资源 (注意如果open的时候把fops替换了, 这里releas则有可能是另外的释放函数, 注意了)

* open vs release;close vs flush

* memory alloc   <linux/slab.h>, are:
void *kmalloc(size_t size, int flags);
void kfree(void *ptr);


* user pinter access  <asm/uaccess.h>)
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);
unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);

返回值代表剩余要copy的字节, 也就是说不是0 就代表有问题.

* read write notes
* free to transfer less data than requied
* update fpos : 用传递进来的参数和正确传输的字节数目来更新.
* 只要有成功的传输,就要返回实际传输字节
* 没有必要非得传输user 要求的大小, 可以根据设备灵活处理, user spac根据返回的字节数会处理这个问题
* 返回0 代表到文件末尾 (如果需要等待数据,则不能返回0)
* copyto/copyfrom 出错的话, 成功传输的字节一般不返回给用户了, 直接返回出错

* write 返回0, 不代表到文件末尾, 只是什么都没有传输而已
* write 也可以只写部分数据的,但是有些应用程序却么有处理好这个特性






相关阅读 更多 +
排行榜 更多 +
无敌赛车王

无敌赛车王

赛车竞速 下载
多人汽车聚会

多人汽车聚会

赛车竞速 下载
漂移基地

漂移基地

赛车竞速 下载