linux系统驱动基础学习笔记

Linux驱动:
 
角色:应用程序

      API
      操作系统
      驱动
 
     实际硬件


功能:
1.对设备进行初始化和释放
2.把数据从内核传送到硬件和从硬件读取数据
3.检测和处理设备出现的错误

Linux驱动程序类型:
字符设备:由文件系统管理    (通过设备文件访问)
块设备:由文件系统管理
网络设备:由协议栈管理      (通过socket访问)


查看系统设备文件
ls -l /dev
cat /proc/devices
cat /sys/power/state

属性:文件类型   主设备号   次设备号
设备编号:<linux/types.h>
    dev_t  32位,12为主设备号,20位为次设备号
实际使用:<linux/kdev_t.h>
dev_t --> 主设备号,次设备号
MAJOR(dev_t dev);
MINOR(dev_t dev);
主设备号,次设备号-->(dev_t)
MKDEV(int major,int minor)


设备驱动组成:
1.配置初始化,注册设备,检测硬件设备是否正常工作。
2.服务于I/O请求的子程序
3.中断服务子程序

1.系统运行时编译并加载,卸载模块:insmod,rmmod
2.Linux内核源代码中编译成模块,启动后用insmod,rmmod
 或者直接在源代码中加载进内核。

输出:内核编程不能使用用户态C库函数中的printf()
只能用printk().为日志机制,记录日志信息或者给出警告提示。(var/log/messages)

日志级别:默认:DEFAULT_MESSAGE_LOGLEVEL   4
<linux/kernel.h>
 #define KERN_EMERG    "<0>"    /* system is unusable */
#define KERN_ALERT    "<1>"    /* action must be taken immediately */
#define KERN_CRIT     "<2>"    /* critical conditions */
#define KERN_ERR      "<3>"    /* error conditions */
#define KERN_WARNING  "<4>"    /* warning conditions */
#define KERN_NOTICE   "<5>"    /* normal but significant */
#define KERN_INFO     "<6>"    /* informational */
#define KERN_DEBUG    "<7>"    /* debug-level messages */

当优先级小于int console_loglevel变量的时候,消息打印到控制台上。
如果syslogd和klogd守护进程在运行的话,消息只能加进var/log/messages文件
klogd只处理内核信息,syslogd处理其他系统信息,比如应用程序


驱动程序与应用程序的区别:
1.驱动没有main,以模块初始化函数为入口
2.驱动完成初始化后不再运行,等待系统调用
3.驱动不能使用标准C库


*编译驱动到内核模板:
1.而配置Kconfig,打开linux-2.6.32.2/drivers/char/Kconfig,
找到MINI2440_HELLO_MODULE,复制一段下来,修改成:
config MY_HELLO
        tristate "my hello module"
        depends on MACH_MINI2440
        default m if MACH_MINI2440
        help
          Mini2440 module samples
2.在make menuconfig,可以在Device Drivers-> Character devices中看到my hello module
选择为M

3.打开linux-2.6.32.2/drivers/char/Makefile
  在有CONFIG_MINI2440_HELLO_MODULE下增加:
  obj-S(CONFIG_MY_HELLO)  +=hello.o

4.回到根目录,执行:make modules
  生成:hello.ko


系统运行后编译模板基本步骤:
1.编译
      make
      即等于:make modules

  Makefile中:
  先看KERNELRELEASE是在linux内核源码中主Makefile中是否定义,如果定义,则编译生成目标文件
  若未定义:定义:主机:KERNELDIR ?= /lib/modules/$(shell uname -r)/build
                开发板:KERNELDIR ?=/mnt/hgfs/LinuxShared/linux-2.6.32/linux-2.6.32.2
  即KERNELDIR是本Makefile 依赖的linux内核源码路径  ,如是交叉编译时就取开发板上运行的源码路径

make:  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
到linux源码所在的目录执行主Makefile 并当前路径传给主Makefile,告诉主Makefile执行完后返回到当前目录,执行Makefile


2.安装模块
      insmod hello.ko
 modprobe -r filename 加载驱动时会同时加载该模块所依赖的其他模块。

  insmod 模块名 参数名=参数值

定义参数:
module_param(参数名、参数类型、参数读写属性)
static char *string_test = “this is a test”;  
static num_test = 1000;    
module_param (num_test,int,S_IRUGO);  
module_param (steing_test,charp,S_ITUGO); 

3.显示模块
      lsmod |grep hello
4.删除模块
      rmmod hello

5.获取模块信息
      modinfo hello.ko
6.清除
     make clean

 

 

---字符驱动---

操作步骤:
//设备的探测和初始化

************************************************************
static __init int myinit(void)
{
      //设备探测相关的
 //1.设备的常用属性分配 -- 设备名,设备号
 //2.设备的注册

 //设备初始化
 //1.驱动中使用的一系列空间分配
 //2.和设备相关的资源的初始化 -- GPIO口的定义(属性,引脚)
 return 0;
}
static __exit void myexit(void)
{
    //注销设备
    //释放资源
}
//IO接口的实现
//中断的处理
***********************************************************
<linux/fs.h>
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 (*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 (*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);
 int (*setlease)(struct file *, long, struct file_lock **);
};


struct file
{
 /*
  * fu_list becomes invalid after file_free is called and queued via
  * fu_rcuhead for RCU freeing
  */
 union
 {
  struct list_head fu_list;
  struct rcu_head  fu_rcuhead;
 } f_u;
 struct path  f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
 const struct file_operations *f_op;
 spinlock_t  f_lock;  /* f_ep_links, f_flags, no IRQ */
 atomic_long_t  f_count;
 unsigned int   f_flags;
 fmode_t   f_mode;
 loff_t   f_pos;
 struct fown_struct f_owner;
 const struct cred *f_cred;
 struct file_ra_state f_ra;

 u64   f_version;
#ifdef CONFIG_SECURITY
 void   *f_security;
#endif
 /* needed for tty driver, and maybe others */
 void   *private_data;

#ifdef CONFIG_EPOLL
 /* Used by fs/eventpoll.c to link all the hooks to this file */
 struct list_head f_ep_links;
#endif /* #ifdef CONFIG_EPOLL */
 struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
 unsigned long f_mnt_write_state;
#endif
};

FILE *fp;

<asm/uaccess.h>

unsigned long copy_from_user(void *to, const void *from, unsigned long n);

unsigned long copy_to_user (void * to, void * from, unsigned long len);

 


globvar_driver.c编译后生成的ko文件加载后,通过lsmod或者cat /proc/devices都可以查看到该设备已经在系统中加载,但是在/dev下面有生成设备文件,需要手动创建节点
[root@localhost driver_2]# mknod /dev/globalvar c 230 0
[root@localhost driver_2]# ls /dev

 

 

---Linux2.6内核字符驱动---

<linux/cdev.h>
struct cdev {
   struct kobject kobj;          // 每个 cdev 都是一个 kobject
   struct module *owner;       // 指向实现驱动的模块
   const struct file_operations *ops;   // 操纵这个字符设备文件的方法
   struct list_head list;       // 与 cdev 对应的字符设备文件的 inode->i_devices 的链表头
   dev_t dev;                     // 起始设备编号
   unsigned int count;       // 设备范围号大小
};


定义一个struct cdev类型的对象来表示当前的设备驱动
给cdev对象分配空间
初始化cdev: cdev_init
分配设备号:regist_chrdev_region或alloc_chrdev_region
设备驱动添加到系统:cdev_add

接口实现

注销: cdev_del
      unregister_chrdev_region

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

linux系统驱动基础学习笔记,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。