模块参数,系统调用,字符设备编程重要数据结构,设备号的申请与注册,关于cdev的API
1、模块参数
应用编程:
int main(int argc, char *argv[])
{
}
./a.out xxx yyy zzz
内核编程:
insmod xxx.ko 参数信息
希望在安装内核模块时也可以给其传递参数,需要使用模块参数
模块参数的实现步骤:
1)在模块中定义全局变量
2)使用
module_param(name,type,perm);或者
module_param_array(name,type,nump,perm);
将该变量声明为模块参数
module_param(name,type,perm);
name, 全局变量的名称
type, 变量的类型
内核支持声明为模块参数的变量类型 int short long charp
perm, 访问权限
module_param_array(name,type,nump,perm);
作用:将一个数组声明为模块参数
name, 数组名称
type, 数组成员变量的数据类型
nump, 数组元素个数指针
perm, 访问权限
实验步骤:
insmod moduleparam.ko
rmmod moduleparam
insmod moduleparam.ko irq=100 str="hello" fish=1,2,3,4,5
ls /sys/module/moduleparam/parameters/ 无显示
cd /sys/module/moduleparam/parameters/
cat fish
cat irq
echo 1234 >irq
echo 11,22,33,44,55,66 >fish
cd /
rmmod moduleparam
模块参数的使用场景:
调试代码时使用
REG1=irq;
insmod xxx.ko irq= 100
rmmod xxx.ko
insmod xxx.ko irq=101;
2、系统调用
谈谈对系统调用的理解?
什么是系统调用?
是操作系统提供应用编程者调用的一组特殊函数
系统调用的作用?
保护内核的安全
保证用户空间以安全的方式调用内核中的函数
系统调用是如何实现的
在用户空间指定系统调用号
产生软中断异常 陷入内核态执行
执行异常向量表 跳转到软中断异常处理代码
在软中断异常处理代码中根据系统调用号
找到内核中的对应函数
并且执行该函数
执行完毕后将结果原路返回给用户空间
系统调用号:arch/arm/include/asm/unistd.h
软中断指令:
arm, swi/svc
intel, int
异常向量表:arch/arm/kernel/entry-armv.S
软中断异常处理代码:arch/arm/kernel/entry-common.S
系统调用表:calls.S
增加一个新的系统调用
cd /home/tarena/driver/kernel/
vi arch/arm/kernel/sys_arm.c
asmlinkage int sys_add(int x, int y)
{
printk("<1>" "enter %s\n", __func__);
return x+y;
}
vi arch/arm/include/asm/unistd.h //增加新的系统调用号
#define __NR_add (__NR_SYSCALL_BASE+378)
vi arch/arm/kernel/calls.S//更新系统调用表
390 CALL(sys_add)
make uImage
让开发板使用新内核
vi test.c
open=("a.txt", O_RDWR) 等价于
syscall(5, "a.txt", O_RDWR)
read(fd, buf,len) 等价于
syscall(3,fd,buf,len)
arm-cortex_a9-linux-gnueabi-gcc test.c -o test
cp test ../../rootfs
./test //注意使用新旧内核的区别
3、字符设备驱动编程
linux是使用C编程实现的
但是内核实现过程中大量运用了面向对象的编程思想
在linux中实现一个字符设备(例如 按键 鼠标 触摸屏 LCD 。。。)
驱动程序,其实质就是实例化一个struct cdev类型的对象
struct cdev
{
//设备号
dev_t dev;
const struct file_operations *ops;
...
}
3.1 设备号
本质是一个32bit的无符号数据
设备号=主设备号(高12bit) + 次设备号(低20bit)
主设备号,用于区分不同类型的设备
次设备号,用于区分同一类设备中的不同个体
ls /dev/ttySAC* -l
设备号的申请与注册有两种方式 :
1)静态方式
2)动态方式
3.1.1 静态方式
查看已经有哪些主设备号被占用
cat /proc/devices
从没被占用的主设备号挑一个为我所用
int register_chrdev_region(dev_t from, unsigned count,
const char *name)
作用:注册连续的多个设备号
from, 要注册的起始设备号
count, 要注册的个数
name, 名称
返回值,0 成功
<0 失败
void unregister_chrdev_region(dev_t from, unsigned count)
实验步骤:
insmod led_drv.ko
cat /proc/devices
rmmod led_drv.ko
cat /proc/devices
3.1.2 动态方式
由内核动态分配一个未被使用主设备号
int alloc_chrdev_region(dev_t *dev,
unsigned baseminor, unsigned count,
const char *name)
dev,传出参数
用于返回分配得到的第一个设备号
baseminor,起始次设备号
count,申请的连续设备号的个数
name, 名称
注销:unregister_chrdev_region
3.2 操作(驱动)函数集合
实现一个字符设备硬件的驱动程序
实则就是实例化一个struct cdev对象
在实例化struct cdev对象过程中主要的编码工作
集中在了struct file_operations
struct file_operations
{
owner
open
read
write
mmap
release
unlocked_ioctl
poll
...
}
具体某个特定的字符设备硬件,只需要实现其中的部分函数即可
3.3 内核中提供的关于cdev的API
void cdev_init(struct cdev *cdev,
const struct file_operations *fops)
{
cdev->ops = fops;
...
}
//注册cdev 将一条学生记录插入到数据库中
cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
...
}
//注销cdev 将一条学生的记录从数据库中删除
void cdev_del(struct cdev *p)
实验步骤:
1)insmod led_drv.ko
找到该驱动使用的主设备号 和 次设备号
2)在开发板上创建设备文件
mknod /dev/myleds c 244 5
3)vi test.c
fd = open("/dev/myleds", O_RDWR);
4) arm-cortex_a9-linux-gnueabi-gcc test.c -o test
5) 板子上执行test
cp test ../../rootfs
./test
总结:
linux下一切皆文件 除了socket
//模块传参
#include "../../global.h"
int irq = ;
char *str = "tarena";
int fish[] = {};
/*保存fish元素个数*/
int num_fish = ; module_param(irq, int, );
module_param(str, charp, );
module_param_array(fish, int, &num_fish,);
int __init moduleparam_init(void)
{
int i = ;
printk("<1>" "irq=%d\n", irq);
printk("<1>" "str=%s\n", str); for(; i<num_fish; i++)
{
printk("<1>" "fish[%d]=%d\n", i, fish[i]);
}
return ;
}
void __exit moduleparam_exit(void)
{
int i = ;
printk("<1>" "irq=%d\n", irq);
printk("<1>" "str=%s\n", str); for(; i<num_fish; i++)
{
printk("<1>" "fish[%d]=%d\n", i, fish[i]);
}
}
module_init(moduleparam_init);
module_exit(moduleparam_exit);
//设备号的注册。
#include "../../global.h"
#include <linux/fs.h> unsigned int major = ;
unsigned int minor = ;
dev_t dev ; //设备号 int __init led_drv_init(void)
{
//dev = major<<20|minor;
dev = MKDEV(major, minor); register_chrdev_region(dev, , "myleds"); return ;
}
void __exit led_drv_exit(void)
{
unregister_chrdev_region(dev, );
}
module_init(led_drv_init);
module_exit(led_drv_exit);
//设备号的动态注册
1 #include "../../global.h"
#include <linux/fs.h> unsigned int major = ;
unsigned int minor = ;
dev_t dev ; //设备号 int __init led_drv_init(void)
{
if(major) //静态
{
//dev = major<<20|minor;
dev = MKDEV(major, minor); register_chrdev_region(dev, , "myleds");
}
else //动态注册
{
alloc_chrdev_region(&dev, minor, , "myleds");
printk("<1>" "major=%d minor=%d\n",
MAJOR(dev), MINOR(dev));
}
return ;
}
void __exit led_drv_exit(void)
{
unregister_chrdev_region(dev, );
}
module_init(led_drv_init);
module_exit(led_drv_exit);
#include "../../global.h"
#include <linux/fs.h>
#include <linux/cdev.h> unsigned int major = ;
unsigned int minor = ;
dev_t dev ; //设备号 /*1 定义一个struct cdev变量*/
struct cdev led_cdev; static int led_open(struct inode *inode,
struct file *filp)
{
printk("<1>" "enter %s\n", __func__);
return ;
}
static int led_close(struct inode *inode,
struct file *filp)
{
printk("<1>" "enter %s\n", __func__);
return ;
} struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
};
int __init led_drv_init(void)
{
if(major) //静态
{
//dev = major<<20|minor;
dev = MKDEV(major, minor); register_chrdev_region(dev, , "myleds");
}
else //动态注册
{
alloc_chrdev_region(&dev, minor, , "myleds");
printk("<1>" "major=%d minor=%d\n",
MAJOR(dev), MINOR(dev));
}
/*2 初始化cdev变量*/
cdev_init(&led_cdev, &led_fops);
/*3 注册cdev变量*/
cdev_add(&led_cdev, dev, ); return ;
}
void __exit led_drv_exit(void)
{
/*4 注销cdev*/
cdev_del(&led_cdev); unregister_chrdev_region(dev, );
}
module_init(led_drv_init);
module_exit(led_drv_exit);
模块参数,系统调用,字符设备编程重要数据结构,设备号的申请与注册,关于cdev的API的更多相关文章
- pygame模块参数汇总(python游戏编程)
一.HelloWorld pygame.init() #初始函数,使用pygame的第一步: pygame.display.set_mod((600,500),0,32) #生成主屏幕screen:第 ...
- MPU6050带字符驱动的i2c从设备驱动1
开干: 1.闲言碎语 这个驱动,越写觉的越简单,入门难,入门之后感觉还好.Linux开发还是比较友好的. 2.编写MPU6050带字符驱动的i2c从设备驱动 要实现的功能就是,将MPU6050作为字符 ...
- Linux设备驱动程序 之 模块参数
模块支持参数的方法 内核允许驱动程序指定参数,这些参数可在运行insmod或者modprobe命令装载模块时赋值,modprobe还可以从它的配置文件(/etc/modporb.conf)中读取参数值 ...
- 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联
转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...
- Linux设备驱动编程之复杂设备驱动
这里所说的复杂设备驱动涉及到PCI.USB.网络设备.块设备等(严格意义而言,这些设备在概念上并不并列,例如与块设备并列的是字符设备,而PCI.USB设备等都可能属于字符设备),这些设备的驱动中又涉及 ...
- [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联
转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...
- insmod module_param 模块参数
模块参数 引导模块时,可以向它传递参数.要使用模块参数加载模块,这样写: insmod module.ko [param1=value param2=value ...] 为了使用这些参数的值,要在模 ...
- linux模块参数
驱动需要知道的几个参数因不同的系统而不同. 从使用的设备号( 如我们在下一章见到的 ) 到驱动应当任何操作的几个方面. 例如, SCSI 适配器的驱动常常有选项控制标记命令队列 的使用, IDE 驱动 ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
随机推荐
- 一篇文章教会你jQuery应用
一 认识jQuery jQuery是JavaScript Query的缩写形式.jQuery是一款非常优秀的JavaScript库,即便是MVVM框架盛行的今天,也有超过半数的网页及应用直接或间接的使 ...
- 自己动手撸一个LinkedList
自己动手撸一个LinkedList 1. 原理 LinkedList是基于双链表的动态数组,数据添加删除效率高,只需要改变指针指向即可,但是访问数据的平均效率低,需要对链表进行遍历.因此,Linked ...
- 加密解密 之base系列编码
Base16 Base16编码使用16个ASCII可打印字符(数字0-9和字母A-F)对任意字节数据进行编码.Base16先获取输入字符串每个字节的二进制值(不足8比特在高位补0),然后将其串联进来, ...
- maven在线自动更新太慢怎么办?
使用IDEA和Eclipse开发maven项目时,maven在添加一项新的依赖时,如果发现本地仓库没有,就会向位于国外服务器的中央仓库下载.如果所处网络没有翻墙,下载速度会慢到你想原地爆炸. 这个时候 ...
- wwindows权限认识(用户及用户组)
windows权限认识(用户及用户组) Windows系统内置了许多本地用户组,这些用户组本身都已经被赋予一些权限(permissions),它们具有管理本地计算机或访问本地资源的权限.只要用户账户加 ...
- opencv::基本阈值操作
图像阈值(threshold) 阈值 是什么?简单点说是把图像分割的标尺,这个标尺是根据什么产生的,阈值产生算法?阈值类型.(Binary segmentation) 阈值类型一阈值二值化(thres ...
- 百万年薪python之路 -- socket粘包问题解决
socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...
- SpringBoot学习(一)基础篇
目录 关于Springboot Springboot优势 快速入门 关于SpringBoot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭 ...
- Kubernetes入门学习--在Ubuntu16.0.4安装配置Minikube
目 录 一. 安装minikube环境 1.1. 安装前准备 1.2. 安装Lantern 1.2.1. Lantern下载网站 1.2.2. Lantern下载地址 1.2.3. Lantern安装 ...
- Kafka 权威指南阅读笔记(第三章,第四章)
Kafka 第三章,第四章阅读笔记 Kafka 发送消息有三种方式:不关心结果的,同步方式,异步方式. Kafka 的异常主要有两类:一种是可重试异常,一种是无需重试异常. 生产者的配置: acks ...