第11章、嵌入式Linux设备驱动开发

Size: px
Start display at page:

Download "第11章、嵌入式Linux设备驱动开发"

Transcription

1 黑色经典 系列之 嵌入式 Linux 应用程序开发详解 第 11 章嵌入式 Linux 设备驱动开发 本章目标 本书从第 6 章到第 10 章详细讲解了嵌入式 Linux 应用程序的开 发, 这些都是处于用户空间的内容 本章将进入到 Linux 的内核空间, 初步介绍嵌入式 Linux 设备驱动的开发 驱动的开发流程相对于应用 程序的开发是全新的, 与读者以前的编程习惯完全不同, 希望读者能 尽快地熟悉现在环境 经过本章的学习, 读者将会掌握以下内容 Linux 设备驱动的基本概念 Linux 设备驱动程序的基本功能 Linux 设备驱动的运作过程常见设备驱动接口函数掌握 LCD 设备驱动程序编写步骤掌握键盘设备驱动程序编写步骤能够独立定制 Linux 服务

2 11.1 设备驱动概述 设备驱动简介及驱动模块操作系统是通过各种驱动程序来驾驭硬件设备的, 它为用户屏蔽了各种各样的设备, 驱动硬件是操作系统最基本的功能, 并且提供统一的操作方式 设备驱动程序是内核的一部分, 硬件驱动程序是操作系统最基本的组成部分, 在 Linux 内核源程序中也占有 60% 以上 因此, 熟悉驱动的编写是很重要的 在第 2 章中已经提到过,Linux 内核中采用可加载的模块化设计 (LKMs,Loadable Kernel Modules), 一般情况下编译的 Linux 内核是支持可插入式模块的, 也就是将最基本的核心代码编译在内核中, 其他的代码可以选择在内核中, 或者编译为内核的模块文件 常见的驱动程序也是作为内核模块动态加载的, 比如声卡驱动和网卡驱动等, 而 Linux 最基础的驱动, 如 CPU PCI 总线 TCP/IP 协议 APM( 高级电源管理 ) VFS 等驱动程序则直接编译在内核文件中 有时也把内核模块叫做驱动程序, 只不过驱动的内容不一定是硬件罢了, 比如 ext3 文件系统的驱动 因此, 加载驱动时就是加载内核模块 这里, 首先列举一些模块相关命令 lsmod 列出当前系统中加载的模块, 其中左边第一列是模块名, 第二列是该模块大小, 第三列则是该模块使用的数量 如下所示 : [root@www root]# lsmod Module Size Used by autofs (autoclean) (unused) eepro iptable_nat (autoclean) (unused) ip_conntrack (autoclean) [iptable_nat] iptable_mangle (autoclean) (unused) iptable_filter (autoclean) (unused) ip_tables [iptable_nat iptable_mangle iptable_filter] usb-ohci (unused) usbcore [usb-ohci] ext jbd [ext3] aic7xxx sd_mod scsi_mod [aic7xxx sd_mod] rmmod 是用于将当前模块卸载 insmod 和 modprobe 是用于加载当前模块, 但 insmod 不会自动解决依存关系, 而 modprobe 则可以根据模块间依存关系以及 /etc/modules.conf 文件中的内容自动插入模块 mknod 是用于创建相关模块

3 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 设备文件分类本书在前面也提到过,Linux 的一个重要特点就是将所有的设备都当做文件进行处理, 这一类特殊文件就是设备文件, 它们可以使用前面提到的文件 I/O 相关函数进行操作, 这样就大大方便了对设备的处理 它通常在 /dev 下面存在一个对应的逻辑设备节点, 这个节点以文件的形式存在 Linux 系统的设备文件分为三类 : 块设备文件 字符设备文件和网络设备文件 块设备文件通常指一些需要以块 ( 如 512 字节 ) 的方式写入的设备, 如 IDE 硬盘 SCSI 硬盘 光驱等 字符型设备文件通常指可以直接读写, 没有缓冲区的设备, 如并口 虚拟控制台等 网络设备文件通常是指网络设备访问的 BSD socket 接口, 如网卡等 对这三种设备文件编写驱动程序时会有一定的区别, 本书在后面会有相关内容的讲解 设备号设备号是一个数字, 它是设备的标志 就如前面所述, 一个设备文件 ( 也就是设备节点 ) 可以通过 mknod 命令来创建, 其中指定了主设备号和次设备号 主设备号表明某一类设备, 一般对应着确定的驱动程序 ; 次设备号一般是用于区分标明不同属性, 例如不同的使用方法, 不同的位置, 不同的操作等, 它标志着某个具体的物理设备 高字节为主设备号和底字节为次设备号 例如, 在系统中的块设备 IDE 硬盘的主设备号是 3, 而多个 IDE 硬盘及其各个分区分别赋予次设备号 驱动层次结构 Linux 下的设备驱动程序是内核的一部分, 运行在内核模式, 也就是说设备驱动程序为内核提供了一个 I/O 接口, 用户使用这个接口实现对设备的操作 图 11.1 显示了典型的 Linux 输入 / 输出系统中各层次结构和功能 输入入 / 输出 输入入 / 输出 请求 响应 用户程序的进程 ( 设备 ) 文件系统 设备驱动程序 设备服务子程序 中断处理程序 物理设备控制器 物理设备 图 11.1 Linux 输入 / 输出系统层次结构和功能

4 Linux 设备驱动程序包含中断处理程序和设备服务子程序两部分 设备服务子程序包含了所有与设备操作相关的处理代码 它从面向用户进程的设备文件系统中接受用户命令, 并对设备控制器执行操作 这样, 设备驱动程序屏蔽了设备的特殊性, 使用户可以像对待文件一样操作设备 设备控制器需要获得系统服务时有两种方式 : 查询和中断 因为 Linux 下的设备驱动程序是内核的一部分, 在设备查询期间系统不能运行其他代码, 查询方式的工作效率比较低, 所以只有少数设备如软盘驱动程序采取这种方式, 大多设备以中断方式向设备驱动程序发出输入 / 输出请求 设备驱动程序与外界的接口每种类型的驱动程序, 不管是字符设备还是块设备都为内核提供相同的调用接口, 因此内核能以相同的方式处理不同的设备 Linux 为每种不同类型的设备驱动程序维护相应的数据结构, 以便定义统一的接口并实现驱动程序的可装载性和动态性 Linux 设备驱动程序与外界的接口可以分为如下三个部分 驱动程序与操作系统内核的接口 : 这是通过数据结构 file_operations( 在本书后面会有详细介绍 ) 来完成的 驱动程序与系统引导的接口 : 这部分利用驱动程序对设备进行初始化 驱动程序与设备的接口 : 这部分描述了驱动程序如何与设备进行交互, 这与具体设备密切相关 它们之间的相互关系如下图 11.2 所示 操作系统内核 各设备 接口 实现 数据结构 file_operations 初始化 设备驱动程序 接口 具体设备 系统引导 接口 进行 交互 驱动程序与设备间 图 11.2 设备驱动程序与外界的接口

5 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 设备驱动程序的特点综上所述,Linux 中的设备驱动程序有如下特点 (1) 内核代码 : 设备驱动程序是内核的一部分, 如果驱动程序出错, 则可能导致系统崩溃 (2) 内核接口 : 设备驱动程序必须为内核或者其子系统提供一个标准接口 比如, 一个终端驱动程序必须为内核提供一个文件 I/O 接口 ; 一个 SCSI 设备驱动程序应该为 SCSI 子系统提供一个 SCSI 设备接口, 同时 SCSI 子系统也必须为内核提供文件的 I/O 接口及缓冲区 (3) 内核机制和服务 : 设备驱动程序使用一些标准的内核服务, 如内存分配等 (4) 可装载 : 大多数的 Linux 操作系统设备驱动程序都可以在需要时装载进内核, 在不需要时从内核中卸载 (5) 可设置 :Linux 操作系统设备驱动程序可以集成为内核的一部分, 并可以根据需要把其中的某一部分集成到内核中, 这只需要在系统编译时进行相应的设置即可 (6) 动态性 : 在系统启动且各个设备驱动程序初始化后, 驱动程序将维护其控制的设备 如果该设备驱动程序控制的设备不存在也不影响系统的运行, 那么此时的设备驱动程序只是多占用了一点系统内存罢了 11.2 字符设备驱动编写 字符设备驱动编写流程 1. 流程说明在上一节中已经提到, 设备驱动程序可以使用模块的方式动态加载到内核中去 加载模块的方式与以往的应用程序开发有很大的不同 以往在开发应用程序时都有一个 main 函数作为程序的入口点, 而在驱动开发时却没有 main 函数, 模块在调用 insmod 命令时被加载, 此时的入口点是 init_module 函数, 通常在该函数中完成设备的注册 同样, 模块在调用 rmmod 函数时被卸载, 此时的入口点是 cleanup_module 函数, 在该函数中完成设备的卸载 在设备完成注册加载之后, 用户的应用程序就可以对该设备进行一定的操作, 如 read write 等, 而驱动程序就是用于实现这些操作, 在用户应用程序调用相应入口函数时执行相关的操作, init_module 入口点函数则不需要完成其他如 read write 之类功能 上述函数之间的关系如图 11.3 所示

6 模块 内核 insmod init_module() 设备注册 设备功能 用户调用 rmmod cleanup_module 设备卸载 图 11.3 设备驱动程序流程图 2. 重要数据结构用户应用程序调用设备的一些功能是在设备驱动程序中定义的, 也就是设备驱动程序的入口点, 它是一个在 <linux/fs.h> 中定义的 struct file 结构, 这是一个内核结构, 不会出现在用户空间的程序中, 它定义了常见文件 I/O 函数的入口 如下所示 : struct file_operations loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *filp, char *buff, size_t count, loff_t *offp); ssize_t (*write) (structfile *filp,constchar *buff,size_tcount,loff_t *offp); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *); int (*fasync) (int, struct file *, int); int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev); int (*lock) (struct file *, int, struct file_lock *); ; 这里定义的很多函数读者在第 6 章中已经见到过了, 当时是调用这些函数, 而在这里我们将学习如何实现这些函数 当然, 每个设备的驱动程序不一定要实现其中所有的函数操作,

7 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发若不需要定义实现时, 则只需将其设为 NULL 即可 其中,struct inode 提供了关于设备文件 /dev/driver( 假设此设备名为 driver) 的信息 struct file 提供关于被打开的文件信息, 主要用于与文件系统对应的设备驱动程序使用 struct file 较为重要, 这里列出了它的定义 : struct file mode_t f_mode;/* 标识文件是否可读或可写,FMODE_READ 或 FMODE_WRITE*/ dev_t f_rdev; /* 用于 /dev/tty */ off_t f_pos; /* 当前文件位移 */ unsigned short f_flags; /* 文件标志, 如 O_RDONLY O_NONBLOCK 和 O_SYNC */ unsigned short f_count; /* 打开的文件数目 */ unsigned short f_reada; struct inode *f_inode; /* 指向 inode 的结构指针 */ struct file_operations *f_op;/* 文件索引指针 */ ; 3. 设备驱动程序主要组成 (1) 设备注册设备注册使用函数 register_chrdev, 调用该函数后就可以向系统申请主设备号, 如果 register_chrdev 操作成功, 设备名就会出现在 /proc/devices 文件里 register_chrdev 函数格式如表 11.1 所示 表 11.1 所需头文件函数原型函数传入值 #include <linux/fs.h> register_chrdev 等函数语法要点 int register_chrdev(unsigned int major, const char *name,struct file_operations *fops) major: 设备驱动程序向系统申请的主设备号, 如果为 0 则系统为此驱动程序动态地分配一个主设备号 name: 设备名 fops: 对各个调用的入口点 函数返回值 成功 : 如果是动态分配主设备号, 此返回所分配的主设备号 且设备名就会出现在 /proc/devices 文件里 出错 : 1 (2) 设备解除注册在关闭设备时, 通常需要解除原先的设备注册, 此时可使用函数 unregister_chrdev, 此后该设备就会从 /proc/devices 里消失 unregister_chrdev 函数格式如下表 11.2 所示 : 表 11.2 所需头文件 #include <linux/fs.h> unregister_chrdev 等函数语法要点

8 函数原型 函数传入值 函数返回值 int unregister_chrdev(unsigned int major, const char *name) major: 设备的主设备号, 必须和注册时的主设备号相同 name: 设备名成功 :0, 且设备名从 /proc/devices 文件里消失 出错 : 1 (3) 打开设备打开设备的接口函数是 open, 根据设备的不同,open 函数完成的功能也有所不同, 但通常情况下在 open 函数中要完成如下工作 递增计数器 检查特定设备的特殊情况 初始化设备 识别次设备号 其中递增计数器是用于设备计数的 由于设备在使用时通常会打开较多次数, 也可以由不同的进程所使用, 所以若有一进程想要关闭该设备, 则必须保证其他设备没有使用该设备 因此使用计数器就可以很好地完成这项功能 这里, 实现计数器操作的是用在 <linux/module.h> 中定义的 3 个宏如下 MOD_INC_USE_COUNT: 计数器加一 MOD_DEC_USE_COUNT: 计数器减一 MOD_IN_USE: 计数器非零时返回真 另外, 当有多个物理设备时, 就需要识别次设备号来对各个不同的设备进行不同的操作, 在有些驱动程序中并不需要用到 注意 虽然这是对设备文件执行的第一个操作, 但却不是驱动程序一定要声明的操作 若这个函数的 入口为 NULL, 那么设备的打开操作将永远成功, 但系统不会通知驱动程序 (4) 释放设备释放设备的接口函数是 release 要注意释放设备和关闭设备是完全不同的 当一个进程释放设备时, 其他进程还能继续使用该设备, 只是该进程暂时停止对该设备的使用 ; 而当一个进程关闭设备时, 其他进程必须重新打开此设备才能使用 释放设备时要完成的工作如下 递减计数器 MOD_DEC_USE_COUNT 在最后一次释放设备操作时关闭设备 (5) 读写设备读写设备的主要任务就是把内核空间的数据复制到用户空间, 或者从用户空间复制到内核空间, 也就是将内核空间缓冲区里的数据复制到用户空间的缓冲区中或者相反 这里首先解释一个 read 和 write 函数的入口函数, 如表 11.3 所示

