当前位置:网站首页>platform driver
platform driver
2022-06-12 06:25:00 【Bohai0525】
platform driver
1、注册设备驱动
1.1、申请设备号
alloc_chrdev_region(dev_t *dev,unsigned int -firstminor,unsigned int -count,char *name);
- 功能:动态的分配(驱动)设备编号
- firstminor: 设备号
- count: 设备数量
- name: 设备名称
- 缺点
- 无法预知在/dev下创建设备节点,因为动态分配设备号不能保证在每次加载驱动module时始终一致(其实若在两次加载同一个驱动module之间并没有加载其他的module,那么自动分配的设备号还是一致的,因为内核分配设备号并不是随机的,但是书上说某些内核开发人员预示不久的将来会用随机方式进行处理),不过,这个缺点可以避免,因为在加载驱动module后,我们可以读取/proc/devices文件以获得Linux内核分配给该设备的主设备号。
1.2、注册
platform_driver_register(struct platform_driver *)
- 1.2.1 struct platform_driver
//------- 定义 --------//
struct of_device_id {
char name[32];
char type[32];
char compatible[128];
const void *data;
};
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct attribute_group **dev_groups;
const struct dev_pm_ops *pm;
void (*coredump) (struct device *dev);
struct driver_private *p;
};
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;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
//------- 初始化 --------//
static const struct of_device_id xvc_of_ids[] = {
{ .compatible = "xlnx,xvc", },
{}
};
static struct platform_driver xil_xvc_plat_driver = {
.driver = {
.name = "xilinx_xvc_driver",
.owner = THIS_MODULE,
.of_match_table = xvc_of_ids,
},
.probe = probe,
.remove = remove,
};
可以看到platform_driver中包含(继承)了“struct device_driver”
device_driver.name为驱动的名字注册后可在“/dev/”或"/sys/bus/platform/driver/"下找到该设备驱动
device_driver.of_match_talbe.compatible为该驱动适配的设备的名字
- 设备的名字可以在设备树中找到
&debug_bridge_0 { compatible = "xlnx,xvc"; };- platform bus而言就是platform_match
static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); }驱动头文件位于 proj_path/petalinux/components/yocto/workspace/sources/linux-xlnx/include/linux
负责注册平台驱动程序,如果在内核中找到了使用驱动程序的设备,调用probe()。
2、创建类
2.1 class_create(owner,name)
- 此函数的执行效果就是在目录/sys/class下创建一个新的文件夹,此文件夹的名字为此函数的第二个输入参数,但此文件夹是空的。
2.2 cdev_init
- 源码如下
//------------------ 定义 --------------//
struct cdev {
struct kobject kobj; //内嵌的内核对象.
struct module *owner; //该字符设备所在的内核模块的对象指针.
const struct file_operations *ops; //该结构描述了字符设备所能实现的方法,即file_operations.
struct list_head list; //用来将已经向内核注册的所有字符设备形成链表.
dev_t dev; //字符设备的设备号,由主设备号和次设备号构成.
unsigned int count; //隶属于同一主设备号的次设备号的个数.
} __randomize_layout;
void cdev_init(struct cdev *cdev, struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev); //首先将cdev对应的空间进行清零操作
INIT_LIST_HEAD(&cdev->list); //初始化list变量为双向环形链表的头结点
cdev->kobj.ktype = &ktype_cdev_default;
kobject_init(&cdev->kobj);
cdev->ops = fops;
}
//------------------ 例子 --------------//
static struct cdev xvc_char_ioc_dev;
static struct file_operations xil_xvc_ioc_ops = {
.owner = THIS_MODULE,
.unlocked_ioctl = char_ctrl_ioctl
};
cdev_init(&xvc_char_ioc_dev, &xil_xvc_ioc_ops);
- 最重要的操作是,将ops与cdev绑定
2.3 cdev_add
- 用于告诉内核该struct cdev的信息
//------------------ 定义 --------------//
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
//------------------ 例子 --------------//
static dev_t xvc_ioc_dev_region;
static struct cdev xvc_char_ioc_dev;
//申请设备号至xvc_ioc_dev_region
alloc_chrdev_region(&xvc_ioc_dev_region, 0, CONFIG_COUNT, XVC_DRIVER_NAME);
//
cdev_add(&xvc_char_ioc_dev, xvc_ioc_dev_region, CONFIG_COUNT);
内核中所有都字符设备都会记录在一个 kobj_map 结构的 cdev_map 变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保存到 cdev_map 这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev 结构变量,从而取出其中的 ops 字段。

