英特尔微处理器芯片 哪家芯片好 linux

当前位置:
基于Linux的嵌入式网络摄像机设计
本嵌入式网络摄像机采用高性能ARM9芯片微处理器,内置嵌入式Web服务器。通过嵌入式多任务操作系统采集摄像机视频数据;采集的视频信号数字化后经MJPEG算法压缩,再通过内部总线送到内置的Web服务器;使用者可以直接用浏览器观看Web服务器上的摄像机图像。
  引言&  基于同轴电缆的视频监控系统结构复杂、稳定性差、可靠性低且价格昂贵,因而出现了嵌入式网络摄像机等远程Web视频监控系统。本嵌入式网络摄像机,采用高性能的ARM9芯片作,内置嵌入式Web服务器&Boa,通过嵌入式多任务操作系统&Linux采集摄像机视频数据;摄像机采集的视频信号数字化后经MJPEG算法压缩,压缩后的视频流再通过内部总线送到内置的Web服务器;通过在网页中嵌入图像播放器,用户可以直接通过浏览器观看Web服务器上的摄像机图像;通过通用网关接口CGI,授权用户还可以控制摄像机、云台和镜头的动作或直接通过Web实现对系统进行配置。&  1 嵌入式网络摄像机系统原理及组成结构&  嵌入式网络摄像机的基本原理:在嵌入式Linux操作系统中内置Web服务器Boa,摄像机采集视频信号并将其数字化,经MJPEG压缩后,传送到内置的Web服务器,通过Web页面将视频信息发布到Internet。由于嵌入式网络摄像机是视频采集终端和Web服务器的融合,因此,用户可以直接通过浏览器观看摄像机拍摄的视频图像,达到远程监控的目的。  整个系统由视频采集模块、视频压缩模块、Web服务器、通用网关接口、Web页面等5个部分组成。 其硬件结构如图1所示:&    图1 嵌入式网络摄像机硬件结构图&  视频采集模块包括以S3C2410X为核心的中央控制和数据处理中心,以及USB Camera数据采集单元。中央控制和数据处理中心主要完成视频采集终端的控制和视频图像的压缩;Web服务器完成基本服务器的功能,负责响应HTTP请求,配合视频采集、压缩模块完成图像信息发布;通用网关接口&CGI,可以根据用户输入的数据信息,控制摄像机、云台和镜头的动作或直接通过Web实现对系统进行配置。  嵌入式微处理器是嵌入式系统的&硬核&。微处理器的选择将对整个嵌入式系统的成本和性能产生决定性的影响。目前,比较流行的处理器主要有:Power PC 、MIPS、Intel、ARM等。ARM(Advanced RISC Machines)公司是一家全球领先的嵌入式微处理器IP(Intellectual Property )核提供商,它设计了一系列高性能、低功耗、低成本和高可靠性的RISC处理器核、外围部件和系统级芯片应用解决方案。当前,ARM系列微处理器核广泛应用于便携式通讯设备、手持终端、多媒体数字消费产品等嵌入式系统解决方案中。本设计选用以ARM920T为核心的S3C2410X 32位微处理器,该处理器集成了LCD控制器、USB Host、USB Slave、NAND控制器、中断控制、功率控制、UART、SPI、SDI/MMC、IIS、GPIO、RTC、TIMER/PWM、ADC等丰富的资源。  操作系统是嵌入式系统的&软核&。早期的嵌入式系统,由于当时还没有操作系统的概念,系统的主要功能都是用汇编语言实现的,其兼容性、通用性及扩展性都很差。随着硬件性能不断提高,在嵌入式系统中使用通用操作系统已成为现实。在嵌入式系统中引入操作系统后,利用软件工程的思想指导嵌入式系统开发,其开发效率和资源可重用率都将得到很大的提高。目前较为流行的有:VxWorks、Neculeus、WindowsCE、Linux等。相对其它商业操作系统,Linux这个开源网络操作系统有以下独特优势:  (1) 价格低廉。在保证产品性能的前提下,价格永远都是系统设计时必须考虑的重用因素之一。由于Linux来源于开源社区,相对于其它商业操作系统,其价格几乎为零。  (2)文档丰富。全世界的Linux程序员都是技术顾问,任何人都可以在开源社区得到其系统所需要的文档和帮助。  (3)网络性能优良。与Unix一脉相承的Linux支持多种,并能够使系统长期稳定运行。  (4)知识创新。在国产操作系统中,嵌入式操作系统被认为是唯一可以赶超国外同行的操作系统。而Linux是操作系统中的佼佼者,任何人都可以遵照GPL规则发布包含自己知识产权的产品,可以高效地进行知识创新,少走弯路。  为此,本设计选用高性能ARM9芯片和嵌入式Linux操作系统。&
