设为主页 | 加入收藏 | 繁體中文

如何编写Linux的设备驱动程序


  这就用到函数
  static int write_tibet(struct inode *inode,struct file *file,
  const char *buf,int count)
  {
  return count;
  }
  static int open_tibet(struct inode *inode,struct file *file )
  {
  MOD_INC_USE_COUNT;
  return 0;
  } static void release_tibet(struct inode *inode,struct file *file )
  {
  MOD_DEC_USE_COUNT;
  }
  verify_area.
  这几个函数都是空操纵
  提供函数指针。
  .实际挪用产生时什么也不做,他们仅仅为下面的结构
  struct file_operations test_fops = {
  NULL,
  read_test,
  write_test,
  NULL, /* test_readdir */
  NULL,
  NULL, /* test_ioctl */
  NULL, /* test_mmap */
  open_test,
  release_test, NULL, /* test_fsync */
  NULL, /* test_fasync */
  /* nothing more, fill with NULLs */
  };
  设置装备摆设驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序
  可以根据两种方法编译。一种是编译进
  kernel,另一种是编译成模块(modules),
  如果编译进内核的话,会增长内核的巨细,还要改动内核的源文件,而且不克不及
  动态的卸载,不利于调试,所以推荐利用模块方法。
  int init_module(void)
  {
  int result;
  result = register_chrdev(0, "test", &test_fops);
  if (result < 0) {
  printk(KERN_INFO "test: can't get major number ");
  return result;
  }
  if (test_major == 0) test_major = result; /* dynamic */
  return 0;
  }
  在用
  这里,
  设置装备摆设。
  零的话,体系将选择一个没有被占用的设置装备摆设号返回。参数二是设置装备摆设文件名,
  参数三用来注销驱动程序实际执行操纵的函数的指针。
  如果注销成功,返回设置装备摆设的主设置装备摆设号,不行功,返回一个负值。
  insmod命令将编译好的模块调入内存时,init_module 函数被挪用。在init_module只做了一件事,便是向体系的字符设置装备摆设表注销了一个字符register_chrdev需要三个参数,参数一是希望得到的设置装备摆设号,如果是
  void cleanup_module(void)
  {
  unregister_chrdev(test_major, "test");
  }
  在用
  rmmod卸载模块时,cleanup_module函数被挪用,它开释字符设置装备摆设test
  在体系字符设置装备摆设表中占据的表项。
  一个极端简单的字符设置装备摆设可以说写好了,文件名就叫
  下面编译
  test.c吧。
  $ gcc -O2 -DMODULE -D__KERNEL__ -c test.c
  得到文件
  如果设置装备摆设驱动程序有多个文件,把每个文件按下面的命令行编译,然后
  test.o便是一个设置装备摆设驱动程序。
  ld -r file1.o file2.o -o modulename.
  驱动程序曾经编译好了,现在把它安置到体系中去。
  $ insmod -f test.o
  如果安置成功,在
  /proc/devices文件中就可以看到设置装备摆设test,
  并可以看到它的主设置装备摆设号
  要卸载的话,运转
  ,。
  $ rmmod test
  下一步要创建设置装备摆设文件。
  mknod /dev/test c major minor
  c
  用
  是指字符设置装备摆设,major是主设置装备摆设号,便是在/proc/devices里看到的。shell命令
  $ cat /proc/devices | awk "\$2=="test" {print \$1}"
  就可以得到主设置装备摆设号,可以把下面的命令行参加你的
  shell script中去。
  minor
  我们现在可以经过设置装备摆设文件来拜访我们的驱动程序。写一个小小的测试程序。
  是从设置装备摆设号,设置成0就可以了。
  #include
  #include
  #include
  #include
  main()
  {
  int testdev;
  int i;
  char buf[10];
  testdev = open("/dev/test",O_RDWR);
  if ( testdev == -1 )
  {
  printf("Cann't open file ");
  exit(0);
  }
  read(testdev,buf,10);
  for (i = 0; i < 10;i++)
  printf("%d ",buf[i]);
  close(testdev);
  }
  编译运转,看看是不是打印出全
  以上只是一个简单的演示。真正实用的驱动程序要庞大的多,要处置惩罚如停止,
  1 ?
  DMA
  ,I/O port等题目。这些才是真正的难点。请看下节,实际情况的处置惩罚。
  如何编写Linux操纵体系下的设置装备摆设驱动程序
  Roy G
  三
  设置装备摆设驱动程序中的一些具体题目。
  1. I/O Port.
  在
  对恣意的
  误用端口。
  和硬件打交道离不开I/O Port,老的ISA设置装备摆设每每是占用实际的I/O端口,linux下,操纵体系没有对I/O口屏蔽,也便是说,任何驱动程序都可以I/O口操纵,这样就很容易引起杂乱。每个驱动程序应该本身避免
  有两个紧张的kernel函数可以包管驱动程序做到这一点。
  1
  )check_region(int io_port, int off_set)这个函数观察体系的I/O表,看能否有别的驱动程序占用某一段I/O口。
  参数1:io端口的基地点,
  参数2:io端口占用的范畴。
  返回值:0 没有占用, 非0,曾经被占用。
  2
  之前,必须向体系注销,以防止被其他程序占用。注销后,在
  )request_region(int io_port, int off_set,char *devname)如果这段I/O端口没有被占用,在我们的驱动程序中就可以利用它。在利用/proc/ioports
  文件中可以看到你注销的
  io口。
  参数1:io端口的基地点。
  参数2:io端口占用的范畴。
  参数3:利用这段io地点的设置装备摆设名。
  在对I/O口注销后,就可以担心肠用inb(), outb()之类的函来拜访了。
  于拜访一段内存。每每性的,我们要得到一块内存的物理地点。在
  (之所以不说是
  在是太简单,太不安全了)只需用段:偏移就可以了。在
  在一些pci设置装备摆设中,I/O端口被映射到一段内存中去,要拜访这些端口就相称dos环境下,dos操纵体系是因为我认为DOS根本就不是一个操纵体系,它实window95中,95ddk
  提供了一个
  在
  vmm 挪用 _MapLinearToPhys,用以把线性地点转化为物理地点。但Linux中是怎样做的呢?
  2
  内存操纵
  在设置装备摆设驱动程序中动态开发内存,不是用malloc,而是kmalloc,或者用
  get_free_pages
  直接请求页。开释内存用的是kfree,或free_pages. 请细致,
  kmalloc
  等函数返回的是物理地点!而malloc等返回的是线性地点!关于
  kmalloc
  地点的转换是由
  驱动程序异样也不克不及直接利用物理地点而是线性地点。但是事实上
  返回的是物理地点这一点自己有点不太明白:既然从线性地点到物理386cpu硬件完成的,那样汇编指令的操纵数应该是线性地点,kmalloc
  返回的确实是物理地点,而且也可以直接经过它拜访实际的
  以由两种表明,一种是在核心态克制分页,但是这好像不太实际;另一种是
  RAM,我想这样可
  linux
  不知对不对,还请高手指教。
  的页目录和页表项设计得正好使得物理地点等同于线性地点。我的想法
  结构占用了。
  言反正传,要细致kmalloc最大只能开发128k-16,16个字节是被页描述符kmalloc用法参见khg.内存映射的I/O口,存放器或者是硬件设置装备摆设的RAM(如显存)一般占用F0000000
  以上的地点空间。在驱动程序中不克不及直接拜访,要经过
  重新映射当前的地点。
  kernel函数vremap得到
  驻留在内存,不克不及被互换到文件中去。但是
  这可以经过牺牲一些体系内存的方法来解决。
  具体做法是:好比说你的呆板由
  另外,许多硬件需要一块比力大的连续内存用作DMA传送。这块内存需要一直kmalloc最多只能开发128k的内存。32M的内存,在lilo.conf的启动参数中加上
  mem=30M
  ,这样linux就认为你的呆板只有30M的内存,剩下的2M内存在vremap
  之后就可以为
  请记着,用
  DMA所用了。vremap映射后的内存,不用时使用unremap开释,否则会糜费页表。
  3
  停止处置惩罚
  同处置惩罚I/O端口一样,要利用一个停止,必须先向体系注销。
  int request_irq(unsigned int irq ,
  void(*handle)(int,void *,struct pt_regs *),
  unsigned int long flags,
  const char *device);
  irq:
  是要请求的停止。
  handle
  :停止处置惩罚函数指针。
  flags
  :SA_INTERRUPT 请求一个疾速停止,0 正常停止。
  device
  :设置装备摆设名。
  停止。
  如果注销成功,返回0,这时在/proc/interrupts文件中可以看你请求的
  4
  一些罕见的题目。
  的话,
  对硬件操纵,偶然时序很紧张。但是如果用C言语写一些低级的硬件操纵gcc每每会对你的程序进行优化,这样时序就错掉了。如果用汇编写呢,
  gcc
  办法是克制优化。这当然只能对一部门你本身编写的代码。如果对所有的代码
  都不优化,你会发现驱动程序根本无法装载。这是因为在编译驱动程序时要
  用到
  出来。
  异样会对汇编代码进行优化,除非你用volatile要害字修饰。最保险的gcc的一些扩展特性,而这些扩展特性必须在加了优化选项之后才能表现
  不胜感激。我一直都在
  关于kernel的调试东西,我现在还没有发现有符合的。有谁晓得请报告我,printk打印调试信息,倒也还拼集。
  我还不是很明白,不敢胡说。
  关于设置装备摆设驱动程序还有许多内容,如等待/唤醒机制,块设置装备摆设的编写等。
  接待各人品评指正。
 


    文章作者: 福州军威计算机技术有限公司
    军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
    版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。

TAG:
评论加载中...
内容:
评论者: 验证码: