1 概述

(1)mailbox是一种框架,通过消息队列和中断驱动信号处理多处理器间的通讯;
(2)mailbox的实现分为contoller和client。简单的说就是client 可以通过controller提供的channel发送信息给controller;
(3)在drivers/mailbox下实现的都是controller的源码;
具体到某个厂商的硬件,则描述如下:

Kconfig文件:内核开关,用于配置mbox模块是否编译到内核;
config ARM_MHU     
tristate "ARM MHU Mailbox"     
depends on ARM_AMBA     help       
    Say Y here if you want to build the ARM MHU controller driver.  The controller has 3 mailbox channels, the last of which can be  used in Secure mode only.

Makefile文件:根据Kconfig编译相应的模块;

我们知道要实现mailbox的源文件其实只有两个
obj-$(CONFIG_MAILBOX) += mailbox.o
obj-$(CONFIG_ARM_MHU) += arm_mhu.o

其中,mailbox.c 是kernel提供的framework,arm_mhu.c 则是具体厂商的实现

(4)client 通过mbox_send_message给controller发送数据的时候必须指定channel;
        int mbox_send_message(struct mbox_chan *chan, void *mssg)

(5)client 在通过mbox_send_message给controller发送数据的时候必须指定channel,channel可以通过以下方式获得。
目前kernel提供了两种方法得到mailbox的channel
struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);

使用完成后调用mbox_free_channel 释放channel,这样别人就可以继续使用这个channel;

void mbox_free_channel(struct mbox_chan *chan); /* may sleep */

其中,mbox_request_channel_byname是mbox_request_channel的一个封装。

2 基本框架


目录:

drivers/mailbox

mailbox.c/mailbox.h/mailbox-test.c/<vendor>-mailbox.c

3 关键数据结构

struct mbox_controller {struct device *dev;                                      // 特定mailbox驱动probe时赋值 dev = &pdev->devconst struct mbox_chan_ops *ops;                         // mailbox channel需要实现的功能函数struct mbox_chan *chans;                                 // mailbox channel指针数组int num_chans;                                           // mailbox channel个数bool txdone_irq; // 通过中断来判断上次传输是否完成bool txdone_poll;   // 通过poll机制来判断上次传输是否完成unsigned txpoll_period;                                  // POLL 周期, 以ms计struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,const struct of_phandle_args *sp);     // 获取特定channel的回调函数/* Internal to API */struct hrtimer poll_hrt;struct list_head node;
};struct mbox_chan {struct mbox_controller *mbox;                            // contronller指针unsigned txdone_method;                                  struct mbox_client *cl;                                  // client指针struct completion tx_complete;                           //void *active_req;unsigned msg_count, msg_free;void *msg_data[MBOX_TX_QUEUE_LEN];spinlock_t lock; /* Serialise access to the channel */void *con_priv;
};struct mbox_chan_ops {int (*send_data)(struct mbox_chan *chan, void *data);         // 发送数据(需要last data sent)int (*startup)(struct mbox_chan *chan);                       // 特定mailbox 启动void (*shutdown)(struct mbox_chan *chan);                     // 特定mailbox 关闭bool (*last_tx_done)(struct mbox_chan *chan);                 // 如果TXDONE_BY_POLL 该回调会被使用bool (*peek_data)(struct mbox_chan *chan);                    // 检测是否有数据
};struct mbox_client {struct device *dev;                                           // client 设备bool tx_block;                                                // block until last data is all transmittedunsigned long tx_tout;                                        // max block period for timeoutbool knows_txdone;                                            // txdone 回调,如果controller已经有txdone,则该配置无效void (*rx_callback)(struct mbox_client *cl, void *mssg);      // 收到数据void (*tx_prepare)(struct mbox_client *cl, void *mssg); // 准备数据void (*tx_done)(struct mbox_client *cl, void *mssg, int r);   // 检测txdone
};

4 函数接口

4.1 mailbox controller api

文件:kernel/include/linux/mailbox_controller.h

(1)注册、注销控制器
int mbox_controller_register(struct mbox_controller *mbox); /* can sleep */--------probe中调用
void mbox_controller_unregister(struct mbox_controller *mbox); /* can sleep */-------probe中调用

(2)(对外接口)将底层收到的数据回调给上层应用

void mbox_chan_received_data(struct mbox_chan *chan, void *data); /* atomic */

(3)通知上层当前数据已经发送完成

void mbox_chan_txdone(struct mbox_chan *chan, int r); /* atomic */

