Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  tipc.c

  Sprache: C
 

/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include <interface/spi/spi.h>
#include <lib/spi/common/utils.h>
#include <lib/spi/srv/common/common.h>
#include <lib/spi/srv/tipc/tipc.h>
#include <lib/tipc/tipc_srv.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <uapi/err.h>
#include <uapi/mm.h>

#define TLOG_TAG "spi-srv-tipc"
#include <trusty_log.h>

/**
 * chan_ctx - per-connection SPI data
 * @shm:        state of memory region shared with SPI server
 * @shm_handle: handle to shared memory region
 * @cs:         tracks CS state of the underlying SPI device
 *              true - asserted, false - deasserted
 */

struct chan_ctx {
    struct mem_buf shm;
    handle_t shm_handle;
    bool cs;
};

static inline bool shm_is_mapped(struct chan_ctx* ctx) {
    return ctx->shm.buf && ctx->shm_handle != INVALID_IPC_HANDLE;
}

static inline void shm_unmap(struct chan_ctx* ctx) {
    if (shm_is_mapped(ctx)) {
        int rc = munmap(ctx->shm.buf, ctx->shm.capacity);
        if (rc != NO_ERROR) {
            TLOGW("munmap() failed: %d\n", rc);
        }
        mb_destroy(&ctx->shm);
        close(ctx->shm_handle);
        ctx->shm_handle = INVALID_IPC_HANDLE;
    }
}

union spi_msg_req_args {
    struct spi_shm_map_req shm;
    struct spi_batch_req batch;
};

static size_t get_spi_msg_size(struct spi_msg_req* req) {
    size_t msg_size = sizeof(struct spi_msg_req);
    switch (req->cmd & SPI_CMD_OP_MASK) {
    case SPI_CMD_MSG_OP_SHM_MAP:
        msg_size += sizeof(struct spi_shm_map_req);
        break;

    case SPI_CMD_MSG_OP_BATCH_EXEC:
        msg_size += sizeof(struct spi_batch_req);
        break;
    }
    return msg_size;
}

static int recv_msg(handle_t chan,
                    struct spi_msg_req* req,
                    union spi_msg_req_args* args,
                    handle_t* h) {
    int rc;
    struct ipc_msg_info msg_inf;
    size_t num_handles = h ? 1 : 0;

    rc = get_msg(chan, &msg_inf);
    if (rc != NO_ERROR) {
        TLOGE("failed (%d) to get_msg()\n", rc);
        return rc;
    }

    struct iovec iovs[2] = {
            {
                    .iov_base = req,
                    .iov_len = sizeof(*req),
            },
            {
                    .iov_base = args,
                    .iov_len = sizeof(*args),
            },
    };
    struct ipc_msg msg = {
            .iov = iovs,
            .num_iov = countof(iovs),
            .handles = h,
            .num_handles = num_handles,
    };
    rc = read_msg(chan, msg_inf.id, 0, &msg);
    if (rc != (int)get_spi_msg_size(req)) {
        TLOGE("failed (%d) to read_msg()\n", rc);
        put_msg(chan, msg_inf.id);
        return rc;
    }

    put_msg(chan, msg_inf.id);
    return NO_ERROR;
}

static int handle_msg_shm_map_req(handle_t chan,
                                  struct chan_ctx* ctx,
                                  struct spi_shm_map_req* shm_req,
                                  handle_t shm_handle) {
    int rc1, rc = NO_ERROR;
    void* shm_base;

    shm_unmap(ctx);

    shm_base = mmap(0, shm_req->len, MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE,
                    0, shm_handle, 0);
    if (shm_base == MAP_FAILED) {
        TLOGE("failed to map shared memory\n");
        rc = ERR_GENERIC;
        goto err_mmap;
    }

    struct spi_msg_resp resp = {
        .status = translate_lk_err(rc)
    };

    rc = tipc_send1(chan, &resp, sizeof(resp));
    if (rc < 0 || (size_t)rc != sizeof(resp)) {
        TLOGE("failed (%d) to send SPI response\n", rc);
        if (rc >= 0) {
            rc = ERR_BAD_LEN;
        }
        goto err_resp;
    }

    mb_init(&ctx->shm, shm_base, shm_req->len, SPI_CMD_SHM_ALIGN);
    ctx->shm_handle = shm_handle;
    return NO_ERROR;

err_resp:
    rc1 = munmap(shm_base, shm_req->len);
    if (rc1 != NO_ERROR) {
        TLOGW("munmap() failed: %d\n", rc);
    }
err_mmap:
    return rc;
}

