/* * Copyright (c) 2022-2023 Huawei Device Co., Ltd. * * This file is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include #include "can/can_core.h" #include "device_resource_if.h" #include "hdf_log.h" #include "osal_mem.h" #define HDF_LOG_TAG can_virtual_c #define CAN_VIRTUAL_BUS_NUM_DFT 31 struct VirtualCanCntlr { struct CanCntlr cntlr; uint8_t workMode; uint32_t bitRate; uint32_t syncJumpWidth; uint32_t timeSeg1; uint32_t timeSeg2; uint32_t prescaler; int32_t busState; }; enum VIRTUAL_CAN_SPEED { CAN_SPEED_1M = 1000UL * 1000, /* 1 MBit/sec */ CAN_SPEED_800K = 1000UL * 800, /* 800 kBit/sec */ CAN_SPEED_500K = 1000UL * 500, /* 500 kBit/sec */ CAN_SPEED_250K = 1000UL * 250, /* 250 kBit/sec */ CAN_SPEED_125K = 1000UL * 125, /* 125 kBit/sec */ CAN_SPEED_100K = 1000UL * 100, /* 100 kBit/sec */ CAN_SPEED_50K = 1000UL * 50, /* 50 kBit/sec */ CAN_SPEED_20K = 1000UL * 20, /* 20 kBit/sec */ CAN_SPEED_10K = 1000UL * 10 /* 10 kBit/sec */ }; static int32_t VirtualReadConfigFromHcs(struct VirtualCanCntlr *virtualCan) { uint32_t value; const struct DeviceResourceNode *node = NULL; struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); if (virtualCan == NULL) { HDF_LOGE("%s: virtual cntlr is null", __func__); return HDF_ERR_INVALID_OBJECT; } node = PlatformDeviceGetDrs(&virtualCan->cntlr.device); if (node == NULL) { HDF_LOGE("%s: properity node null", __func__); return HDF_ERR_INVALID_PARAM; } if (iface == NULL || iface->GetUint32 == NULL) { HDF_LOGE("%s: face is invalid", __func__); return HDF_ERR_NOT_SUPPORT; } if (iface->GetUint32(node, "bus_num", &value, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read bus number failed", __func__); return HDF_FAILURE; } virtualCan->cntlr.number = (int32_t)value; if (iface->GetUint8(node, "work_mode", &virtualCan->workMode, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read work mode failed", __func__); return HDF_FAILURE; } if (iface->GetUint32(node, "bit_rate", &virtualCan->bitRate, 0) != HDF_SUCCESS) { HDF_LOGE("%s: read bit reate failed", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t VirtualCanMsgLoopBack(struct VirtualCanCntlr *virtualCan, const struct CanMsg *msg) { struct CanMsg new; HDF_LOGI("VirtualCanMsgLoopBack: begin"); new = *msg; // Yeah! this is loop back ... virtualCan->busState = CAN_BUS_READY; HDF_LOGI("VirtualCanMsgLoopBack: end"); return CanCntlrOnNewMsgIrqSafe(&virtualCan->cntlr, &new); } static int32_t VirtualCanSendMsg(struct CanCntlr *cntlr, const struct CanMsg *msg) { struct VirtualCanCntlr *virtualCan = NULL; if (cntlr == NULL) { return HDF_ERR_INVALID_OBJECT; } if (msg == NULL) { return HDF_ERR_INVALID_PARAM; } virtualCan = (struct VirtualCanCntlr *)cntlr->device.priv; if (virtualCan == NULL) { HDF_LOGE("%s: private data is null", __func__); return HDF_ERR_INVALID_OBJECT; } virtualCan->busState = CAN_BUS_BUSY; return VirtualCanMsgLoopBack(virtualCan, msg); } struct VirtualSpeedConfigMap { uint32_t speed; uint32_t sjw; uint32_t tsg1; uint32_t tsg2; uint32_t prescaler; }; #define CAN_CLK 80M #define CAN_SJW_2TQ 2 #define CAN_BS1_5TQ 5 #define CAN_BS1_7TQ 7 #define CAN_BS1_13TQ 13 #define CAN_BS1_14TQ 14 #define CAN_BS2_2TQ 2 #define CAN_BS2_5TQ 5 /* * S(bit rate) = 1 / ((1 + BS1 + BS2) * TQ) * TQ = Prescaler / Fclk * S(bit rate) = Fclk / (Prescaler * (1 + BS1 + BS2)) */ static const struct VirtualSpeedConfigMap g_speedMaps[] = { {CAN_SPEED_1M, CAN_SJW_2TQ, CAN_BS1_5TQ, CAN_BS2_2TQ, 10 }, {CAN_SPEED_800K, CAN_SJW_2TQ, CAN_BS1_14TQ, CAN_BS2_5TQ, 5 }, {CAN_SPEED_500K, CAN_SJW_2TQ, CAN_BS1_7TQ, CAN_BS2_2TQ, 16 }, {CAN_SPEED_250K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 20 }, {CAN_SPEED_125K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 40 }, {CAN_SPEED_100K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 50 }, {CAN_SPEED_50K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 100}, {CAN_SPEED_20K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 250}, {CAN_SPEED_10K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 500} }; static int32_t VirtualCanSetBitRate(struct VirtualCanCntlr *virtualCan, uint32_t speed) { int32_t i; const struct VirtualSpeedConfigMap *cfgMap; for (i = 0; i < sizeof(g_speedMaps) / sizeof(g_speedMaps[0]); i++) { if (g_speedMaps[i].speed == speed) { break; } } if (i >= (sizeof(g_speedMaps) / sizeof(g_speedMaps[0]))) { HDF_LOGE("%s: speed: %u not support", __func__, speed); return HDF_ERR_NOT_SUPPORT; } cfgMap = &g_speedMaps[i]; virtualCan->syncJumpWidth = cfgMap->sjw; virtualCan->timeSeg1 = cfgMap->tsg1; virtualCan->timeSeg2 = cfgMap->tsg2; virtualCan->prescaler = cfgMap->prescaler; virtualCan->bitRate = speed; return HDF_SUCCESS; } static int32_t VirtualCanSetMode(struct VirtualCanCntlr *virtualCan, int32_t mode) { if (mode == CAN_BUS_LOOPBACK) { virtualCan->workMode = CAN_BUS_LOOPBACK; return HDF_SUCCESS; } else { return HDF_ERR_NOT_SUPPORT; } } static int32_t VirtualCanSetCfg(struct CanCntlr *cntlr, const struct CanConfig *cfg) { int32_t ret; struct VirtualCanCntlr *virtualCan = NULL; virtualCan = (struct VirtualCanCntlr *)cntlr->device.priv; if (virtualCan == NULL) { HDF_LOGE("%s: private data is null", __func__); return HDF_ERR_INVALID_OBJECT; } virtualCan->busState = CAN_BUS_RESET; ret = VirtualCanSetBitRate(virtualCan, cfg->speed); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set speed failed", __func__); return ret; } ret = VirtualCanSetMode(virtualCan, cfg->mode); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set mode failed", __func__); return ret; } virtualCan->busState = CAN_BUS_READY; return HDF_SUCCESS; } static int32_t VirtualCanGetCfg(struct CanCntlr *cntlr, struct CanConfig *cfg) { struct VirtualCanCntlr *virtualCan = NULL; virtualCan = (struct VirtualCanCntlr *)cntlr->device.priv; if (virtualCan == NULL) { HDF_LOGE("%s: private data is null", __func__); return HDF_ERR_INVALID_OBJECT; } cfg->speed = virtualCan->bitRate; cfg->mode = virtualCan->workMode; return HDF_SUCCESS; } struct CanCntlrMethod g_virtualCanMethod = { .sendMsg = VirtualCanSendMsg, .setCfg = VirtualCanSetCfg, .getCfg = VirtualCanGetCfg, }; /* * ! this function will not be invoked when polciy is 0 * ! no need to make any changes here */ static int32_t HdfVirtualCanBind(struct HdfDeviceObject *device) { return CanServiceBind(device); } static void VirtualCanSetDefault(struct VirtualCanCntlr *virtualCan) { virtualCan->cntlr.number = CAN_VIRTUAL_BUS_NUM_DFT; virtualCan->workMode = CAN_BUS_LOOPBACK; virtualCan->bitRate = CAN_SPEED_10K; } static int32_t VirtualCanInit(struct VirtualCanCntlr *virtualCan) { int32_t ret; HDF_LOGI("%s: enter", __func__); if (virtualCan == NULL) { return HDF_ERR_INVALID_OBJECT; } VirtualCanSetDefault(virtualCan); ret = VirtualReadConfigFromHcs(virtualCan); if (ret != HDF_SUCCESS) { HDF_LOGW("VirtualUartInit: read hcs config failed"); } ret = VirtualCanSetBitRate(virtualCan, virtualCan->bitRate); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set bit rate failed", __func__); return ret; } ret = VirtualCanSetMode(virtualCan, virtualCan->workMode); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set mode failed", __func__); return ret; } return HDF_SUCCESS; } static int32_t HdfVirtualCanInit(struct HdfDeviceObject *device) { int32_t ret; struct VirtualCanCntlr *virtualCan = NULL; HDF_LOGI("%s: entry", __func__); if (device == NULL) { HDF_LOGE("%s: device is null", __func__); return HDF_ERR_INVALID_OBJECT; } virtualCan = (struct VirtualCanCntlr *)OsalMemCalloc(sizeof(*virtualCan)); if (virtualCan == NULL) { return HDF_ERR_MALLOC_FAIL; } virtualCan->busState = CAN_BUS_RESET; ret = VirtualCanInit(virtualCan); if (ret != HDF_SUCCESS) { OsalMemFree(virtualCan); HDF_LOGE("%s: can init error: %d", __func__, ret); return ret; } virtualCan->busState = CAN_BUS_READY; virtualCan->cntlr.ops = &g_virtualCanMethod; virtualCan->cntlr.device.priv = virtualCan; ret = CanCntlrAdd(&virtualCan->cntlr); if (ret != HDF_SUCCESS) { OsalMemFree(virtualCan); HDF_LOGE("%s: add cntlr failed: %d", __func__, ret); return ret; } ret = CanCntlrSetHdfDev(&virtualCan->cntlr, device); if (ret != HDF_SUCCESS) { HDF_LOGW("%s: can controller attach failed:%d", __func__, ret); } return HDF_SUCCESS; } static int32_t VirtualCanDeinit(struct VirtualCanCntlr *virtualCan) { (void)virtualCan; return HDF_SUCCESS; } static void HdfVirtualCanRelease(struct HdfDeviceObject *device) { struct VirtualCanCntlr *virtualCan = NULL; HDF_LOGI("%s: entry", __func__); if (device == NULL) { HDF_LOGE("%s: device is null", __func__); return; } virtualCan = (struct VirtualCanCntlr *)CanCntlrFromHdfDev(device); if (virtualCan == NULL) { HDF_LOGE("%s: platform device not bind", __func__); return; } CanServiceRelease(device); (void)CanCntlrDel(&virtualCan->cntlr); VirtualCanDeinit(virtualCan); OsalMemFree(virtualCan); } static struct HdfDriverEntry g_hdfCanDriver = { .moduleVersion = 1, .moduleName = "can_driver_virtual", .Bind = HdfVirtualCanBind, .Init = HdfVirtualCanInit, .Release = HdfVirtualCanRelease, }; struct HdfDriverEntry *CanVirtualGetEntry(void) { return &g_hdfCanDriver; } HDF_INIT(g_hdfCanDriver);