9 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 表 11.3 read write 函数语法要点 所需头文件 函数原型 #include <linux/fs.h> ssize_t (*read) (struct file *filp, char *buff, size_t count, loff_t *offp) ssize_t (*write) (struct file *filp, const char *buff, size_t count, loff_t *offp) filp: 文件指针 函数传入值 buff: 指向用户缓冲区 count: 传入的数据长度 offp: 用户在文件中的位置 函数返回值 成功 : 写入的数据长度 虽然这个过程看起来很简单, 但是内核空间地址和应用空间地址是有很大区别的, 其中之一就是用户空间的内存是可以被换出的, 因此可能会出现页面失效等情况 所以就不能使用诸如 memcpy 之类的函数来完成这样的操作 在这里就要使用 copy_to_user 或 copy_from_user 函数, 它们就是用来实现用户空间和内核空间的数据交换的 copy_to_user 和 copy_from_user 的格式如表 11.4 所示 表 11.4 所需头文件 函数原型 #include <asm/uaccess.h> copy_to_user/copy_from_user 函数语法要点 Unsigned long copy_to_user(void *to, const void *from, unsigned long count) Unsigned long copy_from_user(void *to, const void *from, unsigned long count) To: 数据目的缓冲区 函数传入值 From: 数据源缓冲区 count: 数据长度 函数返回值 成功 : 写入的数据长度失败 :-EFAULT 要注意, 这两个函数不仅实现了用户空间和内核空间的数据转换, 而且还会检查用户空间指针的有效性 如果指针无效, 那么就不进行复制 (6) 获取内存在应用程序中获取内存通常使用函数 malloc, 但在设备驱动程序中动态开辟内存可以有基于内存地址和基于页面为单位两类 其中, 基于内存地址的函数有 kmalloc, 注意的是,kmalloc 函数返回的是物理地址, 而 malloc 等返回的是线性地址, 因此在驱动程序中不能使用 malloc 函数 与 malloc() 不同,kmalloc() 申请空间有大小限制 长度是 2 的整次方, 并且不会对所获取的内存空间清零 基于页为单位的内存有函数族有如下 get_zeroed_page: 获得一个已清零页面 get_free_page: 获得一个或几个连续页面 get_dma_pages: 获得用于 DMA 传输的页面 与之相对应的释放内存用也有 kfree 或 free_pages 族

10 表 11.5 给出了 kmalloc 函数的语法格式 表 11.5 kmalloc 函数语法要点 所需头文件 函数原型 #include <linux/malloc.h> void *kmalloc(unsigned int len,int flags) Len: 希望申请的字节数 GFP_KERNEL: 内核内存的通常分配方法, 可能引起睡眠 GFP_BUFFER: 用于管理缓冲区高速缓存 函数传入值 flags GFP_ATOMIC: 为中断处理程序或其他运行于进程上下文之外的代码分配内存, 且不会引起睡眠 GFP_USER: 用户分配内存, 可能引起睡眠 GFP_HIGHUSER: 优先高端内存分配 _GFP_DMA:DMA 数据传输请求内存 _GFP_HIGHMEN: 请求高端内存 函数返回值 成功 : 写入的数据长度失败 :-EFAULT 表 11.6 给出了 kfree 函数的语法格式 表 11.6 kfree 函数语法要点 所需头文件函数原型函数传入值函数返回值 #include <linux/malloc.h> void kfree(void * obj) obj: 要释放的内存指针 成功 : 写入的数据长度失败 :-EFAULT 表 11.7 给出了基于页的分配函数 get_free_ page 族函数的语法格式 表 11.7 get_free_ page 类函数语法要点 所需头文件函数原型函数传入值函数返回值 #include <linux/malloc.h> unsigned long get_zeroed_page(int flags) unsigned long get_free_page(int flags) unsigned long get_free_page(int flags,unsigned long order) unsigned long get_dma_page(int flags,unsigned long order) flags: 同 kmalloc order: 要请求的页面数, 以 2 为底的对数 成功 : 写入的数据长度失败 :-EFAULT 表 11.8 给出了基于页的内存释放函数 free_ page 族函数的语法格式

11 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 表 11.8 所需头文件函数原型函数传入值函数返回值 #include <linux/malloc.h> free_page 类函数语法要点 unsigned long free_page(unsigned long addr) unsigned long free_page(unsigned long addr) flags: 同 kmalloc order: 要请求的页面数, 以 2 为底的对数 成功 : 写入的数据长度失败 :-EFAULT (7) 打印信息就如同在编写用户空间的应用程序, 打印信息有时是很好的调试手段, 也是在代码中很常用的组成部分 但是与用户空间不同, 在内核空间要用函数 printk 而不能用平常的函数 printf printk 和 printf 很类似, 都可以按照一定的格式打印消息, 所不同的是,printk 还可以定义打印消息的优先级 表 11.9 给出了 printk 函数的语法格式 表 11.9 所需头文件函数原型函数传入值函数返回值 #include <linux/kernel> int printk(const char * fmt, ) fmt: 日志级别 printk 类函数语法要点 KERN_EMERG: 紧急时间消息 KERN_ALERT: 需要立即采取动作的情况 KERN_CRIT: 临界状态, 通常涉及严重的硬件或软件操作失败 KERN_ERR: 错误报告 KERN_WARNING: 对可能出现的问题提出警告 KERN_NOTICE: 有必要进行提示的正常情况 KERN_INFO: 提示性信息 KERN_DEBUG: 调试信息 : 如 printf 一样的格式说明 成功 :0 失败 : 1 这些不同优先级的信息可以输出到控制台上 /var/log/messages 里 其中, 对输出给控制台的信息有一个特定的优先级 console_loglevel 若优先级小于这个整数值时, 则消息才能显示到控制台上, 否则, 消息会显示在 /var/log/messages 里 若不加任何优先级选项, 则消息默认输出到 /var/log/messages 文件中 注意 要开启 klogd 和 syslogd 服务, 消息才能正常输出 4.proc 文件系统 /proc 文件系统是一个伪文件系统, 它是一种内核和内核模块用来向进程发送信息的机

12 制 这个伪文件系统让用户可以和内核内部数据结构进行交互, 获取有关进程的有用信息, 在运行时通过改变内核参数改变设置 与其他文件系统不同,/proc 存在于内存之中而不是硬 盘上 读者可以通过 ls 查看 /proc 文件系统的内容 表 列出了 /proc 文件系统的主要目录内容 表 /proc 文件系统主要目录内容 目录名称 目录内容 目录名称 目录内容 apm 高级电源管理信息 locks 内核锁 cmdline 内核命令行 meminfo 内存信息 cpuinfo 关于 CPU 信息 misc 杂项 devices 设备信息 ( 块设备 / 字符设备 ) modules 加载模块列表 dma 使用的 DMA 通道 mounts 加载的文件系统 filesystems 支持的文件系统 partitions 系统识别的分区表 interrupts 中断的使用 rtc 实时时钟 ioports I/O 端口的使用 slabinfo Slab 池信息 kcore 内核核心印象 stat 全面统计状态表 kmsg 内核消息 swaps 对换空间的利用情况 ksyms 内核符号表 version 内核版本 loadavg 负载均衡 uptime 系统正常运行时间 除此之外, 还有一些是以数字命名的目录, 它们是进程目录 系统中当前运行的每一个 进程都有对应的一个目录在 /proc 下, 以进程的 PID 号为目录名, 它们是读取进程信息的接口 进程目录的结构如表 所示 表 /proc 中进程目录结构 目录名称 目录内容 目录名称 目录内容 cmdline 命令行参数 cwd 当前工作目录的链接 environ 环境变量值 exe 指向该进程的执行命令文件 fd 一个包含所有文件描述符的目录 maps 内存映像 mem 进程的内存被利用情况 statm 进程内存状态信息 stat 进程状态 root 链接此进程的 root 目录 status 进程当前状态, 以可读的方式显示出来 用户可以使用 cat 命令来查看其中的内容 可以看到,/proc 文件系统体现了内核及进程运行的内容, 在加载模块成功后, 读者可以 使用查看 /proc/device 文件获得相关设备的主设备号 11.3 LCD 驱动编写实例 LCD 工作原理 S3C2410LCD 控制器用于传输视频数据和产生必要的控制信号, 如 VFRAME VLINE

13 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 VCLK VM 等 除了控制信号,S3C2410 还有输出视频数据的端口 VD[23:0], 如图 11.4 所示 图 11.4 S3C2410 LCD 控制器 (1) 寄存器介绍 LCD 的寄存器主要有 :LCDCON1 寄存器 LCDCON2 寄存器 LCDCON3 寄存器 LCDC- ON4 寄存器和 LCDCON5 寄存器 (2) 控制流程 LCD 控制器由 REGBANK LCDCDMA VIDPRCS 和 LPC3600 组成 ( 如图 11.5 所示 ) REGBANK 有 17 个可编程寄存器组和 256*16 的调色板存储器, 用来设定 LCD 控制器 LCDCDMA 是一个专用 DMA, 自动从帧存储器传输视频数据到 LCD 控制器, 用这个特殊的 DMA, 视频数据可不经过 CPU 干涉就显示在屏幕上 IDPRCS 接受从 LCDCDMA 来的视频数据并在将其改变到合适数据格式后经 VD[23:0] 将之送到 LCD 驱动器, 如 4/8 单扫描或 4 双扫描显示模式 TIMEGEN 由可编程逻辑组成, 以支持不同 LCD 驱动器的接口时序和速率的不同要求 TIMEGEN 产生 VFRAME VLINE VCLK VM 信号等 REGBANK TIMEGEN VCLK/LCD-HCLK VLINE/VSYNC/CPV LPC3600 VIDEO MUX VFRAME/VSYNC/SYV VM/VDEN/TP LCDVF0 LCDVF1 LCDVF2 LCDCDMA VIDPRCS VD[23:0] 图 11.5 S3C2410 LCD 控制器内部方框图 (3) 数据流描述 FIFO 存储器位于 LCDCDMA 当 FIFO 空或部分空时,LCDCDMA 要求从基于突发传输模式的帧存储器中取来数据, 存入要显示的图像数据, 而这个帧存储器是 LCD 控制器在 RAM 中开辟的一片缓冲区 当这个传送请求被存储控制器中的总线仲裁器接收到后, 从系统存储器到内部 FIFO