4.2 mailbox client api

文件:kernel/include/linux/mailbox_client.h

(1)发送数据前,申请通道
struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
                          const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);

(2)数据发送

int mbox_send_message(struct mbox_chan *chan, void *mssg);
void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */

(3)数据记录
bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */

(4)释放通道

void mbox_free_channel(struct mbox_chan *chan); /* may sleep */

5 Device Tree中的写法

kernel4.14/Documentation/devicetree/bindings/mailbox/hisilicon,hi6220-mailbox.txt


Hisilicon Hi6220 Mailbox Driver
===============================Hisilicon Hi6220 mailbox supports up to 32 channels. Each channel
is unidirectional with a maximum message size of 8 words. I/O is
performed using register access (there is no DMA) and the cell
raises an interrupt when messages are received.Mailbox Device Node(Controller):(设备节点相关的设备树)
====================Required properties:
--------------------
- compatible:        Shall be "hisilicon,hi6220-mbox"
- reg:            Contains the mailbox register address range (baseaddress and length); the first item is for IPCregisters, the second item is shared buffer forslots.
- #mbox-cells:        Common mailbox binding property to identify the numberof cells required for the mailbox specifier. Must be 3.<&phandle slot_id dst_irq ack_irq>phandle: Label name of mailbox controllerslot_id: Slot id used either for TX or RXdst_irq: IRQ identifier index number which used by MCUack_irq: IRQ identifier index number with generating aTX/RX interrupt to application processor,mailbox driver uses it to acknowledge interrupt
- interrupts:        Contains the interrupt information for the mailboxdevice. The format is dependent on which interruptcontroller the SoCs use.Optional Properties:
--------------------
- hi6220,mbox-tx-noirq: Property of MCU firmware's feature, so mailbox driveruse this flag to ask MCU to enable "automatic idleflag" mode or IRQ generated mode to acknowledge a TXcompletion.Example:
--------mailbox: mailbox@f7510000 {compatible = "hisilicon,hi6220-mbox";reg = <0x0 0xf7510000 0x0 0x1000>, /* IPC_S */<0x0 0x06dff800 0x0 0x0800>; /* Mailbox */interrupt-parent = <&gic>;interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;#mbox-cells = <3>;};Mailbox client(client相关的设备树)
===============Required properties:
--------------------
- compatible:        Many (See the client docs).
- mboxes:        Standard property to specify a Mailbox (See ./mailbox.txt)Cells must match 'mbox-cells' (See Mailbox Device Node above).Optional Properties:
--------------------
- mbox-names:        Name given to channels seen in the 'mboxes' property.Example:
--------stub_clock: stub_clock {compatible = "hisilicon,hi6220-stub-clk";hisilicon,hi6220-clk-sram = <&sram>;#clock-cells = <1>;mbox-names = "mbox-tx", "mbox-rx";mboxes = <&mailbox 1 0 11>, <&mailbox 0 1 10>;};

Example:

kernel4.14/arch/arm64/boot/dts/hisilicon/hi6220.dtsimailbox: mailbox@f7510000 {compatible = "hisilicon,hi6220-mbox";reg = <0x0 0xf7510000 0x0 0x1000>, /* IPC_S */<0x0 0x06dff800 0x0 0x0800>; /* Mailbox */interrupt-parent = <&gic>;interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;#mbox-cells = <3>;};Example:
--------stub_clock: stub_clock {compatible = "hisilicon,hi6220-stub-clk";hisilicon,hi6220-clk-sram = <&sram>;#clock-cells = <1>;mbox-names = "mbox-tx", "mbox-rx";mboxes = <&mailbox 1 0 11>, <&mailbox 0 1 10>;   <phandle channel_index dst_irq ack_irq>};

6 原理详解

6.1 原理概述

(1)driver 通过mbox_controller_register 注册controller;
(2)client 通过mbox_request_channel调用driver->startup;
(3)client 通过mbox_send_message调用driver->send_data,并等待txdone;
(4)driver 收到remote的中断读取数据调用mbox_chan_received_data将数据放到 client->rx_buffer中;

6.1.1 mailbox driver流程

(1)配置controller属性:
(2)申请chan,配置chan个数
(3)配置of_xlate回调,获取chan
(4)配置chan_ops
(5)配置txdone判断方式
(6)通过mailbox_controller_register 注册controller;

6.1.2 mailbox client 流程

(1)通过mbox_request_channel_byname 根据"mbox-names"申请channel;
(2)创建mbox设备;
(3)通过mbox设备的write/read 函数访问controller;
 其中,
write 通过调用mbox_send_message,add_to_rbuf拷贝msg到chan->msg_data[MAX = 20],msg_submit读取msg_data[idx],放到tx_prepare中,调用具体驱动的send message写寄存器;
 
read 通过irq驱动,irq读取寄存器得到消息,调用mailbox.c中的mbox_chan_received_data,再调用client的rx_callback将得到的数据放到client->rx_buffer中;

6.2 Mailbox Controller驱动

6.2.1 Mailbox Controller驱动初始化

6.2.1.1 mbox controller初始化函数

core_initcall(hi6220_mbox_init)>>>platform_driver_register(&hi6220_mbox_driver);
module_exit(hi6220_mbox_exit);>>>platform_driver_unregister(&hi6220_mbox_driver);static struct platform_driver hi6220_mbox_driver = {.driver = {.name = "hi6220-mbox",.owner = THIS_MODULE,.of_match_table = hi6220_mbox_of_match,},.probe    = hi6220_mbox_probe,//mbox controller drivers 初始化函数.remove    = hi6220_mbox_remove, //mbox controller drivers 逆初始化函数
};static const struct of_device_id hi6220_mbox_of_match[] = {{ .compatible = "hisilicon,hi6220-mbox", },{},
};

6.2.1.2 调用probe/remove 函数

probe()函数主要用于初始化mbox controller.

hi6220_mbox_probe(struct platform_device *pdev)>>>mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);//分配vendor设备结构体struct hi6220_mbox *mbox>>>初始化struct hi6220_mbox *mbox中的相关成员变量>>>mbox->mchan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->mchan), GFP_KERNEL);//为chan_num个struct hi6220_mbox_chan申请内存>>>mbox->chan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->chan), GFP_KERNEL);//为chan_num个struct mbox_chan申请内存>>>mbox->irq = platform_get_irq(pdev, 0);>>>res = platform_get_resource(pdev, IORESOURCE_MEM, 0);mbox->ipc = devm_ioremap_resource(dev, res);>>>    res = platform_get_resource(pdev, IORESOURCE_MEM, 1);mbox->base = devm_ioremap_resource(dev, res);>>>申请中断err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,    dev_name(dev), mbox);//其中,hi6220_mbox_interrupt为中断mbox->irq对应的服务函数>>>初始化controllermbox->controller.dev = dev;mbox->controller.chans = &mbox->chan[0];mbox->controller.num_chans = mbox->chan_num;mbox->controller.ops = &hi6220_mbox_ops;mbox->controller.of_xlate = hi6220_mbox_xlate;for (i = 0; i < mbox->chan_num; i++) {mbox->chan[i].con_priv = &mbox->mchan[i];mbox->irq_map_chan[i] = NULL;mbox->mchan[i].parent = mbox;mbox->mchan[i].slot   = i;}>>>mask and clear all interrupt vectorswritel(0x0,  ACK_INT_MSK_REG(mbox->ipc));writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));>>>判断中断使用poll方式还是中断方式/* use interrupt for tx's ack */if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL))mbox->tx_irq_mode = false;elsembox->tx_irq_mode = true;if (mbox->tx_irq_mode)mbox->controller.txdone_irq = true;else {mbox->controller.txdone_poll = true;mbox->controller.txpoll_period = 5;}>>>注册控制器err = mbox_controller_register(&mbox->controller);>>>保存mbox设备数据到pdev->dev->driver_dataplatform_set_drvdata(pdev, mbox);hi6220_mbox_remove(struct platform_device *pdev)>>>struct hi6220_mbox *mbox = platform_get_drvdata(pdev);>>>mbox_controller_unregister(&mbox->controller);

6.2.1.3 中断处理流程
probe函数中注册中断,driver 收到remote的中断,读取数据调用mbox_chan_received_data将数据放到 client->rx_buffer中

static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)>>>读取中断状态(哪个子中断置位???)state = readl(ACK_INT_STAT_REG(mbox->ipc));>>>    查询每个子中断的状态并进行响应        while (state) {>>>查询中断状态中的最高置1的位intr_bit = __ffs(state);//state &= (state - 1);chan = mbox->irq_map_chan[intr_bit];//每个中断位对应一个中断通道if (!chan) {dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",__func__, intr_bit);continue;}mchan = chan->con_priv;         //通道私有数据if (mchan->dir == MBOX_TX)      //若该通道(中断)为发送方向mbox_chan_txdone(chan, 0);else {                          //若该通道(中断)为接受方向for (i = 0; i < MBOX_MSG_LEN; i++)msg[i] = readl(mbox->base +MBOX_DATA_REG(mchan->slot) + i * 4);//读取数据mbox_chan_received_data(chan, (void *)msg);    //将数据交给数据接受函数进行处理}/* clear IRQ source */清中断writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);}

6.2.2 数据接收流程

数据接收是以中断的方式进行的。

hi6220_mbox_interrupt()>>>for (i = 0; i < MBOX_MSG_LEN; i++)msg[i] = readl(mbox->base +MBOX_DATA_REG(mchan->slot) + i * 4);//读取数据>>>mbox_chan_received_data(chan, (void *)msg);    //讲数据交给数据接受函数进行处理>>>chan->cl->rx_callback(chan->cl, mssg); //上层client回调

6.2.3 数据发送流程

6.2.3.1 数据发送分为三种方式

中断方式,polling方式,ACK方式
#define TXDONE_BY_IRQ    BIT(0) /* controller has remote RTR irq */
#define TXDONE_BY_POLL    BIT(1) /* controller can read status of last TX */
#define TXDONE_BY_ACK    BIT(2) /* S/W ACK recevied by Client ticks the TX */

6.2.3.2 数据发送的基本流程

1 获取mailbox的channel

1)申请通道时,client对象指定了自己的需求和能力;
2)在原子上下文中不能调用;
3)通道在一个client占用之后,没有释放之前,不能被其它client使用;
4)分配完成之后,任何此通道上接受的数据包将通过rx_callback传递到客户端
5)使用完成后调用mbox_free_channel 释放channel,这样别人就可以继续使用这个channel
void mbox_free_channel(struct mbox_chan *chan); /* may sleep */

struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
函数功能:通过dts中配置的channel index申请通道>>>of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", index, &spec)>>>根据dts中配置的channel index获得mbox_chanlist_for_each_entry(mbox, &mbox_cons, node)chan = mbox->of_xlate(mbox, &spec);>>>初始化mboxchan->msg_free = 0;chan->msg_count = 0;chan->active_req = NULL;chan->cl = cl;init_completion(&chan->tx_complete);>>>启动通道ret = chan->mbox->ops->startup(chan);struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
函数功能:通过channel name 申请通道,调用mbox_request_channel()函数来实现

2 使用mbox_send_message给controller发送数据

函数功能:在client提交数据到controller进而发送到目标处理器的过程中。
若client设置为tx_block,此函数调用只有在远程已经完成数据接受或tx_out(超时)才能返回;
若client设置为非block模式下,client的每个请求将被此API进行缓存,并返回一个非负数;
若client请求没有进入queue,将返回一个负数。
无论失败,还是成功,API将调用tx_done;

int mbox_send_message(struct mbox_chan *chan, void *mssg)>>>    t = add_to_rbuf(chan, mssg);    //将要发送的msg发暂存到对应通道的rbuf中>>>msg_submit(chan);>>>data = chan->msg_data[idx];>>>chan->cl->tx_prepare(chan->cl, data);   //发到缓存>>>err = chan->mbox->ops->send_data(chan, data);  //发送数据  hi6220_mbox_send_data,>>>mbox_set_state(mbox, slot, MBOX_STATE_TX);>>>if (mbox->tx_irq_mode)mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);>>>发送数据for (i = 0; i < MBOX_MSG_LEN; i++)writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);>>>/* trigger remote request */writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));等待中断。。。。。。。。。。------------------------------------------------------在中断服务函数中发送完成中断到来----------->>>>hi6220_mbox_interrupt>>>mbox_chan_txdone(chan, 0);>>>tx_tick(chan, r);>>>msg_submit(chan);>>>chan->cl->tx_done(chan->cl, mssg, r);------------------------------------------------------>>>若为polling方式下,启定时器hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);>>>若为block形式的发送>>>设置超时时间wait = msecs_to_jiffies(3600000);//永不超时wait = msecs_to_jiffies(chan->cl->tx_tout);>>>阻塞等待超时或完成ret = wait_for_completion_timeout(&chan->tx_complete, wait);>>>若超时时间到tx_tick(chan, t);>>>chan->cl->tx_done(chan->cl, mssg, r);>>>complete(&chan->tx_complete);