static int handle_msg_batch_req(handle_t chan,
                                struct spi_dev_ctx* spi,
                                struct chan_ctx* ctx,
                                struct spi_batch_req* batch_req) {
    int rc;
    struct spi_batch_state state;

    if (!shm_is_mapped(ctx)) {
        return ERR_BAD_STATE;
    }

    state.cs = ctx->cs;
    state.num_cmds = 0;
    rc = spi_srv_handle_batch(spi, &ctx->shm, batch_req, &state);
    if (rc == NO_ERROR) {
        ctx->cs = state.cs;
    }

    struct spi_msg_resp resp = {
        .cmd = SPI_CMD_MSG_OP_BATCH_EXEC | SPI_CMD_RESP_BIT,
        .status = translate_lk_err(rc)
    };

    struct spi_batch_resp batch_resp = {
        .len = mb_curr_pos(&ctx->shm),
        .failed = (rc != NO_ERROR) ? (uint32_t)state.num_cmds : 0
    };

    rc = tipc_send2(chan, &resp, sizeof(resp), &batch_resp, sizeof(batch_resp));
    if (rc < 0 || (size_t)rc != sizeof(resp) + sizeof(batch_resp)) {
        TLOGE("failed (%d) to send batch response\n", rc);
        if (rc >= 0) {
            rc = ERR_BAD_LEN;
        }
        return rc;
    }

    return NO_ERROR;
}

static int on_connect(const struct tipc_port* port,
                      handle_t chan,
                      const struct uuid* peer,
                      void** ctx_p) {
    struct chan_ctx* ctx = calloc(1sizeof(struct chan_ctx));
    if (!ctx) {
        TLOGE("failed to allocate channel context\n");
        return ERR_NO_MEMORY;
    }

    ctx->shm_handle = INVALID_IPC_HANDLE;

    *ctx_p = ctx;
    return NO_ERROR;
}

static int on_message(const struct tipc_port* port,
                      handle_t chan,
                      void* chan_ctx) {
    int rc;
    struct spi_msg_req req;
    union spi_msg_req_args args;
    struct spi_dev_ctx* spi = (struct spi_dev_ctx*)port->priv;
    struct chan_ctx* ctx = (struct chan_ctx*)chan_ctx;
    handle_t h = INVALID_IPC_HANDLE;

    rc = recv_msg(chan, &req, &args, &h);
    if (rc != NO_ERROR) {
        TLOGE("failed (%d) to receive SPI message, closing connection\n", rc);
        return rc;
    }

    switch (req.cmd & SPI_CMD_OP_MASK) {
    case SPI_CMD_MSG_OP_SHM_MAP:
        rc = handle_msg_shm_map_req(chan, ctx, &args.shm, h);
        break;

    case SPI_CMD_MSG_OP_BATCH_EXEC:
        rc = handle_msg_batch_req(chan, spi, ctx, &args.batch);
        break;

    default:
        TLOGE("cmd 0x%x: unknown command\n", req.cmd);
        rc = ERR_CMD_UNKNOWN;
    }

    if (rc != NO_ERROR) {
        TLOGE("failed (%d) to handle SPI message, closing connection\n", rc);
        return rc;
    }

    return NO_ERROR;
}

static void on_disconnect(const struct tipc_port* port,
                          handle_t chan,
                          void* _ctx) {
    int rc;
    struct spi_dev_ctx* spi = (struct spi_dev_ctx*)port->priv;
    struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
    struct spi_shm_hdr hdr;
    struct mem_buf mb;
    struct spi_batch_req req;
    struct spi_batch_state state;

    /* make sure CS is deasserted */
    if (!ctx->cs) {
        return;
    }

    /* Construct a batch with a single deassert command to recover CS state */
    hdr.cmd = SPI_CMD_SHM_OP_CS_DEASSERT;

    /* Deassert commands are header only */
    mb_init(&mb, &hdr, sizeof(hdr), SPI_CMD_SHM_ALIGN);
    mb_resize(&mb, sizeof(hdr));

    req.len = sizeof(hdr);
    req.num_cmds = 1;

    state.cs = true;
    state.num_cmds = 0;

    rc = spi_srv_handle_batch(spi, &mb, &req, &state);
    /* CS state will be out of sync. This is an unrecoverable error. */
    assert(rc == NO_ERROR);

    ctx->cs = false;
}

static void on_channel_cleanup(void* _ctx) {
    struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
    assert(!ctx->cs);
    shm_unmap(ctx);
    free(ctx);
}

static const struct tipc_srv_ops spi_dev_ops = {
        .on_connect = on_connect,
        .on_message = on_message,
        .on_disconnect = on_disconnect,
        .on_channel_cleanup = on_channel_cleanup,
};

int add_spi_service(struct tipc_hset* hset,
                    const struct tipc_port* ports,
                    size_t num_ports) {
    int rc;

    for (size_t i = 0; i < num_ports; i++) {
        if (!ports[i].priv) {
            return ERR_INVALID_ARGS;
        }

#if TEST_BUILD
        const uint32_t max_chan_cnt = 2;
#else
        const uint32_t max_chan_cnt = 1;
#endif
        rc = tipc_add_service(hset, &ports[i], 1, max_chan_cnt, &spi_dev_ops);
        if (rc != NO_ERROR) {
            return rc;
        }
    }

    return NO_ERROR;
}

Messung V0.5 in Prozent
C=90 H=95 G=92

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik