Linux Kernel編程 --- Mailbox驅動框架【轉】


轉自:https://blog.csdn.net/u010961173/article/details/96422441

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->dev
    const 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 transmitted
    unsigned long tx_tout;                                        // max block period for timeout
    bool 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 (base
            address and length); the first item is for IPC
            registers, the second item is shared buffer for
            slots.
- #mbox-cells:        Common mailbox binding property to identify the number
            of cells required for the mailbox specifier. Must be 3.
            <&phandle slot_id dst_irq ack_irq>
              phandle: Label name of mailbox controller
              slot_id: Slot id used either for TX or RX
              dst_irq: IRQ identifier index number which used by MCU
              ack_irq: IRQ identifier index number with generating a
                       TX/RX interrupt to application processor,
                   mailbox driver uses it to acknowledge interrupt
- interrupts:        Contains the interrupt information for the mailbox
            device. The format is dependent on which interrupt
            controller the SoCs use.

Optional Properties:
--------------------
- hi6220,mbox-tx-noirq: Property of MCU firmware's feature, so mailbox driver
            use this flag to ask MCU to enable "automatic idle
            flag" mode or IRQ generated mode to acknowledge a TX
            completion.

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.dtsi


    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>;
    };

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對應的服務函數
            >>>初始化controller
                        mbox->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 vectors
                      writel(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;
                    else
                        mbox->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_data
                platform_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_chan
                list_for_each_entry(mbox, &mbox_cons, node)
                    chan = mbox->of_xlate(mbox, &spec);
        >>>初始化mbox
                chan->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 controller
instance : Instance number
channel : Channel number

Optional 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);
else
memcpy_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);
else
dev_info(client->dev,
"Client: Message sent\n");
}

 
————————————————
版權聲明:本文為CSDN博主「huofengfeihu」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010961173/article/details/96422441


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM