ARM驱动开发入门

2019-07-12 23:32发布

驱动分类

1   常规分类 1.1       字符设备:以字节为最小访问单位的设备,通常支持open,close,read,write系统调用。如串口、LED、按键 1.2       块设备:以块为最小访问单位的设备(块一般为512字节或512字节的倍数),linux中允许块设备传送任意字节数。如硬盘、flash、SD卡。 1.3       网络接口:负责发送和接收数据报文,可以是硬件设备,如网卡,也可以是纯软件设备,如回环接口(lo) 2   总线分类法                1.1             USB设备                1.2             PCI设备                1.3             平台总线设备

学习方法

1   构建驱动模型 2   添加硬件操作 3   驱动测试

硬件访问

1   地址映射 1.1 静态映射 void *ioremap(physaddr,size) physaddr:待映射的物理地址 size:映射的区域长度 返回值:映射后的虚拟地址 1.2 动态映射 用户事先指定映射关系,在内核启动时自动将物理地址映射为虚拟地址。 struct map_desc {      unsigned long virtual;/映射后的虚拟地址      unsigned long pfn;/物理地址所在的页帧号      unsigned long length;/映射长度      unsigned int type;/映射的设备类型 } 2   寄存器读写 unsigned ioread8(void *addr) unsigned ioread16(void *addr) unsigned readb(address) unsigned readw(address) unsigned readl(address)   void iowrite8(u8 value,void *addr) void iowrite16(u16 value,void *addr) void iowrite32(u32 value,void *addr) void writeb(unsigned value, address) void writew(unsigned value, address) void writel(unsigned value, address)

驱动的运用

1   编译安装驱动 1.1 创建Makefile obj-m := memdev.o KDIR := /home/…/linux-tq2440 all: make–C $( KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm 1.2 拷贝驱动(内核模块)到/…/rootfs 1.3 安装驱动程序 insmod  memdev.ko 1.4 查看 lsmod 2   字符设备文件 2.1       查看主设备号 cat /proc/devices 主设备号   设备名 2.2       创建设备文件 mknod /dev/文件名 c 设备号 次设备号(0~255) 3   应用程序 3.1 打开字符设备文件 fd = open(“/dev/memdev0”,O_RDWR); 3.2 操作字符设备文件 write(fd,&buf,sizeof(int)); read(fd,&buf,sizeof(int)); 3.3 关闭字符设备文件 close(fd); 3.4 编译(静态编译) arm-linux-gcc –static 文件名.c –O文件名

字符设备驱动模型

1    设备描述结构cdev 1.1 结构定义 struct cdev { struct kobject kobl; struct module *owner; const struct file operations *ops ;//设备操作集 struct lis thead list; dev_t dev;//设备号。 unsigned int count;设备数 } 1.2 设备号类型dev_t 1.2.1 dev_t介绍:实质为32位的unsigned int,高十二位为主设备号,低二十位为次设备号。 1.2.2 操作设备号: dev_t dev=MKDEV(主设备号,次设备号) 主设备号=MAJOR(dev_t dev) 次设备号=MINOR(dev_t dev) 1.2.3 申请设备号: 静态申请:intregister_chrdev_region(dev_t first, unsigned int count, char *name); first: 待分配的起始设备编号,通常为0; count: 连续设备编号的总数 name:设备名(cat /proc/devices) 动态申请:intalloc_chrdev_region(dev_t *dev,unsigned int -firstminor,unsigned int -count,char*name) dev:得到的设备号保存位置 -firstminor: 待分配的起始设备编号,通常为0; -count: 连续设备编号的总数 name: 设备名(cat /proc/devices) 1.2.4 注销设备号:unregister_chardev_region 1.3 操作集struct file operations 1.3.1 structfile operations介绍:函数指针的集合,定义能在设备上进行的操作。对于不支持的操作设置为NULL 1.3.2 例:struct file operations dev_fops = { .llseek  = NULL; .read= dev_read, .write= dev_write, .ioctl= dev_inctl, .open= dev_open, .release= dev_release, }; 2    驱动初始化 2.1 分配设备描述结构     静态分配:structcdev mdev; 动态分配:structcdev *pdev = cdev_alloc(); 2.2 初始化设备描述结构 cdev_init(struct cdev*cdev,const struct file_operations *fops) *cdev:待初始化的cdev结构/*fops:设备对应的操作函数集 2.3 注册设备描述结构     cdev_add(struct cdev *p,dev_t dev,unsignedcount) p:待添加到内核的字符设备结构 dev:设备号 count:该类设备的设备个数 2.4 硬件初始化 3         设备操作(设备方法) 3.1 int  (*open) (struct inode *,struct file *)  打开设备,响应open系统 3.1.1 structfile: 3.1.1.1   linux系统中,每个打开的文件,都会关联一个structfile,由内核在文件打开时创建,文件关闭后释放 3.1.1.2   重要成员 loff_t f_pos   //文件读写指针 struct file_operation*f_op  //文件对应的操作 3.1.2 structinode 3.1.2.1   每个存在于文件系统的文件都会关联一个inode结构,记录文件物理信息。 3.1.2.2   重要成员: dev_t i_rdev   //设备号 3.2 int  (*release) (struct inode *,struct file*)  关闭设备,响应close系统 3.3 loff_t  (*llseek) (struct file *,loff_t,int)  重定位读写指针,响应lseek系统调用 3.4 ssize_t(*read) (struct file *,char _user *,size_t,loff_t *)  从设备读取数据,响应read系统调用 3.4.1 参数分析: filp:与字符设备文件关联的file结构指针,由内核创建 buff:从设备读到的数据需要保存的位置,由read系统调用提供 count:请求传输的数据量,由read系统调用提供 offp:文件读写位置,由内核从file结构中取出传递进来 3.4.2 从设备中读取数据(硬件访问类操作) 3.4.3 将读到的数据返回给应用程序 3.5 ssize_t(*write) (struct file *,const char _user *,size_t,loff_t *)  向设备写入数据,响应write系统调用 3.5.1 参数分析: filp:与字符设备文件关联的file结构指针,由内核创建 buff:从设备读到的数据需要保存的位置,由read系统调用提供 count:请求传输的数据量,由read系统调用提供 offp:文件读写位置,由内核从file结构中取出传递进来 3.5.2 从应用程序提供的地址中取出数据 3.5.3 将数据写入设备(硬件访问类操作) 4         驱动注销 4.1       用cdev_del函数卸载驱动程序