本文由入驻OFweek公众平台的作者撰写,除OFweek官方账号外,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
邮箱/用户名:
忘记密码?
用其他账号登录: QQ
请输入评论
四川省/成都市
广东省/深圳市
广东省/深圳市
广东省/深圳市
北京市/海淀区
广东省/深圳市
广东省/深圳市
广东省/惠州市
广东省/广州市
江苏省/无锡市
*文字标题:
*纠错内容:
联系邮箱:
*验 证 码:您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
《LINUX内存地址.》.pdf 40页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
需要金币:218 &&
《LINUX内存地址.》.pdf
你可能关注的文档:
··········
··········
第二章 内存寻址
本章介绍寻址技术。值得庆幸的是,操作系统自身不必完全了 物理内存;如今的微处理器包含的硬件线路
使内存管理既高效又健壮,所以编程错误就不会导致内存不正确的访问。
作为本书的一部分,本章将详细描述80x86 微处理器怎样进行芯片级的内存寻址,Linux 又是如何利用寻址
硬件的。我们希望当你学习内存寻址技术在Linux 最流行的硬件平台上的详细实现方法时,既能够更好地理
分页单元的一般原理,又能更好地研究内存寻址技术在其他平台上是如何实现的。
关于内存管理有三章,这是其中的第一章;还有第八章,讨论内核怎样给自己分配主存;以及第九章,考
虑怎样给进程分配线性地址。
程序员偶尔会引用内存地址 (memory
address )作为访问内存单元内容的一种方式,但是,当使用80x86 微
处理器时,我们必须区分以下三种不同的地址:
逻辑地址 (logical address )
包含在机器语言指令中用来指定一个操作数或一条指令的地址。这种寻址方式在80x86 著名的分段结构
中表现得尤为具体,它促使MS-DOS 或windows 程序员把程序分成若干段。每一个逻辑地址都由一个段
(segment)和偏移量 (off set 或disp lacement)组成,偏移量指明了从段开始的地方到实际地址之间的距
线性地址 (linear address )(也称虚拟地址virtual address)
是一个32 位无符号整数,可以用来表示高达4GB 的地址,也就是,高达4 294 967 296 个存储器单元。
线性地址通常用16 进制数字表示,值的范围从0x 到0xffffffff 。
物理地址 (p hy sical address )
用于内存芯片级内存单元寻址。它们与从微处理器的地址引脚发送到内存总线上的电信号相对应。物理
地址由32 位或36 位无符号整数表示。
内存控制单元 (MMU)通过一种称为分段单元 (segmentation unit)的硬件电路把一个逻辑地址转换成线性
地址;接着,第二个称为分页单元 (paging unit)的硬件电路把线性地址转换成一个物理地址 (见图2-1)。
图2-1:逻辑地址转换
在多处理机系统中,所有CPU 都共享同一内存;这意味着RAM 芯片可以由独立的CPU 并发地访问。因为在
RAM 芯片上的读或写操作必须串行地执行,因此一种所谓内存仲裁器 (memory arbiter)的硬件电路插入
在总线和每个RAM 芯片之间。其作用是如果某个RAM 芯片空闲,就准予一个CPU 访问,如果该芯片忙于为
另一个处理器提出的请求服务,就延迟这个CPU 的访问。即使在单处理器上也使用存储器仲裁器,因为单处
理器系统中包含一个叫做DMA 的特殊处理器,而DMA 与CPU 并发操作 (参见第十三章“直接存储器访问
(DMA)”一节“)。在多处理器系统的 况下,因为仲裁器有多个输入端口,所以其结构更加复杂。例如,
双Pentium 在每个芯片的入口维持一个两端口仲裁器,并在试图使用公用总线前请求两个CPU 交换同步信
息。从编程观点看,因为仲裁器由硬件电路管理,因此它是隐藏的。
硬件中的分段
从80286模式开始,Intel微处理器以两种不同的方式执行地址转换,这两种方式分别称为实模式(real mode)
和保护模式(protected mode) 。我们将从下一节开始描述保护模式下的地址转换。实模式存在的主要原因是要
维持处理器与早期模型兼容,并让操作系统自举(参阅附录一中针对实模式的简短描述) 。
段选择符和段寄存器
一个逻辑地址由两部分组成:一个段标识符和一个指定段内相对地址的偏移量。段标识符是一个16位长的字
段,称为段选择符(segment selector 见图2-2) ,而偏移量是一个32位长的字段。我们将在本章“快速访问段描
述符”一节描述断选择符字段。
图2-2:段描述符格式
为了快速方便地找到段选择符,处理器提供段寄存器,段寄存器的唯一目的是存放段选择符。这些段寄存器
称为cs ,ss ,ds ,es ,fs 和gs 。尽管只有6 个段寄存器,但程序可以把同一个段寄存器用于不同的目的,
方法是先将其值保存在存储器中,用完后再恢复。
6 个寄存器中3 个有专门的用途:
代码段寄存器,指向包含程序指令的段。
栈段寄存器,指向包含当前程序栈的段。
数据段寄存器,指向包含静态数据或者全局数据的段。
其它三个段
正在加载中,请稍后...bootloader&linux移植&USB驱动
TAIYUAN UNIVERSITY OF SCIENCE &
TECHNOLOGY
毕业设计(论文)说明书
题目:基于arm920t的bootloader 启动和USB驱动
学 生 姓 名&
&&&&&厉玉柱&&&&&&&&
&&&&自动化071501&&&
所 属 院 (系)电子信息工程学院&
指 导 教 师&
&&&&&&阎学文&&&&&&&
2011 年&& 06
月&& 10 日
太原科技大学毕业设计(论文)任务书
学院(直属系):&&&&&&&&&&&&&&&&&&&&&&&&&
时间:2011 年 3月5 日
学 生 姓 名
指 导 教 师
设计(论文)题目
基于arm920t的bootloader 启动和USB驱动
Linux系统的相关源码分析,裁剪成可以实现USB设备挂载的简单linux系统
启动源码分析移植:实现arm920t的cpu状态和各时钟的初始化,内存init,堆栈部分等继而能装载内核挂载文件系统以及网络模块的init
3& USB驱动实现
参照smdk2410的移植过程,移植u-boot-2009.08-rc1到my2440板。
根据已有的linux 2.6的源码分析内核,实现裁剪。
主要技术指标(或研究目标)
目标:可以在裸板上实现系统启动,且系统可以识别一般的USB设备。
教研室主任(专业负责人)签字:&&&&&&&&&
年& 月& 日&
说明:一式两份,一份装订入学生毕业设计(论文)内,一份交学院(直属系)。
本文研究了基于arm9的嵌入式系统和USB驱动的实现。首先简单介绍系统的硬件结构,即linux系统和驱动的实现开发板TQ2440。在系统上要完成编写启动代码,移植系统的内核等,为USB驱动开发搭建必须的系统平台。然后研究USB总线及内核与驱动设备之间的工作机制。包括两个层面:第一是从linux系统角度分析下线的驱动设备。第二是从上位机的角度分析linux系统作为一个单独的USB下线设备。本文内容主要涉及字符设备和块设备的驱动部分。
,USB驱动,arm9,模块
This paper based on the embedded system and arm9
USB drive realization. First, this article introduces the hardware
structure of the system, namely the Linux system and the
realization of the driver TQ2440 development board. On the system
to complete the writing code, transplant system startup kernel etc,
to build the USB driver development must be system platform. Then
the USB bus and the kernel and drive equipment work between
mechanism. Includes two aspects: the first is from Linux system
perspective of referrals drive equipment. The second is from the
perspective of the upper machine Linux system as a single USB line
equipment. This paper mainly on characters of the drive equipment
and equipment parts.
Key word: Linux, USB drive, arm9, modu
嵌入式系统
嵌入式操作系统(Embedded
System)是指以应用为中心,以计算机技术为基础,软件硬件可裁剪,适应应用系统对功能,可靠性,成本,体积,功耗严格要求的专用计算机系统。
嵌入式计算机在应用数量上远远超过了各种通用计算机,一台通用计算机的外部设备中就包含了5-10个嵌入式微处理器,键盘,鼠标,软驱,硬盘,显示卡,显示器,Modem,网卡,声卡,打印机,扫描仪,数字相机,USB集线器等均是由嵌入式处理器控制的。在制造工业,过程控制,通讯,仪器,仪表,汽车,船舶,航空,航天,军事装备,消费类产品等方面均是嵌入式计算机的应用领域。
嵌入式系统特点
嵌入式处理器的应用软件是实现嵌入式系统功能的关键,对嵌入式处理器系统软件和应用软件的要求也和通用计算机有所不同。
(1) 软件要求固态化存储
为了提高执行速度和系统可靠性, 嵌入式系统中的软件一般都固化在存储器芯片或单片机本身中,而不是存贮于磁盘等载体中。
(2) 软件代码高质量,高可靠性
尽管半导体技术的发展使处理器速度不断提高,片上存储器容量不断增加,但在大多数应用中,存储空间仍然是宝贵的,还存在实时性的要求。为此要求程序编写和编译工具的质量要高,以减少程序二进制代码长度,提高执行速度.序编写和编译工具的质量要高,以减少程序二进制代码长度,提高执行速度。
系统软件(OS)的高实时性是基本要求在多任务嵌入式系统中,对重要性各不相同的任务进行统筹兼顾的合理调度是保证每个任务及时执行的关键,单纯通过提高处理器速度是无法完成和没有效率的,这种任务调度只能由优化编写的系统软件来完成,因此系统软件的高实时性是基本要求。
&&linux是一个免费软件,并且公开源代码。多任务操作系统是知识集成的平台和走向工业标准化道路的由应用和发布linux在PC硬件上运行时,
linux是非常可靠和稳定的,特别是和想在流行的一些操作系统相比 嵌入式内核本身有多稳定呢?对大多数微处理器来说,
linux非常好。一直到新微处理器家族的linux内核运行起来与本来的微处理器一样稳定.他经常被一直到一个或多个特定的主板上.这些本包括特定的外围设备和CPU。linux提供C,C++,JAVA以及其他很多的开发工具。更重要的是,爱好者可以免费获得,并且这些开发工具设计时已经考虑到支持各种不同的微处理器结构和调试环境。
linux基于GNU的工具包,此工具包提供了完整与无缝交叉平台开发工具,从编辑器到底层调试其C编译器产生更有效率的执行代码。
处理器选择
嵌入式微处理器的基础是通用计算机中的CPU在应用中,将处理器装配在专门设计的电路板上,只保留和嵌入式应用有关的母板功能,这样可以大幅度减小系统体积和功耗。为了满足嵌入式应用的特殊要求,
嵌入式微处理器虽然在功能上和标准处理器基本是一样的,但在工作温度,成本,功耗,可靠性,健壮性等方面和工业控制计算机相比,
嵌入式微处理器具有体积小,重量轻,成本低,可靠性高的优点,但是在电路板上必须包括ROM,RAM,总线接口,各种外设等器件,从而降低了系统的可靠性,技术保密性也较差。嵌入式微处理器及其存储器,总线,外设,等安装在一块电路板上,称为单板计算机。如STD-BUS,PC104等。嵌入式处理器目前主要有国半X86,Dragon
Ball,ARM,Strong ARM,Power PC,68000,MIPS系列等。
本章小结:本章主要介绍了嵌入式系统的概念,介绍了linux系统和在嵌入式开发时的硬件选择。
上位机系统
Fedora Core 的前身就是Red Hat
Linux。支持多用户、多线程、多进程、实时性好、功能强大且稳定。有很完善的开发工具,能满足所有我们需要的开发应用。本次设计主要是以pc的linux系统为上位机进行交叉开发,我们利用fedora10上的交叉编译工具可以很顺利的完成bootloader和内核的.BIN文件的编译。由于我的设计还需要windows平台来分析源码,我就用了VMwear安装了fedora的虚拟机系统。虚拟机不影响我们的设计过程关于它的调度限制和我们的设计无关。当然windows上夜有交叉编译环境的,但是就arm平台的支持和方便性来讲linux具有天生的优势。特别是对于企业的产品开发,linux是一款完全免费的开源系统,不存在系统费用。由于linux的开源的原因,世界上很多优秀的程序员都可以参与到linux的开发中,使得它成为一个功能强大且发展速度无可比拟的实时操作系统。关于linux的优势我们不在多说。我们主要看看我们用的Fedora10平台的特色。它也是linux中的重要成员,并且有更好的kernel开放性,任何人都可以修改使用甚至发行它,它本身就是redhat的变种,对习惯redhat的人不会有操作上不便。
交叉编译工具
我们的硬件平台是arm9,那我们就用linux-arm的工具,版本为4.4.3的arm-linux-gcc,它能满足我们对bootloader和内核以及驱动配置部分的应用要求。安装了yaffs文件系统的工具和3.4.5的交叉编译器。有了这些编译环境我们就可以方便的移植1.1.6的U-boot和2.6.30.4的内核了。
在pc端主要用串口的超级终端方式与下线开发板进行实时通信。利用板子的次级USB线进行烧写。交叉连接软件有SecureCRT和dnw。SecureCRT是一个很好的连接工具,也就是功能更好,界面更好的超级终端。利用它以及串口,我们就能对开发板进行操作。由于它的界面友好,所以我们可以把它当做SHELL来使用,而且大部分的指令是兼容的。Dnm是USB下载软件,通过它我们能下载内核和应用到开发板,它是完成实验的重要工具。在使用连接工具前要把串口和USB下载线连接好。需要的驱动程序要按要求安装。
板级系统平台
要完成设计我们必须要为开发板选择一种好的合适的系统,这里我用的是2.6.30.4的内核。2.6的内核比2.4有了很多的升级,对于图像和声音的处理更好。加入了很多新的驱动。Linux 2.6 扩展多平台支持的一个主要途径就是把uClinux的大部并入了主流内核(mainstream kernel)。uCLinux(可以发音为"you-see-Linux",但更正确的拼写,首字母应该式希腊字母"mu")是将Linux应用在微控 制器平台的项目。很多年来,这个Linux分支为许多嵌入式芯片提供了支持,把它更多的集成到主流内核中是一件非常有意义的事。&下面介绍它的特点:
SMP效率:如果有工作需要完成,那么所有处理器都会工作。
  等待进程:没有进程需要长时间地等待处理器;同时,没有进程会无端地占用大量的CPU时间。
  SMP进程映射:进程只映射到一个CPU而且不会在CPU之间跳跃。
  优先级:不重要的任务的优先级低(反之亦然)。
  负载平衡:调度器会降低那些超出处理器负载能力的进程的优先级。
  交互性能:使用新的调度器,即便是在非常高负载的情况下,系统花费很长时间来响应鼠标或者键盘输入的情况将不会再发生。
