标签:
一、概述
Linux内核就是由各种驱动组成的,内核源码中大约有85%的各种渠道程序的代码。一般来说,编写Linux设备驱动大致流程如下:
1、查看原理图,数据手册,了解设备的操作方法。
2、在内核中找到相近的驱动程序,以它为模板开发。
3、实现驱动的初始化:比如像内核注册这个驱动程序
4、设计要实现的操作:open,close,read,write等
5、实现中断服务(不是必须的)
6、编译该驱动程序到内核中,或insmod命令加载
7、测试驱动程序。
二、驱动程序的加载与卸载
module_init(my_init);
module_exit(my_clearup);
三、字符设备驱动程序主要的数据结构
1、系统调用:应用程序不能直接操作硬件,而是使用统一的接口函数调用硬件驱动程序。这些接口成为系统调用。在库函数中定义了,可以在gilbc的fcntl.h, unistd.h,sys/ioctl.h 等文件找到。open,wirite,read等。
2、数据结构file_operations是在内核中的,在include/linux/fs.h中。定义如下:
/* * NOTE: * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl * can be called without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 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); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); };
3、设备的主次设备号-=
内核靠这个寻找对应的驱动程序。应用程序在操作设备文件时,Linux系统就会根据设备文件的类型,主设备号在内核中注册的file_operation(对于块设备号是block_device_operations结构),次设备号来分辨它是同类设备中的第几个。
4、注册函数与卸载函数
register_chrdev;unregister_chrdev;
四、LED驱动程序
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> //定义寄存器 volatile unsigned long *gpfcon=NULL; volatile unsigned long *gpfdat=NULL; static struct class *myFirD_class;//为了能自动创建mdev static struct class_device *myFirD_class_dev; //打开 static int myFirD_open(struct inode *inode, struct file *file) { printk("myFirD has open\n"); //配置IO口 *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));//相与 *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));//相或 return 0; } //写 static ssize_t myFirD_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int val; //printk("first_drv_write\n"); copy_from_user(&val, buf, count); // copy_to_user(); if (val == 1) { // 点灯 *gpfdat &= ~((1<<4) | (1<<5) | (1<<6)); } else { // 灭灯 *gpfdat |= (1<<4) | (1<<5) | (1<<6); } return 0; } //定义一个结构 static struct file_operations myFirD_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = myFirD_open, .write = myFirD_write, }; //需要用函数把结构告诉内核。注册驱动程序 int major; //主设备号 int myFirD_init(void) { major=register_chrdev(0,"myFirD",&myFirD_fops);//告诉内核 myFirD_class = class_create(THIS_MODULE, "myFirD");//建个类 //设备 myFirD_class_dev = class_device_create(myFirD_class, NULL, MKDEV(major, 0), NULL, "xyz"); gpfcon=(volatile unsigned *)ioremap(0x56000050,16); gpfdat = gpfcon + 1;; return 0; } void myFirD_exit(void) { unregister_chrdev(major,"myFirD");//告诉内核 class_device_unregister(myFirD_class_dev); class_destroy(myFirD_class); iounmap(gpfcon); } module_init(myFirD_init); module_exit(myFirD_exit); MODULE_LICENSE("GPL");
五、Makefile文件
KERN_DIR = /work/system/linux-2.6.22.6#内核所在的目录 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += myFirD.o
标签:
原文地址:http://www.cnblogs.com/NEIL-X/p/4840436.html