iTop-4412的Linux驱动中设备注册和驱动注册笔记整理及分析,不会让你失望的

上一篇文章里有一部分没有整理那就是关于编译内核的时候编译器路径的设置部分,拿到源码后一般需要设置一下编译器路径,在源码目录Makefile文件中可以设置编译路径“CROSS_COMPILE”在该文件的180行左右有如下代码:

CROSS_COMPILE   ?= /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

“CROSS_COMPILE”后边就是编译器的路径设置;也是编译环境搭建的时候,解压arm-2009q3的目录和这里对应;补充完毕!
下边是Linux总线设备驱动注册流程图:说白了就是要实现对某一功能的操作,要在LInux内核中进行设备注册和对应驱动注册;而且注册设备的name要和驱动的name对应才行;

在这里插入图片描述
一、设备注册
因为好久之前就看过这一部分了,现在才写这部分说实话忘的差不多了,同时我也在纠结该怎么写;怎么才能通俗易懂的把这部分介绍完。跟着我一起来吧!
首先这部分要了解一个结构体和两个函数,要想查看原型可以在内核源码文件夹中的include/linux/platform_device.h中查看中查看,我特把这个结构体和那两个函数原型列在下边:

/*platform_device结构体*/
struct platform_device {
        const char      * name;//设备名称,在sys/device会显示
        int             id;/*设备ID,用于插入总线并且具有相同name的设备编号
        					 如有一个设备那就是-1,就像一个总线上挂了相同name
        					 的设备,然后再给每一个编一个号的意思*/
        struct device   dev;//结构体中内嵌的device结构体
        u32             num_resources;//设备使用资源的数量
        struct resource * resource;//设备使用资源的数组

        const struct platform_device_id *id_entry;

        /* MFD cell pointer */
        struct mfd_cell *mfd_cell;

        /* arch specific additions */
        struct pdev_archdata    archdata;
};
/*注册设备函数*/
extern int platform_device_register(struct platform_device *);
/*卸载设备函数*/
extern void platform_device_unregister(struct platform_device *);

重点来了,上边的一个结构体和两个函数了解一下就好了,现在大多是使用引入的虚拟平台,使用虚拟平台来注册设备会容易很多。下面呢我们就来利用平台文件(也就是mach-itop4412.c)来具体操作一下
① vim arch/arm/mach-exynos/mach-itop4412.c
②在mach-itop4412.c文件中搜索leds,一leds的示例方式自己依照前边了解的结构体仿照写一个注册设备结构体变量代码,如果在编辑的时候不加宏定义就是不管怎么样都要编译进去:
在这里插入图片描述
照着leds的去写就好了,里边有设备name还有ID这都是上边那个结构体里的;写完保存退出;
③还需要将这个结构体变量导到内核列表里,还是在vim arch/arm/mach-exynos/mach-itop4412.c里,搜索&s3c_device_leds_ctl,在这个代码的上边仿照写一个跟第二部同设备名的代码;
在这里插入图片描述
③编译的时候必须要有这个设备的宏定义,要在/devices/char/Kconfig中仿照示例写一个相应代码(也是上一篇文章中关于Kconfig的操作):
在这里插入图片描述
写完保存退出,完后在make menuconfig中查看一下这个选项有没有,有的话选上,保存退出,然后编译内核文件,烧写到开发板上,ls sys/devices/platform/就可以查到新注册设备;设备注册就成功了;就不上图了自己试试效果更好;

二、驱动注册
这一部分很重要,牢牢掌握,以后写任何Linux驱动都会用到!!!
㈠首先要了解一个结构体和两个函数,分别是驱动注册使用结构体platform_driver、驱动注册函数platform_driver_register、驱动卸载函数platform_driver_unregister
,都在include/linux/platform_device.h中,我们打开看一下这些原型:

struct platform_driver {
        int (*probe)(struct platform_device *);//初始化函数
        int (*remove)(struct platform_device *);//移除驱动函数
        void (*shutdown)(struct platform_device *);//关闭
        int (*suspend)(struct platform_device *, pm_message_t state);//悬挂(休眠)驱动函数
        int (*resume)(struct platform_device *);//休眠后恢复驱动,复位
        struct device_driver driver;//device_driver数据结构的两个参数
        							//– name和注册的设备name要一致
        							//– owner一般赋值THIS_MODULE
        const struct platform_device_id *id_table;
};//结构体,有些部分是可以缺省的,没必要全部写进去;
/*注册驱动函数*/
extern int platform_driver_register(struct platform_driver *);
/*卸载驱动函数*/
extern void platform_driver_unregister(struct platform_driver *);

