Linux设备驱动工程师之路

转载 2012年03月30日 01:18:49
一、重要知识点

  1.I/O端口和I/O内存寄存器和常规内存的区别:寄存器和RAM主要不同在于寄存器有边际效果,读取某个地址时可能导致该地址的内容发生变化,比如说很多设备的中断状态寄存器只要一读取,便自动清0.所以硬件寄存器不能直接访问,而要通过I/O端口和I/O内存两种方式访问。

  在硬件层,I/O内存区域和I/O端口区域没有概念上的区别:它们都是通过向地址总线和控制总线发生电平信号进行访问,再通过数据总线读写数据。

  a.I/O端口:一些CPU制造厂在它们的芯片中使用单一的地址空间,而一些则为外设保留独立的地址空间,以便和内存区间分开来,这段独立与内存地址空间的地址空间就叫I/O端口。在/proc/ioport中可以看到。嵌入式处理器大部分不支持I/O端口。

  访问I/O端口有两步:1.申请I/O端口2.读写I/O端口申请I/O端口:structresource *request_region(unsigned long first, unsigned long n, const char *name)

  申请从first开始的n个端口。参数name为设备名称。如果分配成功则返回非NULL值。

  释放I/O端口:voidrelease_region(unsigned long start, unsigned long n)

  读写I/O端口:读写一个字节unsignedinb(unsigned port)

  voidoutb(usigned char byte, unsigned port)

  读写二个字节unsignedinb(unsigned port)

  voidoutb(usigned short byte, unsigned port)

  读写四个字节unsignedinb(unsigned port)

  voidoutb(usigned long byte, unsigned port)

  b.I/O内存通过将外设寄存器映射到内存空间来进行访问叫做I/O内存,嵌入式大多只支持这种操作。

  访问I/O内存有三步:1.申请I/O内存区域2.映射I/O内存区域3.读写I/O内存申请I/O内存区域structresource *request_mem_region(unsigned long start, unsigned long len, char *name)

  申请访问从start(I/O物理地址)开始的len长度的I/O内存区域,如成功则返回非NULL值。在/proc/iomem中可可以查看到已经被申请的I/O内存区域。在后面的我写的驱动程序中并没用使用申请这一步,是因为我使用的GPIO内存区域已经被申请,如果在申请会导致失败。但是这样做法是不安全的做法,因为同一I/O内存区域域被多个模块使用。

  释放I/O内存区域voidrelease_mem_region(unsigned long start, unsigned long len)

  映射I/O内存区域void*ioremap(unsigned long phy_addr, unsigned long size)

  映射从物理地址phy_addr开始的size长度的的地址空间。返回可以访问I/O内存地址。由ioreamp返回的地址不应该直接引用,必须通过下面一些列的读写函数完成。

  读写操作I/O内存读1、2、4个字节:unsignedint read8(void *addr);unsignedint read16(void *addr)

  unsignedint read32(void *addr)

  写读1、2、4个字节:voidiowrite8(u8 value, void *addr)

  voidiowrite16(u8 value, void *addr)

  voidiowrite32(u8 value, void *addr)

  2.混杂设备驱动在Linux系统中,存在一类字符设备,他们共享一个主设备号(10),但此设备号不同,我们称这类设备为混杂设备(miscdeivce),查看/proc/device中可以看到一个名为misc的主设备号为10.所有的混杂设备形成一个链表,对设备访问时内存根据次设备号找到对应的miscdevice设备。

  Linux内核使用structmiscdeivce来描述一个混杂设备structmiscdevice{ int minor;conststruct file_opreations *fops;structlist_head list;structdevice *parent;structdevice *this_device;}使用时只需填写minor次设备号,*name设备名,*fops文件操作函数集即可。

  Linux内核使用misc_register函数注册一个混杂设备。注册成功后,linux内核为自动为该设备创建设备文件。

  intmisc_register(struct miscdevice *misc)

  二、驱动代码

  1.驱动代码一这段LED驱动代码采用手动I/O内存映射的方式访问。没有使用申请内存区域函数,这样使不安全的。直接访问I/O内存地址而不是通过读写函数访问也是不安全。同时驱动代码包含硬件相关代码也是移植性不好的。写这段代码是为了帮助理解I/O内存映射的过程。

  view plain #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include

  volatile unsigned int long *gpb_con = NULL;volatile unsigned int long *gpb_data = NULL;

  static int leds_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)

  {

  if((cmd>1) |(arg>3))

  return-EINVAL;

  switch(cmd)

  { case 0:*gpb_data&= ~(1<

  default:return-EINVAL;

  }

  return 0;}

  static const struct file_operations leds_fops = {。owner = THIS_MODULE,。ioctl = leds_ioctl,};

  static struct miscdevice misc = {。minor =MISC_DYNAMIC_MINOR,。name ="my_leds",。fops =&leds_fops,};

  static int __init leds_init(void)

  { int ret;

  //注册混杂设备ret =misc_register(&misc);

  //映射I/O内存gpb_con = (volatileunsigned long *)ioremap(0x56000010, 16); //0x56000010为GPIOB控制寄存器的物理地址gpb_data = gpb_con+1;

  //配置LED对应的GPIOB 5、6、7、8口为输出并初始化为1,LED灭*gpb_con |=(1<<5*2)|(1<<6*2)|(1<<7*2)|(1<<8*2);*gpb_data |=(1<<5) | (1<<6) | (1<<7) | (1<<8);

  printk("ledsinit.\n");return ret;}

  static void leds_exit(void)

  {

  misc_deregister(&misc);

  printk("leds_exit\n");}

  module_init(leds_init);module_exit(leds_exit);

  MODULE_AUTHOR("Y-Kee");MODULE_LICENSE("GPL");

  2.驱动代码二:采用内核定义好的GPIO接口(S3C2410_GPB5和S3C2410_GPB5_OUTP)和GPIO操作函数(s3c2410_gpio_setpin和s3c2410_gpio_cfgpin)。可移植性好,也是正确的做法。内核的GPIO操作函数也是通过一些的运算将GPIO接口换算成虚拟内存地址然后进行访问的。

  view plain #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include

  static unsigned long led_table[] = { S3C2410_GPB5,S3C2410_GPB6,S3C2410_GPB7,S3C2410_GPB8,};

  static unsigned long led_cfg_table[] = { S3C2410_GPB5_OUTP,S3C2410_GPB6_OUTP,S3C2410_GPB7_OUTP,S3C2410_GPB8_OUTP,};

  static int leds_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)

  { if((cmd>1) |(arg>3))

  return-EINVAL;

  switch(cmd)

  { case 0:s3c2410_gpio_setpin(led_table[arg],0);break;case 1:s3c2410_gpio_setpin(led_table[arg],1);break;

  default:return-EINVAL;

  }

  return 0;}

  static const struct file_operations leds_fops = {。owner = THIS_MODULE,。ioctl = leds_ioctl,};

  static struct miscdevice misc = {。minor =MISC_DYNAMIC_MINOR,。name ="my_leds",。fops =&leds_fops,};

  static int __init leds_init(void)

  { int ret, i;

  //注册混杂设备ret =misc_register(&misc);

  //配置LED对应的GPIOB 5、6、7、8口为输出并初始化为1,LED灭for(i=0; i<4; i++)

  { s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);s3c2410_gpio_setpin(led_table[i],1);}

  printk("ledsinit.\n");return ret;}

  static void leds_exit(void)

  {

  misc_deregister(&misc);printk("leds_exit\n");}

  module_init(leds_init);module_exit(leds_exit);

  MODULE_AUTHOR("Y-Kee");MODULE_LICENSE("GPL");