本章小结:上面说明了毕设的软件平台和编译工具。这里主要的是编译工具,好的编译工具能让开发工作事半功倍。
RISC结构优先选取使用频最高的简单指令,避免复杂指令
RISC体系结构应具有如下特点:
  采用固定长度的指令格式,指令归整、简单、基本寻址方式有2~3种。使用单周期指令,便于流水线操作执行。大量使用寄存器,数据处理指令只对寄存器进行操作,加载/
存储指令,提高指令的执行效率。
  除此以外,ARM体系结构还采用了一些特别的技术,在保证高性能的前提下尽量缩小芯片的面积,并降低功耗:
  所有的指令都可根据前面的执行结果决定是否被执行,从而提高指令的执行效率。可用加载/存储指令批量传输数据,以提高数据的传输效率。可在一条数据处理指令中同时完成逻辑处理和移位处理。在循环处理中使用地址的自动增减来提高运行效率。
处理器介绍
ARM920T有16K的数据Cache和16K的指令Cache,这两个Cache是基本相同的,数据Cache多了一些写回内存的机制,后面我们以数据Cache为例来介绍Cache的基本原理。我们已经知道,Cache中的存储单位是Cache
Line,ARM920T的一个Cache Line是32字节,因此16K的Cache由512条Cache
Line组成。ARM9TDMI将流水线的级数从ARM7TDMI的3级增加到5级,并使用分开的指令与数据存储器的哈佛(Harvard)体系结构,
因此简单的总线接口很容易连接Cache或SRAM存储器系统。ARM9TDMI支持与外部存储器的双向或单向连接,支持调试结构。ARM9TDMI的性能在相同工艺条件下近似达到ARM7TDMI两倍。
3.2.1 ARM9TDMI的特点
&& 支持Thumb指令集;
&& 含有EmbeddedICE模块支持片上调试;
&& 通过采用5级流水线以增加最高时钟速率;
分开的指令与数据存储器端口以改善CPI,提高处理器性能。
3.2.2 流水线操作
ARM9TDMI的5级流水线的操作见图3.3,图中与ARM7TDMI采用的3级流水线进行了比较。该图显示出处理器的主要处理功能及如何在流水线级增加时重新分配执行,以便使时钟频率在相同工艺技术的条件下能够加倍(近似)。重新分配执行功能(寄存器读、移位、ALU、寄存器写)并不是达到高时钟频率所需的全部。处理器还须能在ARM7TDMI所用的一半时间内访问指令存储器,并重新构造指令译码逻辑,是寄存器读与实际的译码同时进行。
&&&&&&&&&&&&&&&&&&&&&&
CPU的结构图&&&
3.2.3 协处理器
ARM9TDMI还有一个协处理器接口,可支持片上浮点协处理器、数字信号处理或其他专业硬件加速等。
3.2.4 ARM处理器模式
用户模式(User):ARM处理器正常的程序执行状态
快速中断模式(FIQ):用于高速数据传输或通道处理
外部中断模式(IRQ):用于通用的中断处理
管理模式(Supervisor):操作系统使用的保护模式
数据访问终止模式(Abort):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护
系统模式(System):运行具有特权的操作系统任务
未定义指令中止模式(Undifined):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真
微处理器的寄存器结构
  ARM处理器共有37个寄存器,被分为若干个组(BANK),这些寄存器包括:31个通用寄存器,包括程序计数器(PC指针),均为32位的寄存器。6个状态寄存器,用以标识CPU的工作状态及程序的运行状态,均为32位,目前只使用了其中的一部分。
同时,ARM处理器又有7种不同的处理器模式,在每一种处理器模式下均有一组相应的寄存器与之对应。即在任意一种处理器模式下,可访问的寄存器包括15个通用寄存器(R0~R14)、一至二个状态寄存器和程序计数器。在所有的寄存器中,有些是在
7种处理器模式下共用的同一个物理寄存器,而有些寄存器则是在不同的处理器模式下有不同的物理寄存器。
图2 ARM寄存器分配情况
此图给出了在不同工作模式下的及存取器使用情况。(这里做一些特别说明:我们看到arm的每种操作模式下都对应了丰富的寄存器组,这就是为什么说arm处理器有高效率的原因之一。)
处理器的指令结构
ARM微处理器的在较新的体系结构中支持两种指令集:ARM指令集和Thumb指令集。其中,ARM指令为32位的长度,Thumb指令为16位长度。Thumb指令集为ARM指令集的功能子集,但与等价的ARM代码相比较,可节省30%~40%以上的存储空间,同时具备32位代码的所有优点。
内存为64兆,可以满足几乎所有的实验要求。还有512+2兆的flash存储区。在下面的研究中会用到nadaflash的启动方式和norflash的下载启动方式。这里解释两种flash不同作用的原因:
Flash又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还可以快速读取数据(NVRAM的优势),使数据不会因为断电而丢失。NOR
Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR
FLASH里面的代码,这样可以减少SRAM的容量从而节约了成本。NAND
Flash没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND
Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flash以外,还作上了一块小的NOR
Flash来运行启动代码。
:主要介绍了设计的硬件平台。Arm9的结构和特点另外介绍板上的存储器部分。其他的外设部分没有介绍,主要是它们和我们的设计无关。
大家都知道,一个系统的运行的开始必然是系统的初始化,至于初始化的是什么我在下面会详细讲解。相比简单的片上系统,具有多任务的实时运行的系统就需要更高级的软件管理部分——操作系统。操作系统让我们可以把系统的能力成倍扩张。有了操作系统的板级设备可以看做是一个配置较低的pc设备。那么操作系统的初始化不再是简单的硬件初始化,还要实现系统的挂载和权限的转交过程。我们大家都很熟悉windows下的BOIS,在系统启动时我们就可以进入BOIS。它就是一个windows下的启动软件。我们在linux系统下的bootloader一般就用U-boot。当然linux提供了丰富的启动程序选择,但是U-boot功能更强大,代码更简洁,关键是它很适合我们的板级的linux设备。并且它也是开放的源码。比如在实现时我们可以让它对于使用者是一个透明过程,也可以在启动的过程中添加启动的选项。总之,万丈高楼平地起,而对于linux而言,U-boot就是最重要的地基。
U-boot启动内核分为两个阶段,两个阶段的功能如下:
1.第一阶段u-boot的stage1代码通常放在cpu/xxxx/start.S文件中,他用汇编语言写成。硬件设备初始化,具体包括cpu工作状态初始化,中断设置,设置中断向量,设置控制寄存器地址,准备RAM空间便下一阶段的加载。加载U-boot第二阶段的代码到RAM空间堆栈设置等工作。这些是位了下一步跳转做准备。Stage1主要是最最的基础硬件初始化。
2.第二阶段即stage2.它的功能是初始化本阶段使用的硬件设备,检测系统内存映射,将内核从Flash读取到RAM中,为内核设置启动参数,调用内核。这段代码是用c语言编写的。
& 主要的函数分析
&&第一段启动代码对应的文件cpu/arm920t/star.S和board/Samsung/l
Iyuzhu2440/lowlevel_init.S。这里又有问题了,为什么是这两个文件却不是其他文件作为第一阶段的代码文件呢?下面将说明。
4.3.1 链接文件
这是因为在U-boot中的cpu/arm920t/u-boot.lds文件。它主要负责安排整个U-boot代码的执行顺序管理。
&&从下面的函数内容可以看出首先执行的文件是star.S。这里特别注意,地址0x0是启动的其实地址,而它被定义在了star.S上。
ENTRY(_start)
. = ALIGN(4);
cpu/arm920t/start.o&& (.text)
&board/samsung/mini2440/lowlevel_init.o
board/samsung/mini2440/nand_read.o (.text)
& 4.3.2第一部分代码介绍
那么接下来就是star.S发挥作用的时候了。它就是前面说的stage1部分
系统复位位转到u-boot的stage1入口
设置异常向量表
设置cpu速度,时钟频率和中断控制器
初始化内存控制器
拷贝u-boot的stage2代码到RAM
设置堆栈,初始化数据段
图3& Stage1的star.S的程序流程图
开始的中断向量是Arm的结构规定。ARM体系结构规定在上电复位后的起始位置,必须有8条连续的跳转指令,通过硬件实现。他们就是异常向量表。ARM在上电复位后,是从0x开始启动的,其实如果bootloader存在,在执行下面第一条指令后,就无条件跳转到start_code,下面一部分并没执行。设置异常向量表的作用是识别bootloader。以后系统每当有异常出现,则CPU会根据异常号,从内存的0x处开始查表做相应的处理。
中断向量表:
ldr pc, _undefined_instruction 0x04
&ldr pc, _software_interrupt&
&ldr pc, _prefetch_abort&
_data_abort&& 0x10
_not_used&& 0x14
_irq&&& 0x18
_fiq&&& 0x1c
时钟设置部分:
&S3C2440有三个时钟FLCK、HCLK和PCLK。这三个时钟通常设置为1:4:8,1:3:6的分频关系,也就说如果主频FLCK是400MHz,按照1:4:8的设置,那么HLCK是100MHz,PLCK是50MHz。
这里还要解释为什么要先关闭和屏蔽,因为arm一般是在都是在关闭的情况下设置,拿看门狗来说,启动过程中不关闭它,就会有严重问题,系统会不停的重启。
.3 第二部分代码start_armboot
初始化flash 初始化内存
初始化nand 显示 网络等设备
将内核和根文件系统从flash映射到ram
设置内核启动参数和调用内核
Stage2开始
图4 stage2 即start_armboot程序流程图
上面的初始化过程要靠gd_t结构体bd_t结构体init_sequence数组协作完成。
结构体gd_t来存储全局数据区的数据,U-Boot启动内核时要给内核传递参数,这时就要使用gd_t,bd_t结构体中的信息来设置标记列表。数组init_sequence来存储对于大多数开发板都要执行的初始化函数的函数指针。设置好上面三个结构就能完成进入start_armboot函数的所有初始化设置了。
4 .3.4 主要初始化流程
Board_init& 开发板的相关配置
Timer_init&&
时钟初始化
Env_init&&
初始化环境变化
Init_baudrate& 串口控制台初始化
Serial_init
Console_init_f
Display_banne&
打印U-boot版本,编译时间
Dram_init&&&
配置可用的ram,显示ram的大小
Display_dram_config
Flah_init&&&&
nor flash初始化
Nand_init&&&
nandflash初始化
Main_loop&&&
调用main_loop
我们注意到最后的main_loop函数是完成最后的检查,检查的内容就是相关的环境变量。如果未设置就要求用户输入字符。&
&& 挂载内核
&U-Boot使用命令bootm来启动已经加载到内存中的内核。而bootm命令实际上调用的是do_bootm函数。对于Linux内核,do_bootm函数会调用do_bootm_linux函数来设置标记列表和启动内核。do_bootm_linux函数在lib_arm/bootm.c
中定义。do_bootm()是bootm命令真正执行的第一个函数
主要功能 :
1. 复制Image(这里指的是uImage) 头到全局变量header;
2. 检查header的magic number是否正确,检查header和image各自的校验和是否正确;
3. 检查image的体系架构和类型(kernel or MULTI)
4. 将内核zImage搬移到image头中指定的内核加载地址ih_load
调用u-boot-1.3.1/lib_arm/armlinux.c中的do_bootm_linux()函数,将传递给内核的参数存放在指定的内存位置,然后执行thekernel(0,...,...)跳转到内核入口点(ih_ep=0x)执行,控制权交给内核,u-boot执行完毕。完成了寄存器的设置,最后转到内核的入口地址,到这里,U-Boot的工作就结束了,系统跳转到Linux内核代码执行。
本章小结:这一知道内容时分的关键,主要阐述了bootloader的构架和过程。它是开始系统的关键。Bootloader主要是两部分功能函数,第一部分主要是平台和硬件的基本初始化,第二部分是更高级的板级和环境的初始化。到了内核权限的转交启动部分的任务就完成了。
&对于我这样一个没有多少开发经验的学生来说,在移植的过正中确确实实遇到了许多困难的地方。这里我就自己的情况谈一点心得。
&首先要有linux系统的基础知识不用说了。重要的是事情就是要了解我们要移植的系统源码的布局。当然不同系统源码有很多,我在这里选择的是2.6.30.4的源码。原因很简单,就是源码下载方便,相关的资料也很丰富。其次要了解自己要移植的平台的情况。堆在源码中做修改时能理解。
&移植的过程并不是机械的修改源码,而是要有一个系统的概念即能从整体上把握系统移植的构架。然后在细化到每一个需要移植的部分。这里还要说,一个系统源码在真正跑起来之前,几乎所有的部分都是需要我们来修改的。
&移植的过程一定是错误不断的,坚持下来就不怕了。
&另外对系统配置过程是重中之重。配置的方法也很多,我用的是比较友好的make_menuconfig的可视化配置。
&最后要说的就是编译环境。前面的时候已经重点说了编译环境的重要性。为什么要反复强调,就是因为编译的过程让我觉得很挑剔,没有合适的编译环境你别谈移植。
&获取和解压源码就不说了,这里涉及的都是简单的操作而已。
&我们用的是arm平台,所以首先要添加对arm的支持。在第一次使用make_menuconfig时添加make
ARCH=arm CROSS_COMPILE=arm-linux- menuconfig。
&满足我们用的TQ2440的时钟。制作TQ2440的配置单和对EABI的支持。我在移植时调用了已经存在的2410的配置单做修改。
打开配置单,在配置单菜单中选择选项:Load an Alternate Configuration
File。然后输入要调用的配置单,OK即可。回到初始界面然后按如下要求配置:
System type ---&
S3c2410 machines ---&
&&&&&&&&&&&
&&&&&&&&&&&
[ ]IPAQ H1940
&&&&&&&&&&&
[ ]Acer N30
&&&&&&&&&&&
[ ]Simtec Electronices BAST (EB2410ITX)
&&&&&&&&&&&
[ ]NextVision OTOM Board
&&&&&&&&&&&
[ ]AML M5900 Series
&&&&&&&&&&&
[ ]Thorcom VR1000
&&&&&&&&&&&
S3C2412 Machines ---&
&&&&&&&&&&&
[ ]SMDK2413
&&&&&&&&&&&
[ ]SMDK2412
&&&&&&&&&&&
S3C2440 Machines ---&
&&&&&&&&&&&
[ ]Simtec Electronics ANUBIS
&&&&&&&&&&&
[ ]Simtec IM2440 (OSIRIS)module
&&&&&&&&&&&
[ ]HP Ipaq rx3715
&&&&&&&&&&&
[*]SMDK2440
&&&&&&&&&&&
[ ]NexVision NEXCODER2440 Light Board
&&&&&&&&&&&
[*]SMDK2440 with S3c2440 CPU module
S3C2442 Machines ---&
&&&&&&&&&&&
[ ]SMDK2440 with S3C2442 CPU module
S3C2443 Machines ---&
&&&&&&&&&&&
[ ]SMDK2443
支持EABI:
Kernel Features ---&
Memory split (3G/1G user/kernel split) ---&
[ ]Preemptible Kernel (EXPERIMENTAL)
&&[*]Use the ARM EABI to compile
the kernel
[*] Allow old ABI binaries to run with this kernel
(EXPERIMENTAL)
[ ]High Memory Support (EXPERIMENTAL)
Memory modul (Flat Memory) ---&
[ ]Add LRU list to track non-evictable pages
(4096)Low address space to protect from user allocatin
这里有一点要注意,就是前面我们支持U-boot是的机器码是168,所以我们在系统移植时也要修改机器码为168.修改的部分在内核源码的arch/arm/mach-s3c2440/mach-smdk2440.c的MACHINE_START(S3C2440,”SMDK2440”)中。
&&到这里我们的移植第一步已经完成。编译镜像下载到开发板就可以在超级终端看到内核的信息了。
&这部分的驱动我们不用全部编写,因为内核中已经有了nandflash的驱动,但是它不能满足我们要求,要做必要的修改。
如下(arch/arm/plat-s3c24xx/common-smdk.c):
&& Static struct mtd_partition
smdk_default_nand_part[]={
&&&&&&&&&&&&
=”EmbedSky_Board_uboot”,
&&&&&&&&&&&&&
.offset& =0x,
&&&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&&&&
.name& =”EmbedSky_Board_kernel”,
&&&&&&&&&&&&&
.offset& =0x,
&&&&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&&&&
.name& =”EmbedSky_Board_yaffs2”,
&&&&&&&&&&&&&
.offset& =0x,
&&&&&&&&&.size&&&
=MTDPART_SIZE_FULL,
&&&&&&&&&&&&
Static struce s3c2410_platform_nand smdk_nand_info ={
.tacls&&&&
.twrph0&& =25,
.twrph1&& =10,
.nr_sets =ARRATY_SIZE(smdk_nand_sets),
.sets&& =smdk_nand_sets,
添加驱动配置:
Decice Drivers ---&
& &*&Memory
Technology Device(MTD)support ---&
[*]& MTD partitioning support
RedBoot partition table parsing
[]&& Command line partition
&*&& Direct chat
device access toMTD devices
-*-&& Common interface to block
layer for MTD translation layers
&*&& Cahing block
device access to MTD device
&*&& NAND Device
Support ---&
&*&& NAND Flash
support for S3C0 SoC
[ ]AS3C2410 NAND Hardware ECC
编译完成。
&到这里,我们的系统就可以在以上的配置基础上运行了。不过,现在的系统还没有任何的内容。也即是在直观上看不到任何linux的影子。接下来我们就挂载文件系统,是这个系统用它的架构。
&我们用比较好yaffs2作为例子。选择用来制作文件系统的软件busy-box。它可以直接生产一个
yaffs2的文件系统出来,当然这个文件系统是不完整的,因为我们的开发环境不是确定的,所以busy-box生产的文件系统知识一个框架。我们在这个框架下填充完成我们自己的文件系统。因为安装busy-box工具也是很繁琐的一件事,一一类聚会占用很大的篇幅,所以我们默认工具已经安装调试成功。
5.4.1 Busy-box生成文件系统:
&&&&&&&&&&&&&&&内容
bin 存放所有用户都可以使用的、基本的命令。
sbin 存放的是基本的系统命令,它们用于启动系统、修复系统等。
usr 里面存放的是共享、只读的程序和数据。
proc 这是个空目录,常作为proc文件系统的挂载点。
dev 该目录存放设备文件和其它特殊文件。
etc 存放系统配置文件,包括启动文件。
lib 存放共享库和可加载块(即驱动程序),共享库用于启动系统、运行根文件系统中的可执行程序。
boot 引导加载程序使用的静态文件
home 用户主目录,包括供服务账号锁使用的主目录,如FTP
mnt 用于临时挂接某个文件系统的挂接点,通常是空目录。也可以在里面创建空的子目录。
opt 给主机额外安装软件所摆放的目录。
&root用户的主目录
tmp 存放临时文件,通常是空目录。
var 存放可变的数据。
5.4.2 添加对yaffs2文件系统的支持
和前面的内核裁剪是一样的,我们要在配置单中添加对文件系统的支持。
Filesystem---&
Miscellaneous&filesystems---&
file&system&support
Lets&Yaffs&do&its&own&ECC
Native&language&support
&*&&Codepage&437&(United&States,Canada)
&*&Simplified&Chinese&charset(GB2312)
&*&Traditional&Chinese&charset(Big5)
&*&NLS&ISO&8859-1(Latin1:Western&European&Languages)
&*&NLS&UTF-8
make&zImage&;之后我们就能在超级终端上查看到重新启动的linux上有文件系统的内容。
5.4.3 建立根文件系统目录
进入到/opt/studyarm目录,新建建立根文件系统目录的脚本文件create_rootfs_bash,使用命令chmod&+x&create_rootfs_bash改变文件的可执行权限,./create_rootfs_bash运行脚本,就完成了根文件系统目录的创建。
echo&"------Create&rootfs&directons&start...--------"
mkdir&rootfs
echo&"--------Create&root,dev....----------"
mkdir&root&dev&etc&boot&tmp&var&sys&proc&lib&mnt&home
mkdir&etc/init.d&etc/rc.d&etc/sysconfig
mkdir&usr/sbin&usr/bin&usr/lib&usr/modules
echo&"make&node&in&dev/console&dev/null"
mknod&-m&600&dev/console&c&5&1
mknod&-m&600&dev/null&&&&c&1&3
mkdir&mnt/etc&mnt/jffs2&mnt/yaffs&mnt/data&mnt/temp
mkdir&var/lib&var/lock&var/run&var/tmp
chmod&1777&tmp
chmod&1777&var/tmp
echo&"-------make&direction&done---------"
改变了tmp目录的使用权,让它开启sticky位,为tmp目录的使用权开启此位,可确保tmp目录底下建立的文件,只有建立它的用户有权删除。尽管嵌入式系统多半是单用户,不过有些嵌入式应用不一定用root的权限来执行,因此需要遵照根文件系统权限位的基本规定来设计。
5.4.4 建立动态链接库
动态链接库直接用友善之臂的,先解压友善之臂的根文件包,拷贝lib的内容到新建的根文件目录lib内。
cd&/mnt/hgfs/share
tar&&zxvf&root_qtopia.tgz&&C&/opt/studyarm
cp&&rfd&/opt/studyarm/root_qtopia/lib
MODULE_DEVICE_TABLE (usb, skel_table);
#define USB_SKEL_MINOR_BASE
&&& struct
usb_device *
&&&&&&&&&&
&&& struct
usb_interface *
&&& unsigned
bulk_in_&&&&
size_t&&&&&&&&&
bulk_in_&&&&&&
__u8&&&&&&&&&&&
bulk_in_endpointA&&
__u8&&&&&&&&&&&
bulk_out_endpointA
&&& struct
#define to_skel_dev(d) container_of(d, struct usb_skel,
static struct usb_driver skel_
static void skel_delete(struct kref *kref)
struct usb_skel *dev = to_skel_dev(kref);
usb_put_dev(dev-&udev);
(dev-&bulk_in_buffer);
static int skel_open(struct inode *inode, struct file *file)
{&&& struct
usb_skel *
&&& struct
usb_interface *
&&& int retval =
&&& subminor =
iminor(inode);
&&& interface =
usb_find_interface(&skel_driver, subminor);
(!interface) {
err ("%s - error, can't find device for minor %d",
&&&&&&&&&&&&
__FUNCTION__, subminor);
retval = -ENODEV;
usb_get_intfdata(interface);
&&& if (!dev)
retval = -ENODEV;
kref_get(&dev-&kref);
file-&private_data =
&&& return
} static int skel_release(struct inode *inode, struct file
&&& struct
usb_skel *
(struct usb_skel *)file-&private_
&&& if (dev ==
return -ENODEV;
kref_put(&dev-&kref,
skel_delete);
&&& return
static ssize_t skel_read(struct file *file, char *buffer, size_t
count, loff_t *ppos)
&&& struct
usb_skel *
&&& int retval =
(struct usb_skel *)file-&private_
&&&&&&&&&&&
retval = usb_bulk_msg(dev-&udev,
&&&&&&&&&&&&&&&&&
usb_rcvbulkpipe(dev-&udev,
dev-&bulk_in_endpointAddr),
&&&&&&&&&&&&&&&&&
dev-&bulk_in_buffer,
&&&&&&&&&&&&&&&&&
min(dev-&bulk_in_size, count),
&&&&&&&&&&&&&&&&&
&bytes_read, 10000);
if (!retval) {
if (copy_to_user(buffer, dev-&bulk_in_buffer,
bytes_read))
&&&&&&&&&&&
retval = -EFAULT;
&&&&&&&&&&&
retval = bytes_
&&& return
static void skel_write_bulk_callback(struct urb *urb, struct
pt_regs *regs)
&&& struct
usb_skel *
(struct usb_skel *)urb-&
(urb-&status
!(urb-&status == -ENOENT
urb-&status == -ECONNRESET ||
urb-&status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
&&&&&&&&&&&
__FUNCTION__, urb-&status);
usb_buffer_free(urb-&dev,
urb-&transfer_buffer_length,&&
&&&&&&&&&&&
urb-&transfer_buffer,
urb-&transfer_dma);
static ssize_t skel_write(struct file *file, const char
*user_buffer, size_t count, loff_t *ppos)
&&& struct
usb_skel *
&&& int retval =
&&& struct urb
*urb = NULL;
&&& char *buf =
(struct usb_skel *)file-&private_
if (count ==
usb_alloc_urb(0, GFP_KERNEL);
&&& if (!urb)
retval = -ENOMEM;
usb_buffer_alloc(dev-&udev, count, GFP_KERNEL,
&urb-&transfer_dma);
&&& if (!buf)
retval = -ENOMEM;
(copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
usb_fill_bulk_urb(urb, dev-&udev,
&&&&&&&&&&&&&
usb_sndbulkpipe(dev-&udev,
dev-&bulk_out_endpointAddr),
&&&&&&&&&&&&&
buf, count, skel_write_bulk_callback,
dev);//初始化&&
urb-&transfer_flags |=
URB_NO_TRANSFER_DMA_MAP;
&&& retval =
usb_submit_urb(urb, GFP_KERNEL);
(retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__,
usb_free_urb(urb);
&&& return
usb_buffer_free(dev-&udev, count, buf,
urb-&transfer_dma);
usb_free_urb(urb);
&&& return
static struct file_operations skel_fops = {
&&& .owner
THIS_MODULE,
skel_read,
&&& .write
skel_write,
skel_open,
&&& .release =
skel_release,
static struct usb_class_driver skel_class = {
"usb/skel%d",
&skel_fops,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
&&& .minor_base
=&& USB_SKEL_MINOR_BASE,
static int skel_probe(struct usb_interface *interface, const struct
usb_device_id *id)
&&& struct
usb_skel *dev = NULL;
&&& struct
usb_host_interface *iface_
&&& struct
usb_endpoint_descriptor *
&&& size_t
&&& int retval =
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
&&& if (dev ==
err("Out of memory");
&&& memset(dev,
0x00, sizeof(*dev));
kref_init(&dev-&kref);
dev-&udev =
usb_get_dev(interface_to_usbdev(interface));
dev-&interface =
iface_desc = interface-&cur_
&&& for (i = 0;
i & iface_desc-&desc.bNumE
endpoint =
&iface_desc-&endpoint[i].
if (!dev-&bulk_in_endpointAddr
&&&&&&&&&&&
((endpoint-&bEndpointAddress &
USB_ENDPOINT_DIR_MASK)
&&&&&&&&&&&&&&&&&&&
== USB_DIR_IN) &&
&&&&&&&&&&&
((endpoint-&bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK)
&&&&&&&&&&&&&&&&&&&
== USB_ENDPOINT_XFER_BULK)) {
&&&&&&&&&&&&&&&&&&&&&&
buffer_size =
le16_to_cpu(endpoint-&wMaxPacketSize);
&&&&&&&&&&&
dev-&bulk_in_size = buffer_
&&&&&&&&&&&
dev-&bulk_in_endpointAddr =
endpoint-&bEndpointA
&&&&&&&&&&&
dev-&bulk_in_buffer = kmalloc(buffer_size,
GFP_KERNEL);
&&&&&&&&&&&
if (!dev-&bulk_in_buffer) {
&&&&&&&&&&&&&&&
err("Could not allocate bulk_in_buffer");
&&&&&&&&&&&&&&&
&&&&&&&&&&&
if (!dev-&bulk_out_endpointAddr
&&&&&&&&&&&
((endpoint-&bEndpointAddress &
USB_ENDPOINT_DIR_MASK)
&&&&&&&&&&&&&&&&&&&
== USB_DIR_OUT) &&
&&&&&&&&&&&
((endpoint-&bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK)
&&&&&&&&&&&&&&&&&&&
== USB_ENDPOINT_XFER_BULK)) {
&&&&&&&&&&&
&&&&&&&&&&&
dev-&bulk_out_endpointAddr =
endpoint-&bEndpointA
(!(dev-&bulk_in_endpointAddr
dev-&bulk_out_endpointAddr)) {
err("Could not find both bulk-in and bulk-out endpoints");
usb_set_intfdata(interface, dev);
retval = usb_register_dev(interface,
&skel_class);
&&& if (retval)
&&&&&&&&&&&&&&
err("Not able to get a minor for this device.");
usb_set_intfdata(interface, NULL);
info("USB Skeleton device now attached to USBSkel-%d",
interface-&minor);
&&& return
kref_put(&dev-&kref,
skel_delete);
&&& return
static void skel_disconnect(struct usb_interface *interface)
{&&& struct
usb_skel *
&&& int minor =
interface-&
lock_kernel();
usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
usb_deregister_dev(interface, &skel_class);
unlock_kernel();
kref_put(&dev-&kref,
skel_delete);
&&& info("USB
Skeleton #%d now disconnected", minor);
static struct usb_driver skel_driver = {
&&& .owner
THIS_MODULE,
"skeleton",
&&& .probe
skel_probe,
&&& .disconnect
=&& skel_disconnect,
&&& .id_table =
skel_table,
static int __init usb_skel_init(void)
usb_register(&skel_driver);&&&
if (result)
err("usb_register failed. Error number %d", result);
&&& return
static void __exit usb_skel_exit(void)
usb_deregister(&skel_driver);
module_init (usb_skel_init);
module_exit (usb_skel_exit);
MODULE_LICENSE("Dual BSD/GPL");
obj-m& :=usbmouse.O&
KDIR&& :=/lib/modules/$(shell
uname -r)/build&&
PWD :=$(shell pwd)
&&& $(MAKE)
-C $(KDIR) SUBDIRS=$(PWD) modules
&&& rm -rf
&&& rm -rf
&&& rm -rf
&&& rm -rf
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 linux 芯片组驱动 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信