14 就会成功传送 4 个字 FIFO 的总大小是 28 个字, 其中低位 FIFOL 是 12 个字, 高位 FIFOH 是 16 个字 S3C2410 有两个 FIFO 来支持双扫描显示模式 在单扫描模式下, 只使用一个 FIFO(FIFOH) (4)TFT 控制器操作 S3C2410 支持 STN-LCD 和 TFT-LCD TIMEGEN 产生 LCD 驱动器的控制信号, 如 VSYNC HSYNC VCLK VDEN 和 LEND 等 这些控制信号与 REGBANK 寄存器组中的 LCDCONl/2/3/4/5 寄存器的配置关系相当密切, 基于 LCD 控制寄存器中的这些可编程配置, TIMEGEN 产生可编程控制信号来支持不同类型的 LCD 驱动器 VSYNC 和 HSYNC 脉冲的产生依赖于 LCDCON2/3 寄存器的 HOZVAl 域和 LINEVAL 域的配置 HOZVAL 和 LINEVAL 的值由 LCD 屏的尺寸决定, 如下公式 : HOZVAL= 水平显示尺寸 1 (1) LINEVAL= 垂直显示尺寸 1 (2) VCLK 信号的频率取决于 LCDCONl 寄存器中的 CLKVAL 域 VCLK 和 CLKVAL 的关系如下, 其中 CLKVAl 的最小值是 0: VCLK(Hz)=HCLK/L(CLKVAL+1) 2] (3) 帧频率是 VSYNC 信号的频率, 它与 LCDCONl 和 LCDCON2/3/4 寄存器的 VSYNC VD-PD VFPD LINEVAL HSYNC HBPD HFPD HOZVAL 和 CLKVAL 都有关系 大多数 LCD 驱动器都需要与显示器相匹配的帧频率, 帧频率计算公式如下 : FrameRate=1/[(VSPW+1)+(VBPD+1)+(LINEVAL+1)+(VFPD+1)]*[(HSPW+1)+(HBPD+1) +(HFPD+l)+(HOZVAL+1)*[2*(CLKVAL+1)/(HCLK)] LCD 驱动实例 LCD 驱动代码如下所示 : #include <linux/kernel.h> #include <linux/init. h> #include <linux/module. h> #include <linuxjfs. h> #include <linux/delay.h> #include <asm/fcntl.h> #include <asm/unistd.h> #include <asm/io.h> #include <asm/uaccess.h> #include "lcdexp.h" static unsigned char*, lcd base; /* LCD 配置函数 */ static void setup_lcd(void) /* 在设置 LCD 寄存器之前关闭 LCD*/ LCDEN[12] = 0;

15 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 SYSCON1 &= ~0x ; /* 设置 LCD 控制寄存器 * Video Buffer Size[0:12]: 320'240'12 / 128 = 0xlclf * Line Length[13:18]: 320 / 16-1 = 0x13 * Pixel Prescale[19:24]: 0x01 * ACPmscale[25:29]: 0x13 * GSEN[30]: =1,Enables gray scale output to LCD * GSMD[31]: =1,4 bpp ( 16-gray scale ) */ LCDCON = 0xe60f7clf; /* 设置 LCD Palette 寄存器 */ PALLSW = 0x ; PALMSW = 0xfedcba98; /* * 设置 LCD frame buffer Sets 的起始位置 * 这样, frame buffer 就从 0xc 起始 */ FBADDR = 0xc; /* 使能 LCD 使之改变 LCD 的配置 */ LCDEN[12] = 1; SYSCON1 = 0x ; return; /* 在 LCD 中画一个点 * x,y: 亮点的坐标 * color: 点的颜色 */ static void lcd pixel_set(int x, int y, COLOR color) unsigned char* fb_ptr; COLOR pure_color = OxO000; /* if the dot is out of the LCD, return */ If (x<0 II x>=32011 y<0 II y>=240) /* 计算点的地址 */ fb_.ptr = lcd base + (x+y*320)*12/8; /* 把版面上的点映射到帧缓冲中 (frame buffer)*/ if (x & 0xl ) ( pure_color = ( color & 0x000f ) < < 4;

16 *fb_ptr &= 0x0f; *fb_ptr I= pure_color; pure_color = ( color & 0x0ff0 ) >> 4; *(fb_ptr+l) = 0xff & pure_color; else pure_color = color & 0x00ff; *fb_ptr = 0xff & pure_color; pure_color = (color & 0x0f00 ) >> 8; *(fb_ptr+l) &= OxfO; *(fb_ptr+l) = pure_color; return; /* 把所有 LCD 图片清零 */ void clear_lcd(void) int x; int y; for (y=0;y<240; y++) for (x=0; x<320; x++) //lcd_disp.x = x; //lcd_disp.y = y; Lcd_plxel_set(x,y,0x0000); Return; /* (start x, start_y): 矩形最左边的坐标 * (end_x, end_y): 矩形最右边的坐标 */ static void draw_rectangle(int start_x,int start_y,int end_x,int end_y,color color) draw vline(start_x, start_y, end_y, color); draw_vline(end_x, start_y, end_y, color); draw_hline(start_x, end_x, start_y, color),

17 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 draw_hline(start_x, end_x, end_y, color); return; /* * (start x, start_y): 矩形最上边的坐标 * (end_x, end_y): 矩形最下边的坐标 */ static void draw_full_rectangle(int start_x, int start_y,int end_x,int end_y,color color) int i = 0; int tmp= 0; tmp= end_x - start_x; for ( i=0;i<tmp;++i ) draw_vline(start_x+i, start_y,end_y, color); return; /* 显示一个 ascii 符号 * x,y: 符号起始坐标 * codes: 要显示的字节数 */ static void write_en(int x, int y, unsigned char* codes, COLOR color) inti = 0; /* total 16 bytes codes*/ for (i=0;i<16;++i) intj = 0; x += 8; for ( j=0;j<8;++j ) --x; if ((codes[i]>>j) 8, 0x1 ) lcd_pixel_set(x, y, color); /* 移到下一行,x 轴不变,y 轴加一 */ ++y; return;

18 /* 显示一个中文字符 * x,y: 字符起始点 * codes: 要显示的字节数 * color: 要显示的字符颜色 */ static void write_cn(int x, iht y, unsigned char* codes, COLOR color) int i; /* total 2'16 bytes codes */ for(i=0;i< 16;i++) int j = 0; for (j=0;j<2;++j) int k = 0; x += 8(j+1); for ( k=o;k<8;++k ) --x; if ( ( codes[2*i+j] >> k) &0xl ) Icd_pixel_set(x,y,color); x-= 8; ++y; return; static int lcdexp_open(struct inode *node, struct file *file) return 0; static int lcdexp_read(struct file *file, char *buff, size_t count, Ioff_t *offp) return 0; static int lcdexp_write(struct file *file, const char *buff, size_t count, Ioff_t *offp) return 0;

19 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 /*lcd ioctl 驱动函数, 分类处理 lcd 的各项动作, 在每种情况下都会调用前述的关键函数 */ static int lcdex_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) switch ( cmd ) case LCD_Clear:/*lcd 清屏 */ clear_lcd(); break; case LCD_Pixel_Set /*lcd 象素设置 */ struct lcd_display pixel_display; if(copy_from_user(&pixel_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_frorn_user error!\n"), return -1; lcd_pixel_set(pixeldisplay.xl, pixel_display.yl, pixel_display. color); break; case LCD_Big_Pixel_Set:/*lcd 高级象素设置 */ struct lcd_display b_pixel_display; if(copy_from_user(&b_pixel_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1; lcd_big_pixel_set(b_pixel_display.xl,b_pixeldisplay.y1,b_pixel_display. color); break; case LCD_Draw_Vline:/*lcd 中显示水平线 */ struct lcd_display vline_display;

20 if(copy_from_user(&vline_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1; draw_vline(vline_display.xl, vline_display.yl, vline_display.y2, vline_display.color); case LCD_Draw_HLine:/*lcd 中显示垂直线 */ struct lcddisplay hline_display; if (copy_from_user(ehline_display,(structicd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1; draw_hline(hline_display.xl, hline display.x2, hline_display.yl, hline_display.color); break; Case LCD_Draw_Vdashed:/*lcd 中显示水平随意线 */ struct lcd-_display vdashed display; if(copy_from_user(&vdashed_display,(structlcd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1; draw hdashed(hdashed-display.xl, hdashed_display.x2, hdashed_ display.yl, vdashed_display.color); break; Case LCD_Draw_HDdashed:/*lcd 中显示垂直随意线 */ struct lcd_display hdashed display; if(copy_from_user(&hdashed_display,(structlcd_display*)arg,sizeof (struct lcd_display)))

21 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 printk("copy_from_user error!\n"); return -1; draw hdashed(hdashed-display.xl, hdashed_display.x2, hdashed_ display.yl, vdashed_display.color); break; case LCD_Draw_Rectangle:/*lcd 中显示矩阵 */ struct/cd-display rect display; if ( copy_from_user(&rect_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1; draw_rectangle(rect_display.xl,rect_display.yl,rect_display.x2, rect_display.y2,rect_display.color); break; case LCD_Draw_Full_Rectangle:/*lcd 中显示填充矩阵 */ Struct xlcd_display frect_display; if (copy_from_user(&frect_display,(structicd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); draw_full_rectangle(frect_display.xl, frect_display.yl,frect_display.x2,frect_display.y2, rect_display.color); break; case LCD Write_EN:/*lcd 英文显示 */ Struct lcd_display en_display; if ( copy_from_user(&en_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_from_user error!\n"); return -1;

22 write_en(en_display.xl, en_.display.yl, en_display.buf, en_display. color); break; case LCD Write_CN:/*lcd 中文显示 */ struct lcd_display cn_display; if ( copy_from_user(&cn_display,(struct Icd_display*)arg,sizeof (struct lcd_display))) printk("copy_ffom_user errod\n"); return -1; write_cn(cn_display.xl, cn_display.yl, cn_display.buf, cn_display. color); break; default: printk("unknown cmd\n"); break; return 0; static struct file_operations lcdexp_fops = open: lcdexp_open, read: lcdexp_read, ioctl: lcdexp_joctl, write: lcdexp_write, release: lcdexp_release, ; int lcdexp_init(void) int result; lcd base = (unsigned char*)0xc ; result = register_chrdev(dev_ma)or,"lcdexp",&lcdexp_fops); if ( result < 0 ) printk( KERN_INFO "lcdexp:register Icdexp failed!\n' return result; setup_lcd(); for ( i=0;i<320*240*12/8;i++ )

23 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 lcd base++ = 0x77; _lcd_base = (unsigned char*)0xc ; printk("lcd... support.\n"); return 0; static void _exit lcdexp_exit(void) /* clear LCD */ unregister_chrdev(dev_ma.lor,"lcdexp"); module_init(lcdexp_init); module_exit(lcclexp_exit); 11.4 块设备驱动编写 块设备驱动程序描述符块设备文件通常指一些需要以块 ( 如 512 字节 ) 的方式写入的设备, 如 IDE 硬盘 SCSI 硬盘 光驱等 它的驱动程序的编写过程与字符型设备驱动程序的编写有很大的区别 块设备驱动程序描述符是一个包含在 <linux/blkdev.h> 中的 blk_dev_struct 类型的数据结构, 其定义如下所示 : struct blk_dev_struct request_queue_t request_queue; ; queue_proc void *date; *queue; 在这个结构中, 请求队列 request_queue 是主体, 包含了初始化之后的 I/O 请求队列 对于函数指针 queue, 当其为非 0 时, 就调用这个函数来找到具体设备的请求队列, 这是为考虑具有同一主设备号的多种同类设备而设的一个域, 该指针也在初始化时就设置好 指针 data 是辅助 queue 函数找到特定设备的请求队列, 保存一些私有的数据 所有块设备的描述符都存放在 blk_dev 表 struct blk_dev_struct blk_dev[max_blkdev] 中 ; 每个块设备都对应着数组中的一项, 可以使用主设备号进行检索 每当用户进程对一个块设备发出一个读写请求时, 首先调用块设备所公用的函数 generic_file_read() 和 generic_file_write() 如果数据存在在缓冲区中或缓冲区还可以存放数据, 那么就同缓冲区进行数据交换 否则, 系统会将相应的请求队列结构添加到其对应项的 blk_dev_struct 中, 如下图 11.6 所示

24 dev b_dev cmd cmd b_cmd request_fri current_request bh bh b_rpe bhlai b_prev_free next next next 图 11.6 块设备请求队列 块设备驱动编写流程 1. 流程说明块设备驱动程序的编写流程同字符设备驱动程序的编写流程很类似, 也包括了注册和使用两部分 但与字符驱动设备所不同的是, 块设备驱动程序包括一个 request 请求队列 它是当内核安排一次数据传输时在列表中的一个请求队列, 用以最大化系统性能为原则进行排序 在后面的读写操作时会详细讲解这个函数, 下图 11.7 给出了块设备驱动程序的流程图, 请读者注意与字符设备驱动程序的区别 模块 内核 insmod init_module() 设备注册 request() 设备功能 用户调用 rmmod cleanup_module 设备卸载 图 11.7 块设备驱动程序流程图

25 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 2. 重要数据结构由于块设备驱动程序的绝大部分都与设备无关的, 故内核的开发者通过把大部分相同的代码放在一个头文件 <linux/blk.h> 中来简化驱动程序的代码 从而每个块设备驱动程序都必须包含这个头文件 先给出块设备驱动程序要用到的数据结构定义 : struct device_struct const char *name; struct file_operations *chops; ; static struct device_struct blkdevs[max_blkdev]; struct sbull_dev void **data; int quantum;// the current quantum size int qset;// the current array size unsigned long size; unsigned int access_key;// used by sbulluid and sbullpriv unsigned int usage;// lock the device while using it unsigned int new_msg; struct sbull_dev *next;// next listitem ; 与字符设备驱动程序一样, 块设备驱动程序也包含一个 file_operation 结构, 其结构定义一般如下所示 : struct file_operation blk_fops = NULL,//seek block_read,// 内核函数 block_write,// 内核函数 NULL,//readdir NULL,//poll sbull_ioctl,// ioctl NULL,//mmap sbull_open,//open NULL,//flush sbull_release,//release block_fsync,// 内核函数 NULL,//fasync sbull_check_media_change,//check media change NULL,//revalidate NULL,//lock

26 ; 从上面结构中可以看出, 所有的块驱动程序都调用内核函数 block_read() block_write(), block_fsync() 函数, 所以在块设备驱动程序入口中不包含这些函数, 只需包括 ioctl() open() 和 release() 函数即可 (1) 设备初始化块设备的初始化过程要比字符设备复杂, 它既需要像字符设备一样在引导内核时完成一定的工作, 还需要在内核编译时增加一些内容 块设备驱动程序初始化时, 由驱动程序的 init() 完成 块设备驱动程序初始化的工作主要包括 : 检查硬件是否存在 ; 登记主设备号 ; 将 fops 结构的指针传递给内核 ; 利用 register_blkdev() 函数对设备进行注册 : if(register_blkdev(sbull_major, sbull,&sbull_fops)) printk( Registering block device major:%d failed\n,sbull_major); return-eio; ; 将 request() 函数的地址传递给内核 : blk_dev[sbull_major].request_fn = DEVICE_REQUEST; 将块设备驱动程序的数据容量传递给缓冲区 : #define sbull_hards_size 512 #define sbull_block_size 1024 static int sbull_hard = sbull_hards_size; static int sbull_soft = sbull_block_size; hardsect_size[sbull_major] = &sbull_hard; blksize_size[sbull_major] = &sbull_soft; 在块设备驱动程序内核编译时, 应把下列宏加到 blk.h 文件中 : #define MAJOR_NR sbull_major #define DEVICE_NAME sbull #define DEVICE_REQUEST sbull_request #define DEVICE_NR(device) (MINOR(device)) #define DEVICE_ON(device) #define DEVICE_OFF(device) (2)request 操作 Request 操作涉及一个重要的数据结构如下 struct request kdev_t rq_dev;

27 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 ; int cmd; // 读或写 int errors; unsigned long sector; char *buffer; struct request *next; 对于具体的块设备, 函数指针 request_fn 当然是不同的 块设备的读写操作都是由 request() 函数完成 所有的读写请求都存储在 request 结构的链表中 request() 函数利用 CURRENT 宏检查当前的请求 : #define CURRENT (blk_dev[major_nr].current_request) 接下来看一看 sbull_request 的具体使用 : extern struct request *CURRENT; void sbull_request(void) unsigned long offset,total; Begin: INIT_REQUEST: offset = CURRENT -> sector * sbull_hard; total = CURRENT -> current_nr_sectors * sbull_hard; /* 超出设备的边界 */ if(total + offset > sbull_size * 1024) /* 请求错误 */ end_request(0); goto Begin; if(current -> cmd == READ) memcpy(current -> buffer,sbull_storage + offset,total); else if(current -> cmd == WRITE) memcpy(sbull_storage + offset,current -> buffer,total); else end_request(0); /* 成功 */ end_request(1); /* 当请求做完时让 INIT_REQUEST 返回 */ goto Begin;

28 request() 函数从 INIT_REQUEST 宏命令开始 ( 它也在 blk.h 中定义 ), 它对请求队列进行检查, 保证请求队列中至少有一个请求在等待处理 如果没有请求 ( 即 CURRENT = 0), 则 INIT_REQUEST 宏命令将使 request() 函数返回, 任务结束 假定队列中至少有一个请求,request() 函数现在应处理队列中的第一个请求, 当处理完请求后,request() 函数将调用 end_request() 函数 如果成功地完成了读写操作, 那么应该用参数值 1 调用 end_request() 函数 ; 如果读写操作不成功, 那么以参数值 0 调用 end_request() 函数 如果队列中还有其他请求, 那么将 CURRENT 指针设为指向下一个请求 执行 end_request() 函数后,request() 函数回到循环的起点, 对下一个请求重复上面的处理过程 (3) 打开操作打开操作要完成的流程图如下图 11.8 所示 典型实现代码如下所示 : int sbull_open(struct inode *inode,struct file *filp) int num = MINOR(inode -> i_rdev); if(num >= sbull -> size) return ENODEV; sbull -> size = sbull -> size + num; if(!sbull -> usage) check_disk_change(inode -> i_rdev); if(!*(sbull -> data)) return -ENOMEM; sbull -> usage++; MOD_INC_USE_COUNT; return 0; (4) 释放设备操作 释放设备操作要完成的流程图如图 11.9 所示

29 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 开始 设备是否存在? 否 否 是从设备号有效? 是是否共享设备? 是忙否? 否置忙标志 否返回 -ENODEV 是睡眠等待 :sleep_on 该设备的用户数目增加 1: MOD_INC_USE_COUNT; 成功, 返回 0 结束 图 11.8 块设备打开操作流程图 开始 否 是否有未结束的 I/O 操作? 是 完成这些操作 是否需要释放硬件资源? 否 是 对 open( ) 操作中的任何排它访问标志进行复位 该设备用户数目减 1: MOD_DEC_USE_COUNT; 结束

30 图 11.9 释放设备操作流程图典型实现代码如下所示 : void sbull_release(struct inode *inode,struct file *filp) sbull -> size = sbull -> size + MINOR(inode -> i_rdev); sbull -> usage--; MOD_DEC_USE_COUNT; printk("this blkdev is in release!\n"); return 0; (5)ioctl 操作 ioctl 操作要完成的流程图如图 所示 图 ioctl 操作要完成的流程图

31 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发其典型实现代码如下所示 : #include <linux/ioctl.h> #include <linux/fs.h> int sbull_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg) int err; struct hd_geometry *geo = (struct hd_geometry *)arg; PDEBUG( ioctl 0x%x 0x%lx\n,cmd,arg); switch(cmd) case BLKGETSIZE: / * 返回设备大小 */ if(!arg) return EINVAL; // NULL pointer:not valid err = verify_area(verify_write,(long *)arg,sizeof(long)); if(err) return err; put_user(1024*sbull_sizes[minor(inode -> i_rdev)/sbull_hardsects [MINOR(inode -> i_rdev)],(long*)arg]; return 0; case BLKFLSBUF: // flush if(!suser()) return EACCES; // only root fsync_dev(inode -> i_rdev); return 0; case BLKRRPART: // re-read partition table: can t do it return EINVAL; RO_IOCTLS(inode -> i_rdev,arg); // the default RO operations, 宏 RO_IOCTLS(kdev_t dev,unsigned long where) 在 blk.h 中定义 return EINVAL; // unknown command 11.5 中断编程 前面所讲述的驱动程序中都没有涉及到中断处理, 而实际上, 有很多 Linux 的驱动都是 通过中断的方式来进行内核和硬件的交互

32 这是驱动程序申请中断和释放中断的调用 在 include/linux/sched.h 里声明 request_irq() 调用的定义 : int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags,const char * devname,oid *dev_id); irq 是要申请的硬件中断号 在 Intel 平台, 范围是 0~15 handler 是向系统登记的中断处理函数 这是一个回调函数, 中断发生时, 系统调用这个函数, 传入的参数包括硬件中断号,device id, 寄存器值 dev_id 就是下面的 request_irq 时传递给系统的参数 dev_id irqflags 是中断处理的一些属性 比较重要的有 SA_INTERRUPT, 标明中断处理程序是快速处理程序 ( 设置 SA_INTERRUPT) 还是慢速处理程序 ( 不设置 SA_INTERRUPT) 快速处理程序被调用时屏蔽所有中断 慢速处理程序不屏蔽 还有一个 SA_SHIRQ 属性, 设置了以后运行多个设备共享中断 dev_id 在中断共享时会用到 一般设置为这个设备的 device 结构本身或者 NULL 中断处理程序可以用 dev_id 找到相应的控制这个中断的设备, 或者用 irq2dev_map 找到中断对应的设备 void free_irq(unsigned int irq,void *dev_id); 11.6 键盘驱动实现 键盘工作原理 1. 原理简介在键盘产生按键动作之后, 键盘上的扫描芯片 ( 一般为 8048) 获得键盘的扫描码, 并将其发送到主机端 在主机端的处理过程为是端口读取扫描码之后, 对键盘模式作一个判断, 如果是 RAW 模式, 则直接将键盘扫描码发送给应用程序 ; 如果是其他模式, 则就将扫描码转化成为键盘码, 然后再判断模式以决定是否将键盘码直接发送给应用程序 ; 如果是 XLATE 或 Unicod 模式, 则将键盘码再次转化成为符号码, 然后根据对符号码解析, 获得相应的处理函数, 并将其送到 TY 设备的缓存中 模式判断的对应关系如图 所示 MEDIUMRAW 模式 按键动作扫描码键盘码符号码 应用程序应用程序应用程序 RAW 模式 图 模式判断的对应关系

33 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发键盘模式有 4 种, 这 4 种模式的对应关系如图 1 所示 Scancode mode(raw) 模式 : 将键盘端口上读出的扫描码放入缓冲区, 通过参数 s 可以设置 Keycode mode(mediumraw) 模式 : 将扫描码过滤为键盘码放入缓冲区, 通过参数 k 可以设置 ASCII mode(xlate) 模式 : 识别各种键盘码的组合, 转换为 TTY 终端代码放入缓冲区, 通过参数 a 可以设置 UTF-8 mode(unicode) 模式 :Unicode 模式基本上与 XLATE 相同, 只不过可以通过数字小键盘 I 旬接枪入 Unicode 代码, 通过参数 u 可以设置 2. 扫描码一个基本按键的扫描码由 3 个字节组成 :1 个字节的接通扫描码和 2 个字节的断开扫描码 其中第 1 和第 2 个字节相同, 中间字节是断开标志 FOH 例如 B 键的接通扫描码是 32H, 断开扫描码是 FOH 32H,B 键被按下时,32H 被发送出去, 如果移植按住不放, 则键盘将以按键重复率不停地发送 32H, 直到该键释放, 才发出断开扫描码 FOH 32H 扫描码与按键的位置有关, 与该键的 ASCII 码并无对应关系 键盘上还有部分扩展键 ( 功能键和控制键等 ), 这些键的扫描码由 5 个字节组成, 与基本键的扫描码相比, 接通扫描码与断开扫描码前各多了一个固定值字节 EOH 例如 Home 键的接通扫描码是 EOH 70H, 断开扫描码是 EOH FOH 70H 还有两个特殊键,PrintScreen 键的接通扫描码是 EOH 12H EOH 7CH; 断开扫描码是 EOH FOH 7CH EOH FOH 77H, 无断开扫描树 3. 键盘码由前面的分析可见, 单单一个键的按下与断开, 键盘最多要产生一系列多达 6 个字节的扫描码序列, 而内核必须解析扫描码序列从而定位某个键被按下与释放的事件 为达到这个目的, 每一个键被分配一个键盘码 k(k 的范围 1-127)0 如果按键按下产生的键盘码为 k, 则释放该键产生的键盘码为 k+128 按照键盘码的分配规则, 对于产生单个扫描码范围 OxOl~Ox58 的键, 其键盘码与扫描码相同 而对于 0x59~0x71 范围的键, 可以查表获得其扫描码与键盘码对应 4. 符号码符号码 (keysym) 最终是用来标志一个按键事件的惟一值 ; 根据上面的分析, 它由键盘码经过 Keymap 表映射而来 它包括 2 个字节, 高 8 位表示 type, 根据 type 的不同, 我们最终选择不同的处理函数来处理不同类型的事件,type 相同的事件由同一个函数来处理 Type 包括一般键 方向键 字母键 函数键等 在 <linux/keyboard.h> 中可以找到 13 种键类型的宏定义 5.Keymap 表在使用键盘时常常使用组合键, 而组合键的意义通常是系统另外赋予的, 所以从键盘码向 TY 输入符的转换需要借助 Keymap 表来索引 intshift_ final = shift state ^ kbd-aockstate; ushort'key map=key maps[shift finall];

34 keysym=key_map[keycodel]; 由于共计有 8 个修饰符 (modifier), 即 Shift,AitGr,Control,Alt,ShiftL,ShiftR,CtrIL 和 CtrlR, 因此共有 256 张可能的 Keymap, 而在实际使用时, 内核缺省只分配 7 张 Keymap:plain, Shift, AltR, Ctrl, Ctrl+Shift, AItL 和 Ctrl+AitL Keymap 表是一张二维表, 结构图如图 所示 通过这张 Keymap 表, 就能完成键盘码到符号码的转化, 获得相应的符号码 Ctrl shift 符号码 Keysym indexed by keycode 图 二维表结构图 键盘驱动综述 Linux 中的大多数驱动程序都采用了层次型的体系结构, 键盘驱动程序也不例外 在 Linux 中, 键盘驱动被划分成两层来实现 其中, 上层是一个通用的键盘抽象层, 完成键盘驱动中不依赖于底层具体硬件的一些功能, 并且负责为底层提供服务 ; 下层则是硬件处理层, 与具体硬件密切相关, 主要负责对硬件进行直接操作 键盘驱动程序的上层公共部分都在 driver/keyboard.c 中 在 keyboard.c 中, 不涉及底层操作, 也不涉及到任何体系结构, 主要负责键盘初始化 键盘 tasklet 的挂入 按键盘后的处理 Keymap 表的装入 Scancode 的转化 与 TTY 设备的通信 在 pc_keyb.c 中, 主要负责一些底层操作, 跟具体的体系结构相关, 它完成的功能有 : 键盘的 I/O 端口和中断号的分配, 键盘的硬件初始化, 扫描码到键盘码的转化, 键盘中断处理 键盘驱动流程 (1) 初始化 kbd_init() 函数是键盘代码执行的入口点 kbd_init() 在对键盘的工作模式及其他参数进行配置后, 调用 kbd_init hw() 函数 对于上层来说, 此函数是一个统一的接口, 对于不同体系结构或同体系下的不同开发板, 它们的 kbd_init_hw() 的实现代码是不同的 ( 通过

35 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 CONFIG_ARCHXXX 的值来确定 ), 它就是进行键盘的硬件初始化功能 然后将 keyboard tasklet 加入到 tasklet 链表中 至此键盘驱动的初始化工作已经完成 键盘驱动的初始化代码是 keyboard.c 中的 kbd_init, 其源码及分析如下所示 : int init kbd_init(void) int i; struct kbd_struct kbd0; /* 维护 tty/console 对象, 承担 tty 对外的输入和输出 */ extern struct tty_driver console_driver; /* 缺省不亮灯 */ kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; /* 用于显示 flag*/ kbd0.ledmode = LED_SHOW_FLAGS; /* 表示用 key_map 的第一个表, 没有 lock 键 */ kbd0.lockstate = KBD_DEFLOCK; /* 没有粘键 */ kbd0.slockstate = 0; kbd0.modeflags = KBD_DEFMODE; kbd0.kbdmode = VC_XLATE; /* 为每个控制台分配一个 KBD 结构 */ for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i] = kbd0; /* 维护当前各个控制台的 tty_struct 表 */ ttytab = console_driver.table; kbd_init_hw(); /* 把 keyboard_tasklet 挂到 CPU 的运行队列中去 */ tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet); /* 注册电源管理的 KEB 设备 */ pm_kbd =pm_register(pm_sys_dev,pm_sys_kbc,pm_kbd_request_override); return 0; Kbd_init_hw(), 包含了为 keyboard 分配 1/O 端口 分配中断号及对应处理函数 为进行基本保证测试 (BAT) 初始化寄存器, 然后调用在 pc_keyb.c 的 intialize_kbd() 进行硬件初始化, 这是一个非常重要的函数, 它的初始化过程的流程如图 所示

36 图 intialize_kbd() 函数流程 static char * init initialize_kbd(void) int status;

37 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 /* * 测试键盘接口 * 如果测试成功, 那么将会有一个 x55 放在缓冲区中 */ kbd_write_command_w(kbd_ccmd_self_test); if (kbd_wait_for_input()!= 0x55) return "Keyboard failed self test"; /* * 启动一个键盘接口测试, 这时会启动控制器来测试键盘的时钟和数据线, 测试结果放在输入缓冲区中 */ kbd_write_command_w(kbd_ccmd_kbd_test); if (kbd_wait_for_input()!= 0x00) return "Keyboard interface failed self test"; /* * 通过启动键盘时钟使能键盘 */ kbd_write_command_w(kbd_ccmd_kbd_enable); /* * 重启键盘 如果读取时间超时, 就会认为在该机器里没有键盘 * 如果键盘要求再次发送, 则使能键盘重发机制 */ do kbd_write_output_w(kbd_cmd_reset); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status!= KBD_REPLY_RESEND) return "Keyboard reset failed, no ACK"; while (1); if (kbd_wait_for_input()!= KBD_REPLY_POR) return "Keyboard reset failed, no POR"; /* * 设置键盘控制模式, 在这期间, 键盘应该设置为关闭状态

38 */ do kbd_write_output_w(kbd_cmd_disable); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status!= KBD_REPLY_RESEND) return "Disable keyboard: no ACK"; while (1); kbd_write_command_w(kbd_ccmd_write_mode); kbd_write_output_w(kbd_mode_kbd_int KBD_MODE_SYS KBD_MODE_DISABLE_MOUSE KBD_MODE_KCC); if (!(kbd_write_command_w_and_wait(kbd_ccmd_read_mode) & KBD_MODE_KCC)) /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ kbd_write_output_w(0xf0); kbd_wait_for_input(); kbd_write_output_w(0x01); kbd_wait_for_input(); if (kbd_write_output_w_and_wait(kbd_cmd_enable)!= KBD_REPLY_ACK) return "Enable keyboard: no ACK"; /* * 最后, 把键盘读取率设置为最高 */ if (kbd_write_output_w_and_wait(kbd_cmd_set_rate)!= KBD_REPLY_ACK) return "Set rate: no ACK"; if (kbd_write_output_w_and_wait(0x00)!= KBD_REPLY_ACK) return "Set rate: no 2nd ACK";

39 return NULL; 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 (2) 按键处理按键处理是键盘驱动中最为重要的一部分 当有按键事件产生时, 则调用键盘中断处理函数, 也就是 keyboard interrupt(), 它会调用到 handle_kbd_event() 并调用 handle_scancode() 函数 handle_scancode() 这个函数完成按键处理的过程, 它的功能是与 TY 设备通信,Keymap 表装入, 按键处理 handle scancode() 处理的结果就是把按键发给相应的处理函数, 这些函数基本上都会调用 put_queue() 函数 这个函数就是将处理函数的结果发送到 TY 或者 Console 进行显示 下面是 handle_kbd_event 和 handle_scancode 函数源代码 : static unsigned char handle_kbd_event(void) unsigned char status = kbd_read_status(); unsigned int work = 10000; while ((--work > 0) && (status & KBD_STAT_OBF)) unsigned char scancode; scancode = kbd_read_input(); #if 1 #endif /* 错误字节必须被忽略 */ /* 忽略错误字节 */ if (!(status & (KBD_STAT_GTO KBD_STAT_PERR))) if (status & KBD_STAT_MOUSE_OBF) handle_mouse_event(scancode); else handle_keyboard_event(scancode); status = kbd_read_status(); if (!work) printk(kern_err "pc_keyb: controllerjammed (0x%02X).\n",status);

40 return status; static inline void handle_keyboard_event(unsigned char scancode) #ifdef CONFIG_VT kbd_exists = 1; if (do_acknowledge(scancode)) handle_scancode(scancode,!(scancode & 0x80)); #endif tasklet_schedule(&keyboard_tasklet); (3) 转化键盘扫描码在完成键盘的初始化之后, 就需要完成对键盘扫描码的转化 这里调用函数 pckdb_translate, 实现了 scancode 和 keycode 之间的转换 intpckbd_translate(unsignedcharscancode,unsignedchar *keycode,charraw_mode) static int prev_scancode; /* special prefix scancodes.. */ if (scancode == 0xe0 scancode == 0xe1) prev_scancode = scancode; return 0; /* 0xFF 很少被发送, 故可以忽略,0x00 是错误码 */ if (scancode == 0x00 scancode == 0xff) prev_scancode = 0; return 0; scancode &= 0x7f; if (prev_scancode) /* 通常是 0xe0, 但是一个暂停键可以产生 e1 1d 45 e1 9d c5 字符 */ if (prev_scancode!= 0xe0)

41 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 if (prev_scancode == 0xe1 && scancode == 0x1d) prev_scancode = 0x100; return 0; else if (prev_scancode == 0x100 && scancode == 0x45) *keycode = E1_PAUSE; prev_scancode = 0; else #ifdef KBD_REPORT_UNKN if (!raw_mode) printk(kern_info "keyboard:unknowne1escapesequence\n"); #endif prev_scancode = 0; return 0; else prev_scancode = 0; /* * 键盘保持了它自己的内部总线锁和锁状态 在总线锁中, 状态 E0AA 会生成代码, 而状态 E0 2A 会跟随停止码 if (scancode == 0x2a scancode == 0x36) return 0; if (e0_keys[scancode]) *keycode = e0_keys[scancode]; else #ifdef KBD_REPORT_UNKN if (!raw_mode) printk(kern_info "keyboard: unknown scancode e0 %02x\n", scancode); #endif return 0; else if (scancode >= SC_LIM) *keycode = high_keys[scancode - SC_LIM]; if (!*keycode) if (!raw_mode) #ifdef KBD_REPORT_UNKN

42 printk(kern_info "keyboard: unrecognized scancode (%02x)" " - ignored\n", scancode); #endif return 0; else *keycode = scancode; return 1; (4) 按键处理在完成键盘扫描码转换之后就可以开始进行按键处理, 这里用到了 keyboard.c 中的重要函数 kbd_processkeycode 源码如下所示: static void kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat) char raw_mode = (kbd->kbdmode == VC_RAW); if (up_flag) rep = 0; if(!test_and_clear_bit(keycode, key_down)) up_flag = kbd_unexpected_up(keycode); else rep = test_and_set_bit(keycode, key_down); /* 如果键盘自动重复, 那么就要把它忽略, 我们会使用自己的自动重复机制 */ if (rep &&!autorepeat) return; if (kbd_repeatkeycode == keycode!up_flag raw_mode) kbd_repeatkeycode = -1; del_timer(&key_autorepeat_timer); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) sysrq_pressed =!up_flag; goto out;

43 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 else if (sysrq_pressed) if (!up_flag) handle_sysrq(kbd_sysrq_xlate[keycode],kbd_pt_regs,kbd,tty); goto out; #endif /* * 计算下一次需要自动重复的时间 */ if (!up_flag &&!raw_mode) kbd_repeatkeycode = keycode; if (vc_kbd_mode(kbd, VC_REPEAT)) if (rep) key_autorepeat_timer.expires = jiffies +kbd_repeatinterval; else key_autorepeat_timer.expires = jiffies + kbd_repeattimeout; add_timer(&key_autorepeat_timer); if (kbd->kbdmode == VC_MEDIUMRAW) /* soon keycodes will require more than one byte */ put_queue(keycode + up_flag); raw_mode = 1; /* Most key classes will be ignored */ if (!rep (vc_kbd_mode(kbd,vc_repeat) && tty && (L_ECHO(tty) (tty->driver.chars_in_buffer(tty) == 0)))) u_short keysym; u_char type; /* the XOR below used to be an OR */ int shift_final = (shift_state kbd->slockstate) ^ kbd->lockstate;

44 ushort *key_map = key_maps[shift_final]; if (key_map!= NULL) keysym = key_map[keycode]; type = KTYP(keysym); #if 1 #else #endif if (type >= 0xf0) type -= 0xf0; if (raw_mode &&! (TYPES_ALLOWED_IN_RAW_MODE & (1 <<type))) goto out; if (type == KT_LETTER) type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) key_map = key_maps[shift_final ^ (1<<KG_SHIFT)]; if (key_map) keysym = key_map[keycode]; (*key_handler[type])(keysym & 0xff, up_flag); if (type!= KT_SLOCK) kbd->slockstate = 0; else /* maybe only if (kbd->kbdmode == VC_UNICODE)? */ if (!up_flag &&!raw_mode) to_utf8(keysym); else /* 我们至少需要更新移动状态 */ compute_shiftstate(); kbd->slockstate = 0; /* play it safe */ keysym = U(key_maps[0][keycode]); type = KTYP(keysym); if (type == KT_SHIFT) (*key_handler[type])(keysym & 0xff, up_flag);

45 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 rep = 0; out: return; 11.7 实验内容 skull 驱动 1. 实验目的该实验是编写最简单的字符驱动程序, 这里的设备也就是一段内存, 实现简单的读写功能 读者可以了解到整个驱动的编写流程 2. 实验内容该实验要求实现对一段内存的打开 关闭 读写的操作, 并要通过编写测试程序来测试驱动安装是否成功 3. 实验步骤 (1) 编写代码这个简单的驱动程序的源代码如下所示 : #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/malloc.h> #include <asm/uaccess.h> #include <linux/errno.h> /* 全局变量 */ unsigned int fs_major =0; static char *data; /* 关键数据类型, 注意每行结尾是逗号 */ static struct file_operations chr_fops= read: test_read, write: test_write, open: test_open, release: test_release, ;

46 /* 函数声明 */ staticssize_ttest_read(structfile *file,char *buf,size_tcount,loff_t *f_pos); static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos); static int test_open(struct inode *inode, struct file *file); static int test_release(struct inode *inode,struct file *file); int init_module(void); void cleanup_module(void); /* 读函数 */ staticssize_ttest_read(structfile *file,char *buf,size_tcount,loff_t *f_pos) int len; if(count<0) return -EINVAL; len = strlen(data); if(len < count) count = len; copy_to_user(buf,data,count+1); return count; /* 写函数 */ static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos) if(count < 0) return -EINVAL; kfree(data); data = (char *)kmalloc(sizeof(char)*(count+1),gfp_kernel); if(!data) return -ENOMEM; copy_from_user(data,buffer,count+1); return count; /* 打开函数 */ static int test_open(struct inode *inode, struct file *file) MOD_INC_USE_COUNT; printk("this is open\n"); return 0;

47 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 /* 释放函数 */ static int test_release(struct inode *inode,struct file *file) MOD_DEC_USE_COUNT; printk("this is released\n"); return 0; /* 模块注册入口 */ int init_module(void) int res; res=register_chrdev(0,"fs",&chr_fops); if(res<0) printk("can't get major name!\n"); return res; if(fs_major == 0) fs_major = res; return 0; /* 撤销模块入口 */ void cleanup_module(void) unregister_chrdev(fs_major,"fs"); (2) 编译代码 要注意在此处要加上 -DMODULE -D KERNEL 选项, 如下所示 : arm-linux-gcc -DMODULE -D KERNEL -c kernel.c (3) 加载模块 insmod./kernel.o (4) 查看设备号 vi /proc/device (5) 映射为设备文件

48 接下来就要将相应的设备映射为设备文件, 这里可以使用命令 mknod, 如下所示 : mknod /dev/fs c 这里的 /dev/fs 就是相应的设备文件,c 代表字符文件,254 代表主设备号 ( 与 /proc/devices 中一样 ),0 为次设备号 (6) 编写测试代码最后一步是编写测试代码, 也就是用户空间的程序, 该程序调用设备驱动来测试驱动的正确性 上面的实例只实现了简单的读写功能, 测试代码如下所示 : #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <linux/ioctl.h> int main() int fd,i,nwrite,nread; char *buf ="hello\n"; char read_buf[6]=0; fd=open("/dev/fs",o_rdwr); if(fd<=0) perror("open"); exit(1); else printf("open success\n"); nwrite = write(fd,buf,strlen(buf)); if(nwrite<0) perror("write"); exit(1); nread = read(fd,read_buf,6); if(nread<0) perror("read");

49 嵌入式 Linux 应用程序开发详解 第 11 章 嵌入式 Linux 设备驱动开发 exit(1); else close(fd); exit(0); printf("read is %s\n",read_buf); 4. 实验结果在加载模块后可以查看 /var/log/messages 是否有程序中相应的信息输出 : Feb 21 09:49:10 kernel: This is open 查看设备号时有类似如下信息 : 254 fs 这代表 fs 设备的主设备号是 254 最后运行测试程序, 结果如下所示 : [root@(none) tmp]#./testing open success read is hello 查看 /var/log/messages, 有输出信息如下所示 : Feb 21 12:57:06 kernel: This is open Feb 21 12:57:06 kernel: this is released Feb 21 09:43:40 kernel: Goodbye world 本章小结 本章主要介绍了嵌入式 Linux 设备驱动程序的开发 首先介绍了设备驱动程序的概念及 Linux 对设备驱动的处理, 这里要明确驱动程序在 Linux 中的定位 接下来介绍了字符设备驱动程序的编写, 这里详细介绍了字符设备驱动程序的编写流程 重要的数据结构 设备驱动程序的主要组成以及 proc 文件系统 接着又以 LCD 驱动为例介绍了一个较为大型的驱动程序的编写步骤 再接下来, 本章介绍了块设备驱动程序的编写, 主要包括块设备驱动程序描述符和块设备驱动的编写流程 最后, 本章介绍了中断编程, 并以键盘驱动为例进行讲解 本章的实验安排的是 skull 驱动程序的编写, 通过该实验, 读者可以了解到编写驱动程序的整个流程

50 思考与练习 将本章中所述的 lcd 驱动程序运行编译, 并通过模块加载在开发板上测试实验

static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def

static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def Kaise s 2410 Board setting [1]. Device Driver Device Driver Linux s Kernel ARM s kernel s3c2410_kernel2.4.18_r1.1_change.tar.bz2 /usr/src (1) #cd /usr/src (2) #tar xfj s3c2410_kernel2.4.18_r1.1_change.tar.bz2

More information

华恒家庭网关方案

华恒家庭网关方案 LINUX V1.5 1 2 1 2 LINUX WINDOWS PC VC LINUX WINDOWS LINUX 90% GUI LINUX C 3 REDHAT 9 LINUX PC TFTP/NFS http://www.hhcn.com/chinese/embedlinux-res.html minicom NFS mount C HHARM9-EDU 1 LINUX HHARM9-EDU

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,

More information

<4D F736F F D20C7B6C8EBCABDCFB5CDB3BFAAB7A2CAB5D1E9CBC42E646F63>

<4D F736F F D20C7B6C8EBCABDCFB5CDB3BFAAB7A2CAB5D1E9CBC42E646F63> 嵌入式系统实验四 Linux 下设备驱动程序的开发 3.1 设备驱动程序的开发流程 进行嵌入式 Linux 系统的开发, 很大的工作量是为各种设备编写驱动程序 在 ARM 平台上开发嵌入式 Linux 的设备驱动程序与在其他平台上开发是一样的 总的来说, 实现一个嵌入式 Linux 设备驱动的大致流程如下 : (1) 查看原理图, 理解设备的工作原理 (2) 定义主设备号 (3) 在驱动程序中实现驱动的初始化

More information

Bus Hound 5

Bus Hound 5 Bus Hound 5.0 ( 1.0) 21IC 2007 7 BusHound perisoft PC hound Bus Hound 6.0 5.0 5.0 Bus Hound, IDE SCSI USB 1394 DVD Windows9X,WindowsMe,NT4.0,2000,2003,XP XP IRP Html ZIP SCSI sense USB Bus Hound 1 Bus

More information

ebook35-14

ebook35-14 14 V F S L i n u x 14.1 S u p e r I O I D E I D E C S R, C S R L i n u x L i n u x I D E / d e v / h a d m k n o d I D E I D E / d e v / h d a 2 L i n u x Linux /dev/cua0 / d e v / c u a 1 512 1024 BSD

More information

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例 帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例 这篇文章主要介绍了帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例, 本文还详细介绍了帝国 CMS 数据库类中的一些常用方法, 需要的朋友可以参考下 例 1: 连接 MYSQL 数据库例子 (a.php)

More information

Chapter #

Chapter # 第三章 TCP/IP 协议栈 本章目标 通过本章的学习, 您应该掌握以下内容 : 掌握 TCP/IP 分层模型 掌握 IP 协议原理 理解 OSI 和 TCP/IP 模型的区别和联系 TCP/IP 介绍 主机 主机 Internet TCP/IP 早期的协议族 全球范围 TCP/IP 协议栈 7 6 5 4 3 应用层表示层会话层传输层网络层 应用层 主机到主机层 Internet 层 2 1 数据链路层

More information

C/C++语言 - C/C++数据

C/C++语言 - C/C++数据 C/C++ C/C++ Table of contents 1. 2. 3. 4. char 5. 1 C = 5 (F 32). 9 F C 2 1 // fal2cel. c: Convert Fah temperature to Cel temperature 2 # include < stdio.h> 3 int main ( void ) 4 { 5 float fah, cel ;

More information

嵌入式Linux知识培训

嵌入式Linux知识培训 嵌入式 Linux 知识培训 主要包括以下四部分内容 : 一 嵌入式 Linux 开发的基本知识 二 Linux 下使用 C 语言进行系统开发 三 面向嵌入式 Linux 的 GUI 系统的体系结构及二次开发 四 基于 Linux OS Smart Phone 的体系结构及开发内容 李玉东 第一部分 基础知识 嵌入式 Linux 软件系统的构成 1.BootLoader 2. Kernel 3.FileSystem

More information

第11章 可调内核参数

第11章 可调内核参数 11 11 Unix BSD 4.4 Linux sysctl Unix Linux /proc window /proc /proc/sys /proc/sys sysctl Unix root /proc/sys/vm root /proc/sys sysctl /proc/sys struct ctl_table 18274 struct ctl_tables /proc/sys struct

More information

Microsoft PowerPoint - Chapter7-DriverDevices.ppt

Microsoft PowerPoint - Chapter7-DriverDevices.ppt Chapter 7 Device Drivers and Software Interface Design Professor Ching-Lung Su E-mail: kevinsu@yuntech.edu.tw Http://www.eecs.yuntech.edu.tw NYUST/EL P-2/80 Outline 7.1 Introduction to Device Driver 7.2

More information

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++; Memory & Pointer trio@seu.edu.cn 2.1 2.1.1 1 int *p int a 0x00C7 0x00C7 0x00C7 2.1.2 2 int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++; 2.1.3 1. 2. 3. 3 int A,

More information

Guava学习之Resources

Guava学习之Resources Resources 提供提供操作 classpath 路径下所有资源的方法 除非另有说明, 否则类中所有方法的参数都不能为 null 虽然有些方法的参数是 URL 类型的, 但是这些方法实现通常不是以 HTTP 完成的 ; 同时这些资源也非 classpath 路径下的 下面两个函数都是根据资源的名称得到其绝对路径, 从函数里面可以看出,Resources 类中的 getresource 函数都是基于

More information

FY.DOC

FY.DOC 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主

More information

Microsoft Word - 实用案例.doc

Microsoft Word - 实用案例.doc 计 算 机 系 统 应 用 2009 年 第 12 期 嵌 入 式 Linux 下 温 湿 度 传 感 器 的 设 计 与 实 现 1 Design and Implementation of Temperature and Humidity Sensor Based on Embedded Linux 陈 博 刘 锦 高 ( 华 东 师 范 大 学 电 子 科 学 技 术 系 上 海 200241)

More information

chap07.key

chap07.key #include void two(); void three(); int main() printf("i'm in main.\n"); two(); return 0; void two() printf("i'm in two.\n"); three(); void three() printf("i'm in three.\n"); void, int 标识符逗号分隔,

More information

_汪_文前新ok[3.1].doc

_汪_文前新ok[3.1].doc 普 通 高 校 本 科 计 算 机 专 业 特 色 教 材 精 选 四 川 大 学 计 算 机 学 院 国 家 示 范 性 软 件 学 院 精 品 课 程 基 金 青 年 基 金 资 助 项 目 C 语 言 程 序 设 计 (C99 版 ) 陈 良 银 游 洪 跃 李 旭 伟 主 编 李 志 蜀 唐 宁 九 李 涛 主 审 清 华 大 学 出 版 社 北 京 i 内 容 简 介 本 教 材 面 向

More information

6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C C C51 C51 ANSI C MCS-51 C51 ANSI C C C51 bit Byte bit sbit

6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C C C51 C51 ANSI C MCS-51 C51 ANSI C C C51 bit Byte bit sbit 6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C51 6.1 C51 6.1.1 C51 C51 ANSI C MCS-51 C51 ANSI C C51 6.1 6.1 C51 bit Byte bit sbit 1 0 1 unsigned char 8 1 0 255 Signed char 8 11 128

More information

Microsoft Word - 第6章 Android驱动编程.docx

Microsoft Word - 第6章 Android驱动编程.docx Android 系统移植和驱动开发 作者 : 华清远见 第 6 章 Android 驱动编程 本章目标 本章将进入到 Android 的内核空间, 初步介绍嵌入式 Android 设备驱动的开发 驱动的开发流程相对于应用程序的开发是全新的, 与读者以前的编程习惯完全不同, 希望读者能尽快熟悉环境 本章主要内容 : 设备驱动概述 字符设备驱动编程 GPIO 驱动程序实例 4 4 扫描键盘驱动 6.1

More information

手册 doc

手册 doc 1. 2. 3. 3.1 3.2 3.3 SD 3.4 3.5 SD 3.6 3.7 4. 4.1 4.2 4.3 SD 4.4 5. 5.1 5.2 5.3 SD 6. 1. 1~3 ( ) 320x240~704x288 66 (2G SD 320x2401FPS ) 32M~2G SD SD SD SD 24V DC 3W( ) -10~70 10~90% 154x44x144mm 2. DVR106

More information

1

1 SDT Uclinux SDT.alf.c 44blib.alf 44blib.c jtag ADS.alf.c make menuconfig make dep make clean make lib_only make user_only make romfs make image make uclinux ext2 cash lcd frambuffer 1 armsys-c uclinux

More information

untitled

untitled 1 Outline 數 料 數 數 列 亂數 練 數 數 數 來 數 數 來 數 料 利 料 來 數 A-Z a-z _ () 不 數 0-9 數 不 數 SCHOOL School school 數 讀 school_name schoolname 易 不 C# my name 7_eleven B&Q new C# (1) public protected private params override

More information

新・明解C言語入門編『索引』

新・明解C言語入門編『索引』 !... 75!=... 48 "... 234 " "... 9, 84, 240 #define... 118, 213 #include... 148 %... 23 %... 23, 24 %%... 23 %d... 4 %f... 29 %ld... 177 %lf... 31 %lu... 177 %o... 196 %p... 262 %s... 242, 244 %u... 177

More information

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc 2 5 8 11 0 13 1. 13 2. 15 3. 18 1 23 1. 23 2. 26 3. 28 2 36 1. 36 2. 39 3. 42 4. 44 5. 49 6. 51 3 57 1. 57 2. 60 3. 64 4. 66 5. 70 6. 75 7. 83 8. 85 9. 88 10. 98 11. 103 12. 108 13. 112 4 115 1. 115 2.

More information

ebook15-C

ebook15-C C 1 1.1 l s ( 1 ) - i i 4. 14 - d $ l s -ldi /etc/. /etc/.. - i i 3077 drwxr-sr-x 7 bin 2048 Aug 5 20:12 /etc/./ 2 drwxr-xr-x 13 root 512 Aug 5 20:11 /etc/../ $ls -ldi /. /..... i 2 2 drwxr-xr-x 13 root

More information

新版 明解C++入門編

新版 明解C++入門編 511!... 43, 85!=... 42 "... 118 " "... 337 " "... 8, 290 #... 71 #... 413 #define... 128, 236, 413 #endif... 412 #ifndef... 412 #if... 412 #include... 6, 337 #undef... 413 %... 23, 27 %=... 97 &... 243,

More information

untitled

untitled MODBUS 1 MODBUS...1 1...4 1.1...4 1.2...4 1.3...4 1.4... 2...5 2.1...5 2.2...5 3...6 3.1 OPENSERIAL...6 3.2 CLOSESERIAL...8 3.3 RDMULTIBIT...8 3.4 RDMULTIWORD...9 3.5 WRTONEBIT...11 3.6 WRTONEWORD...12

More information

<4D F736F F D20B5DA36D5C22020D7D6B7FBC9E8B1B8C7FDB6AF>

<4D F736F F D20B5DA36D5C22020D7D6B7FBC9E8B1B8C7FDB6AF> LINUX 设备驱动开发详解 作者 : 华清远见 第 6 章 字符设备驱动 Linux Linux 6.1 Linux cdev file_operations Linux 6.2 globalmem 6 9 6.3 6.1 globalmem seek() I/O globalmem 6.4 6.3 globalmem Linux 字符设备驱动结构 6.1.1 cdev 结构体 在 Linux 2.6

More information

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 odps-sdk 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基 开放数据处理服务 ODPS SDK SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基础功能的主体接口, 搜索关键词 "odpssdk-core" 一些

More information

DVK530/531扩展板

DVK530/531扩展板 DVK720 扩展板 驱动移植手册 2014.04.03 V1.0 版权声明 本手册所有权由深圳市微雪电子有限公司独家持有 未经本公司的书 面许可, 不得以任何方式或形式进行修改 分发或复制本文档的任何 部分, 否则一切后果由违者自负 版本更新记录 版本日期说明 V1.0 2014.04.03 初始发布 深圳市微雪电子有限公司 www.waveshare.net I 目录 版权声明... I 版本更新记录...

More information

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1 21 , 7, Windows,,,, : 010-62782989 13501256678 13801310933,,,, ;,, ( CIP) /,,. : ;, 2005. 11 ( 21 ) ISBN 7-81082 - 634-4... - : -. TP316-44 CIP ( 2005) 123583 : : : : 100084 : 010-62776969 : 100044 : 010-51686414

More information

epub 33-8

epub 33-8 8 1) 2) 3) A S C I I 4 C I / O I / 8.1 8.1.1 1. ANSI C F I L E s t d i o. h typedef struct i n t _ f d ; i n t _ c l e f t ; i n t _ m o d e ; c h a r *_ n e x t ; char *_buff; /* /* /* /* /* 1 5 4 C FILE

More information

A Preliminary Implementation of Linux Kernel Virus and Process Hiding

A Preliminary Implementation of Linux Kernel Virus and Process Hiding 邵 俊 儒 翁 健 吉 妍 年 月 日 学 号 学 号 学 号 摘 要 结 合 课 堂 知 识 我 们 设 计 了 一 个 内 核 病 毒 该 病 毒 同 时 具 有 木 马 的 自 动 性 的 隐 蔽 性 和 蠕 虫 的 感 染 能 力 该 病 毒 获 得 权 限 后 会 自 动 将 自 身 加 入 内 核 模 块 中 劫 持 的 系 统 调 用 并 通 过 简 单 的 方 法 实 现 自 身 的

More information

untitled

untitled Lwip Swedish Institute of Computer Science February 20, 2001 Adam Dunkels adam@sics.se (QQ: 10205001) (QQ: 329147) (QQ:3232253) (QQ:3232253) QQ ARM TCPIP LCD10988210 LWIP TCP/IP LWIP LWIP lwip API lwip

More information

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File 51 C 51 51 C C C C C C * 2003-3-30 pnzwzw@163.com C C C C KEIL uvision2 MCS51 PLM C VC++ 51 KEIL51 KEIL51 KEIL51 KEIL 2K DEMO C KEIL KEIL51 P 1 1 1 1-1 - 1 Project New Project 1 2 Windows 1 3 N C test

More information

C 1

C 1 C homepage: xpzhangme 2018 5 30 C 1 C min(x, y) double C // min c # include # include double min ( double x, double y); int main ( int argc, char * argv []) { double x, y; if( argc!=

More information

untitled

untitled 不 料 料 例 : ( 料 ) 串 度 8 年 數 串 度 4 串 度 數 數 9- ( ) 利 數 struct { ; ; 數 struct 數 ; 9-2 數 利 數 C struct 數 ; C++ 數 ; struct 省略 9-3 例 ( 料 例 ) struct people{ char name[]; int age; char address[4]; char phone[]; int

More information

ebook15-10

ebook15-10 1 0 10.1 U N I X V 7 4. 3 B S D S V R 3 P O S I X. 1 100 % 10.2 S I G S I G A B RT a b o r t S I G A L R M a l a r m V 7 1 5 S V R 4 4. 3 + B S D 31 < s i g n a l. h > 0 10. 9 k i l l 0 P O S I X. 1 D

More information

c_cpp

c_cpp C C++ C C++ C++ (object oriented) C C++.cpp C C++ C C++ : for (int i=0;i

More information

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023) ( CIP) /. :, 2005. 2 ( ) ISBN 7-5624-3339-9.......... TP311. 1 CIP ( 2005) 011794 : : : : * : : 174 ( A ) :400030 : ( 023) 65102378 65105781 : ( 023) 65103686 65105565 : http: / /www. cqup. com. cn : fxk@cqup.

More information

/3/15 1, linux. linux,,. : 1.NAT ; 2. (load balance, virtual server);; 3. ; 4. ; 5. 6.VPN; 7. ; 8. ; 9.. (,

/3/15 1, linux. linux,,. : 1.NAT ; 2. (load balance, virtual server);; 3. ; 4. ; 5. 6.VPN; 7. ; 8. ; 9.. (, Yawl(yawl@docshownet) wwwdocshownet 2000/3/15 1, linux linux,, 1NAT ; 2 (load balance,virtual server);; 3 ; 4 ; 5 6VPN; 7 ; 8 ; 9 (,, )IP, (VPN,, ) IP, (call_in_firewall(),call_fw_firewall(),call_out_firewall(),

More information

bingdian001.com

bingdian001.com TSM12M TSM12 STM8L152C6, STM8L152R8 MSP430F5325 whym1987@126.com! /******************************************************************************* * : TSM12.c * : * : 2013/10/21 * : TSM12, STM8L f(sysclk)

More information

JLX

JLX PRODUCT:LCD MODULE. Model No.: JLX177-006 Product Type: 1.77 inch QVGA TFT Modoule. 产品规格书 晶联讯研发研发部 : Written By Checked By Approved By 客户名称 : 结构电子核准 地址 : 深圳市宝安区西乡宝安大道东华工业区 A3 栋 6 楼电话 :0755-29784961 Http://www.jlxlcd.cn

More information

概述

概述 OPC Version 1.6 build 0910 KOSRDK Knight OPC Server Rapid Development Toolkits Knight Workgroup, eehoo Technology 2002-9 OPC 1...4 2 API...5 2.1...5 2.2...5 2.2.1 KOS_Init...5 2.2.2 KOS_InitB...5 2.2.3

More information

<4D F736F F D20B5DAC8FDCBC4D5C2D7F7D2B5B4F0B0B82E646F63>

<4D F736F F D20B5DAC8FDCBC4D5C2D7F7D2B5B4F0B0B82E646F63> 第三章 Q3 1 1. 省略了 I/O 操作的复杂逻辑, 易实现, 耗费低 ; 2. 可以利用丰富的内存寻址模式实现灵活的 I/O 操作 Q3 2 假设存储单元 ds1 处寄存器地址为 0x2000, 代码如下 #define ds1 0x2000 while ( *ds1 == 0 ) ; Q3 3 假设设备 (dev1) 中有两个寄存器 ds1 和 dd1,dev1 的地址为 0x1000,ds1

More information

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha CYPOK CYPOK 1 UltraEdit Project-->Install Language Tool: Language Suite----->hi-tech picc Tool Name ---->PICC Compiler Executable ---->c:hi-picinpicc.exe ( Command-line Project-->New Project-->File Name--->myc

More information

1.01

1.01 2013 操作系统课程设计 内容简介 设计目的 设计内容 实施方法及要求 时间安排 辅导 2 设计目的 掌握 Linux 操作系统的使用方法 ; 了解 Linux 系统内核代码结构 ; 掌握实例操作系统的实现方法 3 内容简介 设计目的 设计内容 实施方法及要求 时间安排 辅导 4 设计内容 (1) 要求 : 熟悉和理解 Linux 编程环境 内容 编写一个 C 程序, 使用 Linux 下的图形库,

More information

Important Notice SUNPLUS TECHNOLOGY CO. reserves the right to change this documentation without prior notice. Information provided by SUNPLUS TECHNOLO

Important Notice SUNPLUS TECHNOLOGY CO. reserves the right to change this documentation without prior notice. Information provided by SUNPLUS TECHNOLO Car DVD New GUI IR Flow User Manual V0.1 Jan 25, 2008 19, Innovation First Road Science Park Hsin-Chu Taiwan 300 R.O.C. Tel: 886-3-578-6005 Fax: 886-3-578-4418 Web: www.sunplus.com Important Notice SUNPLUS

More information

Microsoft Word - 01.DOC

Microsoft Word - 01.DOC 第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的

More information

P4VM800_BIOS_CN.p65

P4VM800_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date [ 17:00:09] [Fri 02/25/2005] BIOS Version : P4VM800 BIOS P1.00 Processor Type : Intel (R) Pentium (R) 4 CPU 2.40 GHz Processor

More information

Car DVD API User Manual V0.2 Feb 03, 2008

Car DVD API User Manual V0.2 Feb 03, 2008 Car DVD API User Manual V0.2 Feb 03, 2008 Important Notice SUNPLUS TECHNOLOGY CO. reserves the right to change this documentation without prior notice. Information provided by SUNPLUS TECHNOLOGY CO. is

More information

六域链联盟 SDChain-Matrix 节点搭建指南 2018/07/26 Version : 1.0.0

六域链联盟 SDChain-Matrix 节点搭建指南 2018/07/26 Version : 1.0.0 SDChain-Matrix 节点搭建指南 目录 1 环境要求... 3 2 软件下载... 4 3 安装部署... 4 3.1 部署可执行程序目录... 4 3.2 部署配置文件目录... 4 3.3 部署数据库文件目录... 4 3.4 部署日志文件目录... 4 3.5 部署依赖库文件目录... 4 4 配置参数... 5 5 启动运行... 7 5.1 普通模式启动... 7 5.2 加载启动模式...

More information

P4V88+_BIOS_CN.p65

P4V88+_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date [ 17:00:09] [Wed 12/22/2004] BIOS Version : P4V88+ BIOS P1.00 Processor Type : Intel (R) Pentium (R) 4 CPU 2.40 GHz Processor

More information

目录

目录 ALTERA_CPLD... 3 11SY_03091... 3 12SY_03091...4....5 21 5 22...8 23..10 24..12 25..13..17 3 1EPM7128SLC.......17 3 2EPM7032SLC.......18 33HT46R47......19..20 41..20 42. 43..26..27 5151DEMO I/O...27 52A/D89C51...28

More information

Microsoft Word - MAN2023A_CH_APPONE.doc

Microsoft Word - MAN2023A_CH_APPONE.doc AT91 softpack 1.5 代码解读 基于 SAM7X EK 综合应用代码解读 文档编号 文档版本 Rev. A 文档摘要 基于 AT91SAM7X EK 开发板的代码解读,GPIO H161T01 代码解读 关键词 AT91SAM7X256 系统板 创建日期 2010 07 14 创建人员 Cust126 审核人员 Robin 文档类型 公开发布 / 开发板配套文件 版权信息 Mcuzone

More information

Microsoft PowerPoint - 嵌入式系统设计课件第五讲.ppt

Microsoft PowerPoint - 嵌入式系统设计课件第五讲.ppt 嵌入式软件系统 嵌入式软件系统的开发形式 嵌入式系统软件的组成 嵌入式系统开发常用协议 嵌入式系统的引导代码 嵌入式系统的内核 Linux 设备驱动程序开发 嵌入式软件系统的开发形式 基于裸机的开发无须操作系统的支持, 软件的每个代码都需要软件程序员进行开发, 一般采用汇编语言, 大多开发简单系统, 如家用电器的简单控制, 适用嵌入式微控制器 基于嵌入式操作系统的开发小型嵌入式系统应用, 不需要复杂文件系统,

More information

<4D F736F F F696E74202D20B5DAB6FEBDB2A3BAC7B6C8EBCABD4C696E75782D416E64726F6964C7FDB6AFBFAAB7A2BDD2C3D8D6AED2BABEA7C6C1C7FDB6AFBFAAB7A22DB9F9C0CFCAA62E BBCE6C8DDC4A3CABD5D>

<4D F736F F F696E74202D20B5DAB6FEBDB2A3BAC7B6C8EBCABD4C696E75782D416E64726F6964C7FDB6AFBFAAB7A2BDD2C3D8D6AED2BABEA7C6C1C7FDB6AFBFAAB7A22DB9F9C0CFCAA62E BBCE6C8DDC4A3CABD5D> 在线大讲堂 手机驱动开发揭秘之液晶屏驱动开发 版权 华清远见嵌入式培训中心版权所有 ; 未经华清远见明确许可, 不能为任何目的以任何形式复制或传播此文档的任何部分 ; 本文档包含的信息如有更改, 恕不另行通知 ; 保留所有权利 2 主要内容 1. 液晶屏技术背景 2. 液晶屏接口分析 3. 液晶屏驱动框架分析 液晶屏与触摸屏关系 显示输出 控制输入 液晶屏与触摸屏关系 输入设备 软件 计算机硬件接口

More information

C语言的应用.PDF

C语言的应用.PDF AVR C 9 1 AVR C IAR C, *.HEX, C,,! C, > 9.1 AVR C MCU,, AVR?! IAR AVR / IAR 32 ALU 1KBytes - 8MBytes (SPM ) 16 MBytes C C *var1, *var2; *var1++ = *--var2; AVR C 9 2 LD R16,-X ST Z+,R16 Auto (local

More information

第 14 行调用 of_demo_controller_register 注册 demo controller 驱动,xlate 函数设置的都是 of_demo_simple_xlate, 这个函数完成对 user 传来的参数的处理 1. int of_demo_controller_registe

第 14 行调用 of_demo_controller_register 注册 demo controller 驱动,xlate 函数设置的都是 of_demo_simple_xlate, 这个函数完成对 user 传来的参数的处理 1. int of_demo_controller_registe 作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Linux 4.10.17 概述 上一篇大概介绍了一下 demo controller 的结构, 下面结合驱动分析 正文 一 demo controller 驱动 这里主要分析 probe 函数 demo_controller_probe: 1. static int demo_controller_probe(struct

More information

untitled

untitled 3 C++ 3.1 3.2 3.3 3.4 new delete 3.5 this 3.6 3.7 3.1 3.1 class struct union struct union C class C++ C++ 3.1 3.1 #include struct STRING { typedef char *CHARPTR; // CHARPTR s; // int strlen(

More information

提纲 1 2 OS Examples for 3

提纲 1 2 OS Examples for 3 第 4 章 Threads2( 线程 2) 中国科学技术大学计算机学院 October 28, 2009 提纲 1 2 OS Examples for 3 Outline 1 2 OS Examples for 3 Windows XP Threads I An Windows XP application runs as a seperate process, and each process may

More information

51 C 51 isp 10 C PCB C C C C KEIL

51 C 51 isp 10   C   PCB C C C C KEIL http://wwwispdowncom 51 C " + + " 51 AT89S51 In-System-Programming ISP 10 io 244 CPLD ATMEL PIC CPLD/FPGA ARM9 ISP http://wwwispdowncom/showoneproductasp?productid=15 51 C C C C C ispdown http://wwwispdowncom

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

Windows 2000 Server for T100

Windows 2000 Server for T100 2 1 Windows 95/98 Windows 2000 3.5 Windows NT Server 4.0 2 Windows DOS 3.5 T200 2002 RAID RAID RAID 5.1 Windows 2000 Server T200 2002 Windows 2000 Server Windows 2000 Server Windows 2000 Server 3.5 for

More information

mvc

mvc Build an application Tutor : Michael Pan Application Source codes - - Frameworks Xib files - - Resources - ( ) info.plist - UIKit Framework UIApplication Event status bar, icon... delegation [UIApplication

More information

Microsoft Word - AN3259C

Microsoft Word - AN3259C www.maxim-ic.com.cn 应用笔记 3259 DS31256 Envoy - 寄存器转储列程 概述本应用笔记提供了将 DS31256 的寄存器 排队程序 描述符和 FIFO RAM 的内容转储到一个文件的程序代码 这些数据在 DS31256 无法正常工作时非常关键, 为进一步的研究和调试提供了重要信息 例如, 寄存器数据经过转储后可以显示每个 DS31256 寄存器的设置 为了保证正确地设置器件,

More information

untitled

untitled 1 DBF (READDBF.C)... 1 2 (filetest.c)...2 3 (mousetes.c)...3 4 (painttes.c)...5 5 (dirtest.c)...9 6 (list.c)...9 1 dbf (readdbf.c) /* dbf */ #include int rf,k,reclen,addr,*p1; long brec,erec,i,j,recnum,*p2;

More information

ebook15-12

ebook15-12 1 2I / O 12.1 I / O V I / O s e l e c tp o l l r e a d vw r i t e v I / Om m a p 14 15 12.2 I / O 1 0. 5 F I F O F I F O i o c t l 14 I / O I / o p e n, r e a dw r i t e I / O (1) o p e n O _ N O N B L

More information

How to Debug Tuxedo Server printf( Input data is: %s, inputstr); fprintf(stdout, Input data is %s, inputstr); fprintf(stderr, Input data is %s, inputstr); printf( Return data is: %s, outputstr); tpreturn(tpsuccess,

More information

untitled

untitled www.mcudriver.cn 1.1 / 1) WinAVR20070525 2) Source Insight 3) ISP 4) PonyProg ISP 5) USB 6) 1.2. MCU ATMEGA16 1.3. AVR8 1.4 LED0~LED7 1 1.5 #include // Program 1.1 LED.C #define uchar unsigned

More information

1 CPU interrupt INT trap CPU exception

1 CPU interrupt INT trap CPU exception 1 CPU interrupt INT trap CPU exception 2 X86 CPU gate 64 16 1 2 5 8 16 16 P DPL 00101 TSS 101 DPL P 1 64 16 1 2 1 1 3 3 5 16 16 16 P DPL 0 D 000 16 110 111 100 D 1=32 0=16 DPL P 1 INT DPL1>=CPL>=DPL CPU

More information

Abstract arm linux tool-chain root NET-Start! 2

Abstract arm linux tool-chain root NET-Start! 2 Lab III - Embedding Linux 1 Abstract arm linux tool-chain root NET-Start! 2 Part 1.4 Step1. tool-chain 4 Step2. PATH 4 Part 2 kernel 5 Step1. 5 Step2... 6 Step3...8 Part 3 root. 8 Step1. 8 Step2. 8 Part

More information

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 177 [P179] (1) - [P181] [P182] (2) - for [P183] (3) - switch [P184] [P187] [P189] [P194] 178 [ ]; : : int var; : int var[3]; var 2293620 var[0] var[1] 2293620

More information

嵌入式Linux块设备驱动开发解析

嵌入式Linux块设备驱动开发解析 The success's road 嵌 入 式 LINUX 网 络 驱 动 开 发 Copyright 2007-2008 Farsight. All rights reserved. 要 点 Linux 网 络 设 备 驱 动 程 序 概 述 计 算 机 网 络 概 述 skbuf 数 据 结 构 介 绍 Linux 网 络 设 备 驱 动 程 序 API 介 绍 Linux 网 络 设 备 驱

More information

系统架构 - 模块划分 功能 状态机 H265 主要的模块 : 1. 顶层模块 H265ENC_top 包括 sys_ctrl,enc_core 及 fetch 三个模块 2. sys_ctrl 就是一个状态机, 控制 fetch 和 enc_core 中各子模块的工作 3. enc_core 编码

系统架构 - 模块划分 功能 状态机 H265 主要的模块 : 1. 顶层模块 H265ENC_top 包括 sys_ctrl,enc_core 及 fetch 三个模块 2. sys_ctrl 就是一个状态机, 控制 fetch 和 enc_core 中各子模块的工作 3. enc_core 编码 3.1 系统架构与模块仿真文件 作者 : 江亲炜 日期 :2017/1/8 系统架构 - 模块划分 功能 状态机 H265 主要的模块 : 1. 顶层模块 H265ENC_top 包括 sys_ctrl,enc_core 及 fetch 三个模块 2. sys_ctrl 就是一个状态机, 控制 fetch 和 enc_core 中各子模块的工作 3. enc_core 编码器的核心 4. 存取 cur_pixel

More information

/ / (FC 3)...

/ / (FC 3)... Modbus/TCP 1.0 1999 3 29 Andy Swales Schneider aswales@modicon.com ... 2 1.... 3 2.... 3 2.1.. 3 2.2..4 2.3..4 2.4... 5 3.... 5 3.1 0... 5 3.2 1... 5 3.3 2... 6 3.4 / /... 7 4.... 7 5.... 8 5.1 0... 9

More information

学习MSP430单片机推荐参考书

学习MSP430单片机推荐参考书 MSP430 16 MSP430 C MSP430 C MSP430 FLASH 16 1 CPU 16 ALU 16 PC SP SR R4~R15 2 3 00-FFH 100-1FFH 4 5 1 2 51 24 27 6 1 2 3 4 5 6 4 12 SR SP SR CPU SR CPU C Z N GIE CPUOff CPU OscOff SCG0 SCG1 CPU EXIT SP

More information

Microsoft Word - 11.doc

Microsoft Word - 11.doc 除 錯 技 巧 您 將 於 本 章 學 到 以 下 各 項 : 如 何 在 Visual C++ 2010 的 除 錯 工 具 控 制 下 執 行 程 式? 如 何 逐 步 地 執 行 程 式 的 敘 述? 如 何 監 看 或 改 變 程 式 中 的 變 數 值? 如 何 監 看 程 式 中 計 算 式 的 值? 何 謂 Call Stack? 何 謂 診 斷 器 (assertion)? 如 何

More information

Linux kernel exploit研究和探索

Linux kernel exploit研究和探索 Linux kernel exploit DOC alert7 PPT e4gle 2002-12-2 1 2002-12-2 2 Linux kernel exploit kernel exploit exploit exploit exploit (Kernel Buffer Overflow) (Kernel

More information

nooog

nooog C : : : , C C,,, C, C,, C ( ), ( ) C,,, ;,, ; C,,, ;, ;, ;, ;,,,, ;,,, ; : 1 9, 2 3, 4, 5, 6 10 11, 7 8, 12 13,,,,, 2008 1 1 (1 ) 1.1 (1 ) 1.1.1 ( ) 1.1.2 ( ) 1.1.3 ( ) 1.1.4 ( ) 1.1.5 ( ) 1.2 ( ) 1.2.1

More information

3.1 num = 3 ch = 'C' 2

3.1 num = 3 ch = 'C' 2 Java 1 3.1 num = 3 ch = 'C' 2 final 3.1 final : final final double PI=3.1415926; 3 3.2 4 int 3.2 (long int) (int) (short int) (byte) short sum; // sum 5 3.2 Java int long num=32967359818l; C:\java\app3_2.java:6:

More information

C/C++语言 - 分支结构

C/C++语言 - 分支结构 C/C++ Table of contents 1. if 2. if else 3. 4. 5. 6. continue break 7. switch 1 if if i // colddays.c: # include int main ( void ) { const int FREEZING = 0; float temperature ; int cold_ days

More information

Microsoft Word - PS2_linux_guide_cn.doc

Microsoft Word - PS2_linux_guide_cn.doc Linux For $ONY PlayStatioin2 Unofficall General Guide Language: Simplified Chinese First Write By Beter Hans v0.1 Mail: hansb@citiz.net Version: 0.1 本 人 是 菜 鸟 + 小 白 欢 迎 指 正 错 误 之 处, 如 果 您 有 其 他 使 用 心 得

More information

行业

行业 PCI-1711/1711L 1.1...2 1.1.1...2 1.1.2...2 1.1.3 FIFO...2 1.1.4...2 1.1.5 16 16...3 1.2...3 2.1...3 2.2...3 2.2.1... 2.2.2...8 2.3...10 2.3.1...10 2.3.2... 11 2.3.3...12 2.3.4...13 2.4.5...14 3.1...16

More information

PowerPoint 演示文稿

PowerPoint 演示文稿 Linux 盘符绑定实现原理 http://www.ilinuxkernel.com 正一 2016.7.25 目录 Linux 盘符的分配 Linux 内核 IDR 机制 Linux 盘符绑定 Linux 盘符的分配 sd_probe() 函数 系统中有新的 SCSI 磁盘 ( 包括 USB 硬盘 ) 插入, 就会调用 sd_probe() 函数 哪里决定盘符? 01438: spin_lock(&sd_index_lock

More information

uClinux for blackfin

uClinux for blackfin uclinux Blackfin support@besovideo.com QQ 21ic http://bbs.21ic.com/club/bbs/bbsview.asp?boardid=51 24! support@besovide o.com R&D BF561 Linux C MemoryMAP 32 X86 *((volatile unsigned short *)(0x10000300))=0xf0c0;

More information

Microsoft Word - MSP430 Launchpad 指导书.docx

Microsoft Word - MSP430 Launchpad 指导书.docx Contents 3... 9... 14 MSP430 LAUNCHPAD 指导书 3 第一部分第一个工程 New Project File > New > CCS Project Project name: ButtonLED Device>Family: MSP430 Variant: MSP430G2553 Project templates and examples : Empty Project

More information

行业

行业 PCI-1710 1.1...2 1.1.1...2 1.1.2...2 1.1.3 FIFO( )...2 1.1.4...2 1.1.5...2 1.1.6 16 16...3 1.1.7...3 1.2...3 1.3...3 2.1...3 2.2...4 2.2.1...4 2.2.2...5 2.3...9 2.3.1...10 2.3.2... 11 2.3.3...12 2.3.4...12

More information

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml

res/layout 目录下的 main.xml 源码 : <?xml version=1.0 encoding=utf 8?> <TabHost android:layout_height=fill_parent xml 拓展训练 1- 界面布局 1. 界面布局的重要性做应用程序, 界面是最基本的 Andorid 的界面, 需要写在 res/layout 的 xml 里面, 一般情况下一个 xml 对应一个界面 Android 界面布局有点像写 html( 连注释代码的方式都一样 ), 要先给 Android 定框架, 然后再在框架里面放控件,Android 提供了几种框架,AbsoluteLayout,LinearLayout,

More information

ebook 132-6

ebook 132-6 6 SQL Server Windows NT Windows 2000 6.1 Enterprise Manager SQL Server Enterprise Manager( ) (Microsoft Management C o n s o l e M M C ) Enterprise Manager SQL Server Enterprise Manager 6.1.1 Enterprise

More information

K7VT2_QIG_v3

K7VT2_QIG_v3 ............ 1 2 3 4 5 [R] : Enter Raid setup utility 6 Press[A]keytocreateRAID RAID Type: JBOD RAID 0 RAID 1: 2 7 RAID 0 Auto Create Manual Create: 2 RAID 0 Block Size: 16K 32K

More information

一个开放源码的嵌入式仿真环境 ― SkyEye

一个开放源码的嵌入式仿真环境 ― SkyEye SkyEye SkyEye http://hpclab.cs.tsinghua.edu.cn/~skyeye/ I hear and I forget, I see and I remember, I do and I understand. SkyEye SkyEye SkyEye SkyEye SkyEye 1. SkyEye PC pervasive computing PC I O PDA

More information

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢   学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 Email: 51141201063@ecnu.cn 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Java 类型 引用 不可变类型 对象存储位置 作用域 OOP

More information

PCMCIA Compact Flash GPRS GPS PCMCIA Personal Computer Memory Card International Association CF Compact Flash PCMCIA CF PCMCIA/CF

PCMCIA Compact Flash GPRS GPS PCMCIA Personal Computer Memory Card International Association CF Compact Flash PCMCIA CF PCMCIA/CF 09 PCMCIA Compact Flash GPRS GPS PCMCIA Personal Computer Memory Card International Association CF Compact Flash PCMCIA CF PCMCIA/CF PCMCIA WiFi Linux PCMCIA PCMCIA/CF 9-1 PCMCIA/CF PCMCIA 16 CF PCMCIA

More information

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 ->

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 -> 目录 1 大概思路... 1 2 创建 WebAPI... 1 3 创建 CrossMainController 并编写... 1 4 Nuget 安装 microsoft.aspnet.webapi.cors... 4 5 跨域设置路由... 4 6 编写 Jquery EasyUI 界面... 5 7 运行效果... 7 8 总结... 7 1 1 大概思路 创建 WebAPI 创建 CrossMainController

More information

内 容 1 2 3 4 培 训 目 标 基 础 知 识 常 用 监 控 命 令 在 实 战 中 综 合 运 用 2

内 容 1 2 3 4 培 训 目 标 基 础 知 识 常 用 监 控 命 令 在 实 战 中 综 合 运 用 2 Linux 常 用 监 控 命 令 介 绍 基 础 应 用 组 梁 若 羽 2011-07-12 1 内 容 1 2 3 4 培 训 目 标 基 础 知 识 常 用 监 控 命 令 在 实 战 中 综 合 运 用 2 培 训 目 标 掌 握 常 用 监 控 命 令 的 用 途 和 启 用 方 法 熟 悉 各 个 关 键 输 出 参 数 的 真 实 含 义 了 解 Linux 操 作 系 统 的 一

More information