platform_device和platform_driver(二)

来源:互联网 发布:mac 菜单栏 隐藏 编辑:程序博客网 时间:2024/06/11 17:45
    紧接上面介绍的数据结构,介绍驱动程序的具体实现过程。
 
    相信大家都知道module_init()这个宏。驱动模块加载的时候会调用这个宏。它接收一个函数为参数,作为它的参数的函数将会对上面提到的platform_driver进行处理。看一个实例:假如这里module_init要接收的参数为s3c2410_uda1341_init这个函数,下面是这个函数的定义:

staticint __init s3c2410_uda1341_init(void){
 memzero(&input_stream,sizeof(audio_stream_t));
 memzero(&output_stream,sizeof(audio_stream_t));
 return platform_driver_register(&s3c2410iis_driver);
}

注意函数体的最后一行,它调用的是platform_driver_register这个函数。这个函数定义于driver/base/platform.c中,原型如下:

int platform_driver_register(struct platform_driver *drv)

它的功能就是为上面提到的plarform_driver中的driver这个结构中的probe、remove这些变量指定功能函数。

    到目前为止,内核就已经知道了有这么一个驱动模块。内核启动的时候,就会调用与该驱动相关的probe函数。我们来看一下probe函数实现了什么功能。

    probe函数的原型为

    int xxx_probe(struct platform_device *pdev)

    即它的返回类型为int,接收一个platform_device类型的指针作为参数。返回类型就是我们熟悉的错误代码了,而接收的这个参数呢,我们上面已经说过,驱动程序为设备服务,就需要知道设备的信息。而这个参数,就包含了与设备相关的信息。

    probe函数接收到plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。

    在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看在的设备文件了。举一个例子,在音频芯片的驱动中,就可以调用register_sound_dsp来注册一个dsp设备文件,lcd的驱动中就可以调用register_framebuffer来注册fb设备文件。这个工作完成以后,系统中就有我们需要的设备文件了。而和设备文件相关的操作都是通过一个file_operations 来实现的。在调用register_sound_dsp等函数的时候,就需要传递一个file_operations 类型的指针。这个指针就提供了可以供用户空间调用的write、read等函数。file_operations结构的定义位于include/linux/fs.h中,列出如下:

struct file_operations{
    struct module *owner;
    loff_t (*llseek)(struct file *, loff_t,int);
    ssize_t (*read)(struct file *,char __user *,size_t, loff_t*);
    ssize_t (*write)(struct file *,const char __user*, size_t, loff_t *);
    ssize_t (*aio_read)(struct kiocb*, const struct iovec *, unsignedlong, loff_t);
    ssize_t (*aio_write)(struct kiocb*, const struct iovec *, unsignedlong, loff_t);
    int (*readdir)(struct file *,void *, filldir_t);
    unsigned int(*poll)(struct file *,struct poll_table_struct *);
    int (*ioctl)(struct inode*, struct file *, unsignedint, unsigned long);
    long (*unlocked_ioctl)(struct file *,unsigned int,unsigned long);
    long (*compat_ioctl)(struct file *,unsigned int,unsigned long);
    int (*mmap)(struct file *,struct vm_area_struct *);
    int (*open)(struct inode*, struct file *);
    int (*flush)(struct file *, fl_owner_t id);
    int (*release)(struct inode*, struct file *);
    int (*fsync)(struct file *,struct dentry *,int datasync);
    int (*aio_fsync)(struct kiocb*, int datasync);
    int (*fasync)(int,struct file*, int);
    int (*lock)(struct file *,int, struct file_lock *);
    ssize_t (*sendpage)(struct file *,struct page *,int, size_t, loff_t *, int);
    unsigned long(*get_unmapped_area)(structfile *,unsigned long,unsigned long,unsigned long,unsigned long);
    int (*check_flags)(int);
    int (*dir_notify)(structfile *filp,unsigned longarg);
    int (*flock)(struct file *,int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info*, struct file *, loff_t *,size_t, unsigned int);
    ssize_t (*splice_read)(structfile *, loff_t*, struct pipe_inode_info *,size_t, unsigned int);
    int (*setlease)(structfile *,long, struct file_lock **);
};

    到目前为止,probe函数的功能就完成了。

    当用户打开一个设备,并调用其read、write等函数的时候,就可以通过上面的file_operations来找到相关的函数。所以,用户驱动程序还需要实现这些函数,具体实现和相关的设备有密切的关系,这里就不再介绍了。


原创粉丝点击