㈡驱动常见的几种状态,初始化(结构体中的probe),移除(结构体中的remove),休眠(结构体中的suspend),复位(结构体中的resume);
就像PC一样,有的驱动休眠之后无法使用,有的可以使用;有的系统唤醒之后,驱动需要重新启动才能正常工作,也有直接就可以使用等等;
了解了这些下面就编写一个ceshi.c文件测试一下:

/*包含初始化宏定义的头文件,代码中的函数module_init和module_exit在此文件中*/
#include <linux/init.h>
/*所有的Linux 代码必须遵循GPL 协议和作者申明*/
#include <linux/module.h>
/*驱动注册头文件,包含设备注册结构体、注册函数、卸载函数以及驱动注册结构体、注册函数、卸载函数*/
#include <linux/platform_device.h>

/*声明是开源的,没有内核版本限制*/
MODULE_LICENSE("Dual BSD/GPL");
/*声明作者*/
MODULE_AUTHOR("TOPEET");

#define DRIVER_NAME "hello_ctl"

static int hello_probe(struct platform_device *pdv)
{
	printk(KERN_EMERG "\tinitalized\n");
	return 0;
}

static int hello_remove(struct platform_device *pdv)
{
	return 0;
}

static void hello_shutdown(struct platform_device *pdv)
{
	
}

static int hello_suspend(struct platform_device *pdv)
{
	return 0;
}

static int hello_resume(struct platform_device *pdv)
{
	return 0;
}

struct plantform_deiver hello_driver = {
	.probe = hello_probe,
	.remove= hello_remove,
	.shutdown= hello_shutdown,
	.suspend= hello_suspend,
	.resume = hello_resume ,
	.driver = {
			.name = DRIVER_NAME,
			.owner = THIS_MODULE,
	}
};

static int hello_init(void)
{
	int DriverState;
	printk(KERN_EMERG "HELLO WORLD enter!\n");
	DriverState = platform_driver_register(&hello_driver);
	printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
	return 0;
}

static int hello_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	platform_driver_unregister(&hello_driver);
}

module_init(hello_init);             /*初始化函数*/
module_exit(hello_exit);            /*卸载函数*/

编写完将.c文件,还需要一个Makefile文件,代码如下:

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += ceshi.o 

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
	make -C $(KDIR) M=$(PWD) modules
		
#make clean执行的操作是删除后缀为o的文件
clean:
	rm -rf *.o

然后将ceshi.c和Makefile文件拷贝到Ubuntu中,编译,将生成的文件.ko文件在开发板上使用:
– insmod加载模块命令
– lsmod查看模块命令
– rmmod卸载模块命令
来加载、查看和卸载驱动,来查看相应效果,具体操作图就不上了,大家自己亲自操作下,效果好些。看看打印的信息和写的代码中对比一下,加深一下对程序的理解。下面还有点儿复习C的笔记:

//printk的使用
//printk()和C库中的printf()在使用上最主要的区别就是 printk()指定了日志级别。
//内核根据日志级别来判断是否在终端(console)上打印消息:内核把级别比某个特定值低的所有消息显示在终端(console)上。但是所有信息都会记录在printk的“ring buffer”中。
//printk有8个loglevel,定义在中:
#define KERN_EMERG "<0>" /* 系统不可使用 */
#define KERN_ALERT "<1>" /* 需要立即采取行动 */
#define KERN_CRIT "<2>" /* 严重情况 */
#define KERN_ERR "<3>" /* 错误情况 */
#define KERN_WARNING "<4>" /* 警告情况 */
#define KERN_NOTICE "<5>" /* 正常情况, 但是值得注意 */
#define KERN_INFO "<6>" /* 信息型消息 */
#define KERN_DEBUG "<7>" /* 调试级别的信息 */

下一篇文章就是关于以module方式注册设备和比较重要的生成设备节点,敬请关注!!

又到了这个环节,请欣赏我的鸡汤时刻!一GO我嘞GOGO!!!!
送给阅读过这篇文章的人:骨气——只要是人,他就有欲望,就贪婪;这种不劳而获的获取,实际上他是一种自我欺骗的幻觉,在这大千世界里,什么都有可能发生,但幻觉他不会形成一种常态,我们不能因为我们不敢面对现实,而行这种苟且之事,志士不饮盗之水,廉者不受嗟来之食,这才是做人应该有的骨气;无功受禄,无品又无德;
下篇文章见。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值