简单地说,设备驱动程序通过调用cdev_add把它所管理的设备对象的指针嵌入到一个类型为struct probe的节点之中,然后再把该节点加入到cdev_map所实现的哈希链表中。
3、创建设备
3.1、 MKDEV
- #define MKDEV(major,minor) (((major) << MINORBITS) | (minor))
- 将主设备号和次设备号转换成dev_t类型
3.2、device_create
函数定义
- struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, …)
class: pointer to the struct class that this device should be registered to
- the struct class 指针,必须在本函数调用之前先被创建
parent: pointer to the parent struct device of this new device
- 该设备的parent指针。
devt: the dev_t for the char device to be added
- 字符设备的设备号,如果dev_t不是0,0的话,1个”dev”文件将被创建。
drvdata:
- 被添加到该设备回调的数据。
fmt: string for the device’s name
- 设备名字。
可以看下面的函数调用例子
// ----- 例子1 ------//
device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );
// 如果成功,它将会在/dev目录下产生/dev/hello0设备。
4、地址映射
4.1、platform_get_resource源码
// ------------- 定义 -------------//
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
{
int i;
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if (type == resource_type(r) && num-- == 0)
return r;
}
return NULL;
}
// ------------- 调用 -------------//
db_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4.1.1、struct platform_device *dev
- 该设备是platform bus调用platform_match后传入得于该驱动匹配得设备指针
4.1.2、int type
- 表示内核资源得类型
#define IORESOURCE_IO 0x00000100 /* Resource type */
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
4.1.3、资源表得获取
/dts-v1/;
/plugin/;
/ {
[email protected] {
target = <&amba>;
overlay2: __overlay__ {
#address-cells = <2>;
#size-cells = <2>;
debug_bridge_0: [email protected] {
clock-names = "s_axi_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "xlnx,debug-bridge-3.0", "generic-uio";
reg = <0x0 0x80000000 0x0 0x10000>;
xlnx,bscan-mux = <0x1>;
xlnx,build-revision = <0x0>;
xlnx,chip-id = <0x0>;
xlnx,clk-input-freq-hz = <0x11e1a300>;
xlnx,core-major-ver = <0x1>;
xlnx,core-minor-alpha-ver = <0x61>;
xlnx,core-minor-ver = <0x0>;
xlnx,core-type = <0x1>;
xlnx,dclk-has-reset = <0x0>;
xlnx,debug-mode = <0x2>;
xlnx,design-type = <0x0>;
xlnx,device-family = <0x0>;
xlnx,en-bscanid-vec = "false";
xlnx,en-int-sim = <0x1>;
xlnx,en-passthrough = <0x0>;
xlnx,enable-clk-divider = "false";
xlnx,fifo-style = "SUBCORE";
xlnx,ir-id-instr = <0x0>;
xlnx,ir-user1-instr = <0x0>;
xlnx,ir-width = <0x0>;
xlnx,major-version = <0xe>;
xlnx,master-intf-type = <0x1>;
xlnx,minor-version = <0x1>;
xlnx,num-bs-master = <0x0>;
xlnx,pcie-ext-cfg-base-addr = <0x400>;
xlnx,pcie-ext-cfg-next-ptr = <0x000>;
xlnx,pcie-ext-cfg-vsec-id = <0x0008>;
xlnx,pcie-ext-cfg-vsec-length = <0x020>;
xlnx,pcie-ext-cfg-vsec-rev-id = <0x0>;
xlnx,tck-clock-ratio = <0x8>;
xlnx,two-prim-mode = "false";
xlnx,use-bufr = <0x0>;
xlnx,use-ext-bscan = "true";
xlnx,use-softbscan = <0x1>;
xlnx,use-startup-clk = "false";
xlnx,user-scan-chain = <0x1>;
xlnx,xsdb-num-slaves = <0x0>;
xlnx,xvc-hw-id = <0x0001>;
xlnx,xvc-sw-id = <0x0001>;
};
};
};
};
&debug_bridge_0 {
compatible = "xlnx,xvc";
};
- 推测platform_device注册时会获取设备树的reg信息从而初始化struct resource
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
- 老的方式
struct resource demod_res = { //定义res结构体
.name = "demod kernel",
.start = 0x8xxx, //即io地址的物理地址
.end = 0x8xxxx+ offset,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
};
static struct platform_device demod_device = {
.name = "demod",
.id = -1,
},
.num_resources = ARRAY_SIZE(demod_res),
.resource = demod_res, //关键的一步,将res挂载在platform device结构体中
};
4.2、devm_ioremap_resource(&pdev->dev, db_res)
- 实现虚拟地址到物理地址的影射
5、补充
5.1、cdev_add和device_create的关系
- cdev_add后cdev(驱动设备)就激活了,内核就可以操作它了,但是用户空间依然无法访问
- 要从用户空间访问此设备,应该在/dev中创建设备节点。通过使用class_create创建虚拟设备类,然后使用sysfs函数创建设备并使用device_create注册它来完成此操作。 device_create将在/dev中创建一个设备文件。
6、鸣谢
- 以上部分内容参考前辈们的文章,在此特别感谢!
边栏推荐
- Open the camera in unity3d and display the contents of the camera in the scene as texture2d
- QT--实现TCP通信
- LeetCode-1350. Invalid students
- Unity3d script captures a sub area from the screen and saves it as texture2d, which is used to save pictures and maps
- MLP sensor
- Excel VBA opens a file that begins with the specified character
- Book classification based on Naive Bayes
- Using hidden Markov model to mark part of speech
- Word vector training based on nnlm
- Delete the duplicate items in the ordered array -- force deduction question 26 (simple)
猜你喜欢