6.3 Mailbox Client驱动

以mailbox-test为例说明。

struct mbox_test_device {
    struct device        *dev;
    void __iomem        *tx_mmio;
    void __iomem        *rx_mmio;
    struct mbox_chan    *tx_channel;
    struct mbox_chan    *rx_channel;
    char            *rx_buffer;
    char            *signal;
    char            *message;
    spinlock_t        lock;
    wait_queue_head_t    waitq;
    struct fasync_struct    *async_queue;
};

6.3.1 Client 设备树相关的配置

Controller
----------Required properties:
- compatible            : Should be "st,stih407-mailbox"
- reg                   : Offset and length of the device's register set
- mbox-name             : Name of the mailbox
- #mbox-cells:          : Must be 2<&phandle instance channel direction>phandle   : Label name of controllerinstance  : Instance numberchannel   : Channel numberOptional properties
- interrupts            : Contains the IRQ line for a Rx mailbox
Example:mailbox0: mailbox@0  {compatible      = "st,stih407-mailbox";reg             = <0x08f00000 0x1000>;interrupts      = <GIC_SPI 1 IRQ_TYPE_NONE>;#mbox-cells     = <2>;mbox-name       = "a9";
};Client
------Required properties:
- compatible            : Many (See the client docs)
- reg                   : Shared (between Application and Remote) memory address
- mboxes                : Standard property to specify a Mailbox (See ./mailbox.txt)Cells must match 'mbox-cells' (See Controller docs above)Optional properties
- mbox-names            : Name given to channels seen in the 'mboxes' property.Example:mailbox_test {compatible      = "mailbox-test";reg             = <0x[shared_memory_address], [shared_memory_size]>;mboxes          = <&mailbox2 0 1>, <&mailbox0 2 1>;mbox-names      = "tx", "rx";
};

