关注+星标公众号,不错过精彩内容 来源 | 一口Linux Linux是嵌入式的灵魂,很多嵌入式代码的“精髓”都潜藏在Linux内核之中,今天就来教教大家如何从Linux内核抄代码?
之前分享过一篇文章,《看完linux内核源码要多久?》
数以千亿级的电子设备都在运行linux,最核心的Linux内核代码总计有xxxx行,它汇集了全球几百万顶尖程序员的代码,博大精深:
可以说linux内核代码是人类智慧的结晶,要想写出高效、稳定的c代码,大家可以从linux内核中寻找灵感!
彭老师,平时在做项目中,很多小模块都是从参考的linux内核代码。
本文通过一个小例子,来教大家如何借鉴(抄袭)内核代码。
用C语言实现语音压缩算法用于话音通信,要支持不同的压缩比,比如8k、2.4k等,每一种压缩比都会有一组配套的算法参数,
用C语言实现,最常见的就是通过结构体数组来管理这些参数,
那么内核大佬是如何用数组来实现的呢?
JZ4740、JZ4760、JZ4775、JZ4780是北京君正推出的嵌入式微处理器系列,主要用于智能硬件、物联网等领域。
该系列处理器的uart控制器的ip核比较雷同,所以驱动大部分功能是相通的,
但是也有一些差别比如uart的fifo大小,有16、32、64的区别,
那么如何让同一个驱动同时支持不同的uart控制器 ?
该驱动是基于platform总线的,
所以可以根据设备树的compatible的属性信息,来区分当前的uart控制器版本。
参考驱动文件路径如下:
8250_ingenic.c drivers\tty\serial\8250驱动信息:
staticconststructingenic_uart_configjz4740_uart_config = { .tx_loadsz = 8, .fifosize = 16,};staticconststructingenic_uart_configjz4760_uart_config = { .tx_loadsz = 16, .fifosize = 32,};staticconststructingenic_uart_configjz4780_uart_config = { .tx_loadsz = 32, .fifosize = 64,};staticconststructof_device_idof_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, { /* sentinel */ }};MODULE_DEVICE_TABLE(of, of_match);staticintingenic_uart_probe(struct platform_device *pdev){structuart_8250_portuart = {};conststructingenic_uart_config *cdata;conststructof_device_id *match; match = of_match_device(of_match, &pdev->dev);if (!match) { dev_err(&pdev->dev, "Error: No device match found\n");return -ENODEV; } cdata = match->data; ……}内核结构体数组的初始化赋值,都是通过这种 . 加上成员名的方法,
为了保护数组内容不被其他代码修改,数组定义为const类型
强烈建议大家使用这种方法来写c代码
用来表示fifo细节的结构体:
structingenic_uart_config {int tx_loadsz;int fifosize;};设备树信息:
uart0: serial@10030000 { compatible = "ingenic,jz4780-uart"; reg = <0x100300000x100>; interrupt-parent = <&intc>; interrupts = <51>; clocks = <&ext>, <&cgu JZ4780_CLK_UART0>; clock-names = "baud", "module"; status = "disabled"; };注意其中的compatible属性信息,ingenic,jz4780-uart
驱动大致原理:
structof_device_id {char name[32]; char type[32];char compatible[128];// 存放外设名字constvoid *data; //存放私有信息};函数**of_match_device()**是内核提供的设备树匹配函数,
该函数会遍历数组of_match[],根据比较数组的每一个元素的compatible和pdev->dev->of_node->properties,如何相同,则返回struct of_device_id类型指针,该指针指向数组的某一个元素
用于保存uart控制器的私有信息就保存在数组of_match->data中,函数**of_match_device()**会根据设备传入的名字,帮助我们找到该元素
通过变量cdata;保存私有信息,对于ingenic,jz4780-uart来说,就是变量jz4780_uart_config,
后面就可以通过该变量
这种方法是内核最通用的处理方法,
有的外设驱动还会先通过控制总线先从外设读取一个预存在某个内部寄存器的id值,然后再根据这个id值来区分外设硬件版本。
根据该思想,我们编写自己的代码:
#include<stdio.h>#include<string.h>#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))structmy_private_s{int comp_type; int cfg1;int cfg2; int cfg3;char compatible[32]; };#define COMPRESS_TYPE1 0#define COMPRESS_TYPE2 1#define COMPRESS_TYPE3 3#define COMPRESS_TYPE4 4//比较下面两种定义区别//struct my_private_s of_match[] = {staticconststructmy_private_sof_match[] = { { .comp_type = COMPRESS_TYPE1, .cfg1 = 11, .cfg2 = 111, .cfg3 = 1111, .compatible = "com_type1", }, { .comp_type = COMPRESS_TYPE2, .cfg1 = 22, .cfg2 = 222, .cfg3 = 2222, .compatible = "com_type2" }, { .comp_type = COMPRESS_TYPE3, .cfg1 = 33, .cfg2 = 333, .cfg3 = 3333, .compatible = "com_type3" }, { .comp_type = COMPRESS_TYPE4, .cfg1 = 44, .cfg2 = 444, .cfg3 = 444, .compatible = "com_type4" }, {},};struct my_private_s const* of_match_device(int comp_type){int i = 0;for(i=0;i<ARRAY_SIZE(of_match);i++) {if(of_match[i].comp_type == comp_type) {return &of_match[i]; } }returnNULL;}voiddump_compress_info(const struct my_private_s *comp_type){printf("\n\tcomp type:%d\n\tcfg1:%d\n\tcfg2:%d\n\tcfg3:%d\n\tname:%s\n", comp_type->comp_type, comp_type->cfg1, comp_type->cfg2, comp_type->cfg3, comp_type->compatible);}conststructmy_private_s *my_dev = NULL;intmain(){ my_dev = of_match_device(COMPRESS_TYPE1);if(my_dev == NULL) {printf("[yikou] not find valid compress type\n");return-1; }else{ dump_compress_info(my_dev); }//思考下面代码//my_dev->cfg1 = 88;return1;}编译测试:
为了保护我们的配置信息不被恶意修改,我们必须把数组定义为const类型,防止后面维护的老铁给修改了,
------------ END------------

分享一个MCU代码自检和诊断的案例!

8位MCU将会消失吗?

基于MCU的冰箱压缩机控制方案