Linux下编写和加载 .ko 文件(驱动模块文件

Linux下编写和加载 .ko 文件(驱动模块文件,第1张

一、.ko 文件介绍

.ko文件是kernel object文件(内核模块),该文件的意义就是把内核的一些功能移动到内核外边, 需要的时候插入内核,不需要时卸载。

二、优点

(1)这样可以缩小内核体积;

(2)使用方便。

三、.ko文件一般的用处

(1)作为一个功能模块,需要使用时,直接插入运行就行。如在imx6上连接模拟摄像头,先运行模拟摄像头对应的驱动模块 camera.ko文件,然后对应的工程执行文件运行就行。

四、使用.ko 文件

1、加载驱动模块test.ko

(1)方法一 

进入test.ko驱动模块文件所在的目录,然后直接   insmod  test.ko 

(2)方法二 

将test.ko文件拷贝到/lib/module/#uname-r#/目录下,这里,#uname -r#意思是,在终端中输入 

uname -r后显示的内核版本及名称,例如mini2440中#uname-r#就是2.6.32.2-FriendlyARM。

然后 depmod(会在/lib/modules/#uname -r#/目录下生成modules.dep和modules.dep.bb文件,表明模块的依赖关系) 

最后 modprobe test(注意这里无需输入.ko后缀) 即可

注:两种方法的区别

modprobe和insmod类似,都是用来动态加载驱动模块的,区别在于modprobe可以解决load module时的依赖关系,它是通过/lib/modules/#uname -r/modules.dep(.bb)文件来查找依赖关系的;而insmod不能解决依赖问题。也就是说,如果你确定你要加载的驱动模块不依赖其他驱动模块的话,既可以insmod也可以modprobe,当然insmod可以在任何目录下执行,更方便一些。而如果你要加载的驱动模块还依赖其他ko驱动模块的话,就只能将模块拷贝到上述的特定目录,depmod后再modprobe。

 linux *** 作系统下,加载驱动的方式有二:

静态加载驱动;

动态加载驱动;

 作为前者,静态加载驱动是通过将驱动程序编译到内核而进行的一系列配置 *** 作;对于后者而言则是向内核注册设备信息,从而在kernel启动后,再通过insmod指令,关联好主、次设备号,从而以模块的形式进行加载的;

 二者各有优点,所以应用的场合也是不一样的;

介绍个动态加载模块的过程

在该驱动中,我们假设对键盘的获取是以0.2s为周期执行。源代码如下

static struct timer_list timer///////我们定义的定时器,也许你会问timer_list是什么来的,其实一看名称就应该就知道了,而为什么要用到list那么多定时器呢?其实在linux中还有很多相同的定义,比如说信号,我们定义的也是信号集,你可以定义该list是一个元素的,也可以是多个的。所以对于 timer_list就可以这样描述:在未来某一个特定时刻执行某一系列特定任务的功能。下面我们还会给出内核中timer_list的具体描述,^_^ 好像我的话又说多了

static int Keypad_starttimer(void)

{

init_timer(&timer)//初始化定时器结构

timer.function=Keypad_timer//超时服务程序

timer.expires=jiffies+20//当前时刻加0.2s

add_timer(&timer)

return 0

}

///超时服务程序

static void Keypad_timer(unsigned long data)

{

read_xy()

}

/////////接下来说下timer-list这个数据结构,如果你不感兴趣的话可以跳过,该结构在include\linux\timer.h中定义

struct timer_list

{

struct list_head entry

unsigned long expries

spinlock_t lock

unsigned long magic

void (*function)(unsigned long)

unsigner long data

struct tvec_t_base_s *base

}

七.利用等待队列实现阻塞型I\O

在用户程序执行读 *** 作的时候有可能尚且没有数据可以读取,为此需要让read *** 作等待,直到有数据可以读取,这就是阻塞型i\o,阻塞型io可以通过使用进程休眠方法实现。在无数据可以读取的时候,采用等待队列让进程休眠,直到有数据到达的时候才唤醒进程完成数据的读 *** 作。

在本驱动中的read,若循环队列缓冲区中没有数据,则进程进入休眠态,定时器函数每隔0.2s读取键值一次,将按键状态放入缓冲并且适时唤醒进程读取数据。

等待队列的使用流程如下:

1.声明一个等待队列

2.把当前进程加入到等待队列中

3.把进程的状态设置为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE

4.调用schedule,以让出cpu

5.检测所需要的资源是否可用,若是,把当前进程从等待队列中删除,否则转3循环

接下来我们在对read中有关等待队列阻塞实现做具体的解释

static ssize_t Keypad_read(struct file *filp,char *buf,ssize_t count,loff_t *l)

{

DECLEARE_WAITQUEUE(wait,current)//声明等待队列,将当前进程加入到等待队列中

KEY_EVENT t

ulong out_buf[2]

if(head==tail)//当前循环队列中没有数据可以读取

{

if(filp->f_flags &O_NONBLOCK)//假如用户采用的是非堵塞方式读取

return _EAGAIN

add_wait_queue(&queue,&wait)//将当前进程加入等待队列

current->state=TASK_INTERRUPTIBLE//设置当前进程的状态

while((head==tail)&&!signal_pending(current))//假若还没有数据到循环队列并且当前进程没有受到信号(该类信号具体来说是未决的休眠)

{

shedule()//进程调度

current->state=TASK_INTERRUPTIBLE

}

current->state=TASK_RUNNING//该进程恢复执行

remove_wait_queue(&queue,&wait)//移出等待队列

if(head==tail)

return count

t=get_data()//调用get_data()函数,得到缓冲区中的数据,下面将给予详细的 介绍

out_buf[0]=t.status

out_buf[1]=t.click

copy_to_user(buf,&out_buf,sizeof(out_buf))//将得到的键值拷贝到用户数据区

return count

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/6223886.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-18
下一篇2023-03-18

发表评论

登录后才能评论

评论列表(0条)

    保存