6.3.2 Client初始化

static struct platform_driver mbox_test_driver = {.driver = {.name = "mailbox_test",.of_match_table = mbox_test_match,},.probe  = mbox_test_probe,.remove = mbox_test_remove,
};
module_platform_driver(mbox_test_driver);static int mbox_test_probe(struct platform_device *pdev)>>>tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);>>>res = platform_get_resource(pdev, IORESOURCE_MEM, 0);>>>size = resource_size(res);>>>tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);>>>申请通道tdev->tx_channel = mbox_test_request_channel(pdev, "tx");tdev->rx_channel = mbox_test_request_channel(pdev, "rx");>>> client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);>>> client->dev        = &pdev->dev;>>> client->rx_callback    = mbox_test_receive_message;>>> client->tx_prepare = mbox_test_prepare_message;>>> client->tx_done        = mbox_test_message_sent;>>> client->tx_block  = true;>>> client->knows_txdone    = false;>>> client->tx_tout        = 500;>>> channel = mbox_request_channel_byname(client, name);  //调用API申请通道>>>platform_set_drvdata(pdev, tdev);>>>spin_lock_init(&tdev->lock);>>>tdev->rx_buffer = devm_kzalloc(&pdev->dev,MBOX_MAX_MSG_LEN, GFP_KERNEL);>>>ret = mbox_test_add_debugfs(pdev, tdev);>>>init_waitqueue_head(&tdev->waitq);static int mbox_test_remove(struct platform_device *pdev)>>> debugfs_remove_recursive(root_debugfs_dir);>>> mbox_free_channel(tdev->tx_channel);>>> mbox_free_channel(tdev->rx_channel);

6.3.3 Client数据收发

数据接收(回调函数)
static void mbox_test_receive_message(struct mbox_client *client, void *message)spin_lock_irqsave(&tdev->lock, flags);if (tdev->rx_mmio) {memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);} else if (message) {memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);}mbox_data_ready = true;spin_unlock_irqrestore(&tdev->lock, flags);wake_up_interruptible(&tdev->waitq);kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);数据发送
static void mbox_test_prepare_message(struct mbox_client *client, void *message)
{struct mbox_test_device *tdev = dev_get_drvdata(client->dev);if (tdev->tx_mmio) {if (tdev->signal)memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);elsememcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);}
}static void mbox_test_message_sent(struct mbox_client *client,void *message, int r)
{if (r)dev_warn(client->dev,"Client: Message could not be sent: %d\n", r);elsedev_info(client->dev,"Client: Message sent\n");
}

