毕设中涉及到一个关于GPIO驱动的编程,在这里想总结一下,也想和大家分享一下。
  首先,开发平台是基于AT91RM9200的,主要是用该CPU去读取DS1820温度传感器的温度。至于DS1280这块芯片,我将在下面的文章中将有所介绍。GPIO(Gereral   Programable   Input   Output)就是通用可编程输入输出口。
  下面就总结一下,编写一个基于AT91RM9200的GPIO驱动的一些规则:
   (1)需要定义函数结构体,比如:static int at91_NETMAN_ioctl(struct inode *,struct file *,int,unsigned long);这种函数主要是定义在一个叫file_operations的大的结构体中的,file_operations该结构体整合了所有需要对模块进行操作的一些函数。   在驱动程序中, file_operations 是一个重要的结构体,通过它把针对设备的具体操作注册给内核的统一接口。结构体中全是函数指针, open release ioctl ,用于设备的打开与释放、设备的读写以及设备的控制。 编写驱动程序就是构造一系列可供应用程序调动的函数(包括 open release read write llseek ioctl 等)。在用户自己的驱动程序中,首先要根据驱动程序的功能,实现 file_operations 结构中的函数,不需要的函数接口可以直接 file_operations 结构中初始化为 NULL file_operations 变量会在驱动程序初始化时注册到系统内部。当操作系统对设备操作时,会调用驱动程序注册的 file_operations 结构中的函数指针。方法一:  S truct  file_operations {<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

                

int (*seek)  (struct inode * ,struct file *, off_t ,int);
                 int (*read)  (struct inode * ,struct file *, char ,int);

             

int (*write)   (struct inode * ,struct file *, off_t ,int)

            

int (*readdir)  (struct inode * ,struct file *, struct dirent * ,int);

            

int (*select) (struct inode * ,struct file *, int ,select_table *);

                 

int (*ioctl)  (struct inode * ,struct file *, unsined int ,unsigned long

                 

int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);

                  

int (*open)  (struct inode * ,struct file *);

                 

int (*release)  (struct inode * ,struct file *);

                 

int (*fsync) (struct inode * ,struct file *);

                 

int (*fasync)  (struct inode * ,struct file *,int);
};
定义方法二:首先需要定义 int 9200_ioctl(struct inode *,struct file *,int,unsigned long);
 然后调用上面的结构体struct file_operations   9200_file{
                                                                    ioctl:(void(*))9200_ioctl
};
在这种结构体中的每一个名称都对应着一个系统调用,用户进程利用系统调用,对主设备进行read和write等操作,系统调用通过设备文件的主设备号,找到相应的设备驱动程序,然后读取这个数据结构相应的函数,接着把控制权交给函数。
  (2)设置基地址:AT91PS_SYS 9200_sys= (AT91PS_SYS)AT91C_VA_BASE_SYS
  其中9200_sys是我自己定义的结构体名称,而AT91PS_SYS 是库函数定义的一个结构体, 其中9200_ SYS 是一个结构体,包含了 ATM9200 的所有寄存器,以上语句的功能就是把所有寄存器的最低地址赋值给9200_ SYS 这样结构体中的寄存器名称就和实际的地址对应起来了。注意:这里用到的地址都是经过映射过的虚拟地址,在实际运行中会通过处理器内部的 MMU 单元转换为实际的物理地址发往地址总线。
  (3)打开设备:int 9200_open(struct inode *inode, struct file *filp)  
                           {
                           MOD_INC_USE_COUNT;
                            return 0;
                            } 
其中9200_open应该已经在file_operations   中定义。 而MOD_INC_USE_COUNT语句实现的功能我将详细介绍一下:因为我们在写好一个驱动程序,则需要将我们的主设备作为一个模块加载到内核当中去的,所以其他的模块也可能会使用这个模块,MOD_INC_USE_COUNT就是用来增加当前使用该模块的进程。另外还有MOD_DEC_USE_COUNT这个主要是减少减少当前用户或进程的数目,这个主要是用在释放设备的时候用到。
  (4)释放设备:int 9200_close(struct inode *inode,struct file *filp)
                    {
                   MOD_DEC_USE_COUNT;
                    return 0;
同样,9200_close也是在file_operations  中定义的,
  (5)注册和注销驱动设备:
一个新的文件系统要加入系统,必须进行注册。那么,一个新的驱动程序要加入系统,也必须进行注册。在下一章我们会看到,我们把设备大体分为字符设备和块设备。字符设备的注册和注销调用register_chrdev()unregister_chrdev()函数。注册了设备驱动程序以后,驱动程序应该调用devfs_register()登记设备的入口点,所谓设备的入口点就是设备所在的路径名;在注销设备驱动程序之前,应该调用devfs_unregister()取消注册。
devfs_register()devfs_unregister() 函数原型为: devfs_handle_t devfs_register(devfs_handle_t dir, const char *name,unsigned int flags,unsigned int major, unsigned int minor,umode_t mode, void *ops, void *info)其中devfs_handle_t表示Devfs的句柄(一个结构类型),每个参数的含义如下:

dir : 我们要创建的文件所在的Devfs的句柄。NULL意味着这是Devfs的根,即 /dev

flags : 设备文件系统的标志,缺省值为DEVFS_FL_DEFAULT

major : 主设备号,普通文件不需要这一参数。

minor : 次设备号, 普通文件也不需要这一参数

mode : 缺省的文件模式(包括属性和许可权)。

ops : 指向 file_operations block_device_operations结构的指针

info : 任意一个指针,这个指针将被写到file结构的private_data域。

使用注册和注销的过程中需要使用到_init和_exit
  (6)主函数ioctl():
在这个函数中将对AT91RM9200管脚的设置,实现对外部设备的控制,这个也是最核心的东西。
 
  以上纯属个人的心得,希望对在学习CPIO驱动编程的朋友有所帮助。