java工程师进阶之路

java工程师进阶之路,努力学习20周,奠定CTO 下面是需要掌握的知识点:...
  • u011159417
  • u011159417
  • 2017年03月03日 17:18
  • 873

一个新java工程师的成长之路

首先,我并不是什么大牛,jinjin
  • b568648946
  • b568648946
  • 2014年09月03日 16:31
  • 803

从工程师到Leader成长之路

一、找准兴趣点:认识自己 作为新手程序猿,首先要清楚的认识到,从什么开始做起,才能让自己觉得,工作,是一件非常开心的事情! 作为技术工程师,能选择作为职业方向的也不少,比如: Web前端工程师(...
  • fish_study_csdn
  • fish_study_csdn
  • 2016年04月09日 22:36
  • 1076

java晋级之路--如何成为高级工程师

首先,先给大家讲述一下我个人的经历吧。 我虽然是软件工程专业,但是大学没学到啥东西,算是零基础了。找工作那会,就找了个培训班,简单学了下,极度勉强的情况下算是入门了。于是在北京开始寻找生涯中的第一份...
  • u011550710
  • u011550710
  • 2017年07月25日 20:42
  • 597

Java工程师发展之路

java高级程序员需要具备的知识如下: 1、语法:Java程序员必须比较熟悉语法,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息 知道是什么样的语法错误并且知道任何修正。 2、 命令:必...
  • mo_fan_qing_wa
  • mo_fan_qing_wa
  • 2016年07月18日 19:11
  • 662

Java工程师成神之路~

一、基础篇1.1 JVM1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id=133 http://ife...
  • chengfangang
  • chengfangang
  • 2015年12月11日 12:50
  • 2970

测试工程师成长之路

测试工程师 china development labs CDL简介 邮箱 了解测试的历史以及测试行业的发展 测试工作量是很轻吗?和coding相...
  • chengyangyy
  • chengyangyy
  • 2013年11月21日 17:58
  • 1321

工程师成长之路:工作1-3年工程师如何突破瓶颈期

本文转载自:http://bbs.csdn.net/topics/392036101 序 2013年03月02日, 我写了一篇博客(http://blog.csdn.net/lgg...
  • dlijun
  • dlijun
  • 2016年12月01日 09:30
  • 886

一个普通数据挖掘工程师的成长之路摘要

在搜索文献的过程中,我喜欢上了经济学人的《graphic details》栏目,发现他们绘制的图非常漂亮、专业,然后我就开始学习excel,尽自己所能将excel图表做的更漂亮更专业,这些经历为我日后...
  • zhouhaiqing0905
  • zhouhaiqing0905
  • 2015年11月05日 15:26
  • 1139

【大数据工程师之路】Hadoop——概述

一、Hadoop来历         在没有Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明了倒排...
  • gwblue
  • gwblue
  • 2015年02月23日 16:26
  • 10641
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux设备驱动工程师之路
举报原因:
原因补充:

(最多只允许输入30个字)