Linux Kernel编程 --- Mailbox驱动框架相关推荐

  1. mailbox 编程_Linux Kernel编程 --- Mailbox驱动框架【转】

    1 概述 (1)mailbox是一种框架,通过消息队列和中断驱动信号处理多处理器间的通讯: (2)mailbox的实现分为contoller和client.简单的说就是client 可以通过contr ...

  2. 【Linux开发】如何查看Linux kernel的内置模块驱动列表和进程ID

    [Linux开发]如何查看Linux kernel的内置模块驱动列表和进程ID 标签:[Linux开发] 命令: cat /lib/modules/$(uname -r)/modules.builti ...

  3. imx6 通过移植XRM117x(SPI转串口)对Linux中的SPI驱动框架进行分析

    最近分析了一下Linux 中的SPI驱动框架,将自己的理解总结一下,不足之处还请斧正! 1.SPI通信基础知识 SPI(Serial Peripheral Interface)是一种串行(一次发送1b ...

  4. Linux之字符设备驱动框架

    目录 一.驱动介绍 1.内核模块 2.日志级别 3.模块符号的导出 4.内核模块参数 二.字符设备驱动(一) 1.模块加载 2.注册字符设备驱动 3.内存映射 三.字符设备驱动(二) 1.模块加载 2 ...

  5. 从零开始学习linux的I2C设备驱动框架——写一个简单的SHT20驱动

    目录 0.测试环境说明 1.设备树的修改 2.设备驱动框架 3.I2C数据传输过程 3.1 struct i2c_msg 3.2 SHT20的数据收发 4.I2C适配器超时等待时间的修改 本文资源 参 ...

  6. 【分析笔记】Linux 4.9 单总线驱动框架分析

    文章介绍 本文主要是基于 T507 Android 10 Linux 4.9 的源代码,对 Linux W1 总线框架的分析记录,便于了解整个框架的基本实现机制. 驱动框架 这张图基本上将内部的各个源 ...

  7. linux kernel有线网卡驱动enc28j60分析 一

    1.为了更好低学习linux的网络驱动架构,本文选择分析linux kernel下的有线网卡驱动enc28j60来学习网络驱动架构. enc28j60是一个10/100Mb的有线网卡,适用于嵌入式设备 ...

  8. Linux下的FrameBuffer驱动框架

    一.RGB LCD经典显示器件介绍: 1.LCD屏幕的重要属性参数: ① 分辨率:也就是屏幕上的像素点的个数: ② 像素格式:即单个像素点RGB三种颜色的表达方式,包括RGB888.ARGB8888和 ...

  9. linux kernel内核、驱动日志调试方法(一)

    本文是对网络资料进行总结归纳,抄录其他博客资料,如有侵权,请告知,进行删除 一:通过打印调试printk printk是打印内核消息的函数,printk通过附加不同日志级别(loglevel)或者说消 ...

最新文章

  1. Mysql5.6主从复制-基于binlog
  2. Cloudify — OpenStack Infrastructure Plugin V3
  3. JQuery Ajax解读(3)
  4. 本月 上月 php,显示本月,上月,今天,今年以及各时间起点与
  5. java继承总结_java继承总结(二)
  6. 深度学习总结:GAN,3种方式实现fixedGtrainD,fixedDtrainG, retain, detach
  7. RHEL5.X 重启网卡出现./network-functions: line 78: .: ifcfg-eth0: file not found
  8. [JavaWeb]Web概念概述
  9. JavaScript 字符串截取方法汇总
  10. python getsize_Python getsizeof()和getsize()区分详解
  11. LINUX SHELL中echo如何处理特殊字符
  12. 职场:迈过职业生涯中的5个坎
  13. 状态良好(恢复分区)空间的删除的方法
  14. 双平衡吉尔伯特混频器设计(项目设计论文)
  15. Flask框架:创建app对象
  16. android 11.0 12.0第三方输入法app设置系统默认输入法
  17. 分布式系统下的幂等性问题如何解决?
  18. 搭建阿里云物联网平台实现MQTT通信
  19. 九连环问题(Java)
  20. ubuntu18.04-ros-melodic-carlar安装教程详细指南

热门文章

  1. 语音识别框架之ESPnet
  2. CF-B. Morning Jogging
  3. 天翼网盘客户端数据目录研究
  4. tiny4412 linux-4.2 移植(七)USB 2.0 host框架(1)phy
  5. SSM毕设项目酒店餐饮管理系统ls1a2(java+VUE+Mybatis+Maven+Mysql)
  6. 音乐制作软件中文版-Studio One 4.5.1 WiN-MAC
  7. 一键清理垃圾文件清理代码.bat
  8. loadrunner12--tree
  9. 一文掌握 YUV 图像的基本处理
  10. webService 实战篇--客户端调用