C2w model - language model

Leetcode personal question solution (Sword finger offer3-5) 3 Duplicate number in array, 4 Find in 2D array, 5 Replace spaces

Understand Houdini's (heightfield) remap operation

Multithreading mode (I) -- protective pause and join source code

SQL 注入读写文件

(UE4 4.27) customize primitivecomponent

Unity implements smooth interpolation

SQLite cross compile dynamic library

In unity3d, billboard effect can be realized towards another target

PHP一句话木马深度详细剖析
随机推荐
Cv2.fillpoly coco annotator segment coordinate conversion to mask image
Leetcode personal question solution (Sword finger offer3-5) 3 Duplicate number in array, 4 Find in 2D array, 5 Replace spaces
Leetcode January 13 daily question 747 At least twice the maximum number of other numbers
LeetCode-419. Battleship on deck
About why GPU early-z reduces overdraw
Unity implements smooth interpolation
LeetCode-1490. Clone n-ary tree
Unity C script implements AES encryption and decryption
Delete the duplicate items in the ordered array -- force deduction question 26 (simple)
PDF. JS help file
GET 和 POST 的区别及留言板代码实现
C2w model - language model
Automatic modeling of Interchange
Multithreading (2) -- pipeline (4) -- Park and unpark
English grammar_ Adverb_ With or without ly, the meaning is different
LeetCode-1078. Bigram participle
Analysis of memory management mechanism of (UE4 4.26) UE4 uobject
Apache poi 导入导出Excel文件
Android studio mobile development creates a new database and obtains picture and text data from the database to display on the listview list
torch在高版本训练的模型在低版本中使用报错