Board logo

标题: Linux操作系统下PCI设备驱动程序开发 03 [打印本页]

作者: samwalton    时间: 2014-2-23 13:38     标题: Linux操作系统下PCI设备驱动程序开发 03

设备的打开与释放
  打开设备是通过调用file_operations结构中的函数open( )来完成的,它是驱动程序用来为今后的操作完成初始化准备工作的。在大部分驱动程序中,open( )通常需要完成下列工作:
  检查设备相关错误,如设备尚未准备好等。
  如果是第一次打开,则初始化硬件设备。
  识别次设备号,如果有必要则更新读写操作的当前位置指针f_ops。
  分配和填写要放在file->private_data里的数据结构。
  使用计数增1。
  释放设备是通过调用file_operations结构中的函数release( )来完成的,这个设备方法有时也被称为close( ),它的作用正好与open( )相反,通常要完成下列工作:
  使用计数减1。
  释放在file->private_data中分配的内存。
  如果使用计算为0,则关闭设备。
  设备的读写操作
  字符设备的读写操作相对比较简单,直接使用函数read( )和write( )就可以了。但如果是块设备的话,则需要调用函数block_read( )和block_write( )来进行数据读写,这两个函数将向设备请求表中增加读写请求,以便Linux内核可以对请求顺序进行优化。由于是对内存缓冲区而不是直接对设备进行操作的,因此能很大程度上加快读写速度。如果内存缓冲区中没有所要读入的数据,或者需要执行写操作将数据写入设备,那么就要执行真正的数据传输,这是通过调用数据结构blk_dev_struct中的函数request_fn( )来完成的。
  设备的控制操作
  除了读写操作外,应用程序有时还需要对设备进行控制,这可以通过设备驱动程序中的函数ioctl( )来完成。ioctl( )的用法与具体设备密切关联,因此需要根据设备的实际情况进行具体分析。
  设备的中断和轮询处理
  对于不支持中断的硬件设备,读写时需要轮流查询设备状态,以便决定是否继续进行数据传输。如果设备支持中断,则可以按中断方式进行操作。
  三、PCI驱动程序实现
  1. 关键数据结构
  PCI设备上有三种地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在启动时负责对所有PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件/proc/pci中列出所有找到的PCI设备,以及这些设备的参数和属性。
  Linux驱动程序通常使用结构(struct)来表示一种设备,而结构体中的变量则代表某一具体设备,该变量存放了与该设备相关的所有信息。好的驱动程序都应该能驱动多个同种设备,每个设备之间用次设备号进行区分,如果采用结构数据来代表所有能由该驱动程序驱动的设备,那么就可以简单地使用数组下标来表示次设备号。
  在PCI驱动程序中,下面几个关键数据结构起着非常核心的作用:
  pci_driver
  这个数据结构在文件include/linux/pci.h里,这是Linux内核版本2.4之后为新型的PCI设备驱动程序所添加的,其中最主要的是用于识别设备的id_table结构,以及用于检测设备的函数probe( )和卸载设备的函数remove( ):
  struct pci_driver {
  struct list_head node;
  char *name;
  const struct pci_device_id *id_table;
  int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
  void (*remove) (struct pci_dev *dev);
  int (*save_state) (struct pci_dev *dev, u32 state);
  int (*suspend)(struct pci_dev *dev, u32 state);
  int (*resume) (struct pci_dev *dev);
  int (*enable_wake) (struct pci_dev *dev, u32 state, int enable);
  };
  pci_dev
  这个数据结构也在文件include/linux/pci.h里,它详细描述了一个PCI设备几乎所有的硬件信息,包括厂商ID、设备ID、各种资源等:
  struct pci_dev {
  struct list_head global_list;
  struct list_head bus_list;
  struct pci_bus *bus;
  struct pci_bus *subordinate;
  void *sysdata;
  struct proc_dir_entry *procent;
  unsigned int devfn;
  unsigned short vendor;
  unsigned short device;
  unsigned short subsystem_vendor;
  unsigned short subsystem_device;
  unsigned int class;
  u8 hdr_type;
  u8 rom_base_reg;
  struct pci_driver *driver;
  void *driver_data;
  u64 dma_mask;
  u32 current_state;
  unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
  unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
  unsigned int irq;
  struct resource resource[DEVICE_COUNT_RESOURCE];
  struct resource dma_resource[DEVICE_COUNT_DMA];
  struct resource irq_resource[DEVICE_COUNT_IRQ];
  char name[80];
  char slot_name[8];
  int active;
  int ro;
  unsigned short regs;
  int (*prepare)(struct pci_dev *dev);
  int (*activate)(struct pci_dev *dev);
  int (*deactivate)(struct pci_dev *dev);
  };




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0