/* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ /** * @file bus.c * @brief 1、support bus driver framework;2、provide bus API。 * @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 */ #include #include DoubleLinklistType bus_linklist; /*Create the bus linklist*/ static void BusLinkInit(struct Bus *bus) { static uint8 bus_link_flag = RET_FALSE; if(!bus_link_flag) { InitDoubleLinkList(&bus_linklist); bus_link_flag = RET_TRUE; bus->bus_link_flag = RET_TRUE; } /*Create the driver of the bus linklist*/ if(!bus->bus_drvlink_flag) { InitDoubleLinkList(&bus->bus_drvlink); bus->bus_drvlink_flag = RET_TRUE; } /*Create the hardware device of the bus linklist*/ if(!bus->bus_devlink_flag) { InitDoubleLinkList(&bus->bus_devlink); bus->bus_devlink_flag = RET_TRUE; } } static int BusMatchDrvDev(struct Driver *driver, struct HardwareDev *device) { NULL_PARAM_CHECK(driver); NULL_PARAM_CHECK(device); if(!strncmp(driver->owner_bus->bus_name, device->owner_bus->bus_name, NAME_NUM_MAX)) { KPrintf("BusMatchDrvDev match successfully, bus name %s\n", driver->owner_bus->bus_name); driver->private_data = device->private_data;//driver get the device param device->owner_bus->owner_driver = driver; driver->owner_bus->owner_haldev = device; return EOK; } return ERROR; } /** * @Description: support to obtain bus for a certain dev if necessary, then configure and init its drv * @param bus - bus pointer * @param dev - dev pointer * @param drv_name - drv name * @param configure_info - BusConfigureInfo pointer * @return successful:EOK,failed:ERROR */ int DeviceObtainBus(struct Bus *bus, struct HardwareDev *dev, const char *drv_name, struct BusConfigureInfo *configure_info) { NULL_PARAM_CHECK(bus); NULL_PARAM_CHECK(dev); int32 ret = EOK; ret = KMutexObtain(bus->bus_lock, WAITING_FOREVER); if(EOK != ret) { KPrintf("DevObtainBus bus_lock error %d!\n", ret); return ret; } if(bus->owner_haldev != dev) { struct Driver *drv = BusFindDriver(bus, drv_name); configure_info->configure_cmd = OPE_CFG; drv->configure(drv, configure_info); configure_info->configure_cmd = OPE_INT; drv->configure(drv, configure_info); bus->owner_haldev = dev; } return ret; } /** * @Description: support to register bus pointer with linklist * @param bus - bus pointer * @return successful:EOK,failed:NONE */ int BusRegister(struct Bus *bus) { x_err_t ret = EOK; NULL_PARAM_CHECK(bus); bus->match = BusMatchDrvDev; BusLinkInit(bus); bus->bus_lock = KMutexCreate(); DoubleLinkListInsertNodeAfter(&bus_linklist, &(bus->bus_link)); return ret; } /** * @Description: support to release bus pointer in linklist * @param bus - bus pointer * @return successful:EOK,failed:NONE */ int BusRelease(struct Bus *bus) { NULL_PARAM_CHECK(bus); KMutexAbandon(bus->bus_lock); bus->bus_cnt = 0; bus->driver_cnt = 0; bus->haldev_cnt = 0; bus->bus_link_flag = RET_FALSE; bus->bus_drvlink_flag = RET_FALSE; bus->bus_devlink_flag = RET_FALSE; return EOK; } /** * @Description: support to unregister bus pointer and delete its linklist node * @param bus - bus pointer * @return successful:EOK,failed:NONE */ int BusUnregister(struct Bus *bus) { NULL_PARAM_CHECK(bus); bus->bus_cnt--; DoubleLinkListRmNode(&(bus->bus_link)); return EOK; } /** * @Description: support to register driver pointer to bus pointer * @param bus - bus pointer * @param driver - driver pointer * @return successful:EOK,failed:NONE */ int DriverRegisterToBus(struct Bus *bus, struct Driver *driver) { NULL_PARAM_CHECK(bus); NULL_PARAM_CHECK(driver); driver->owner_bus = bus; bus->driver_cnt++; DoubleLinkListInsertNodeAfter(&bus->bus_drvlink, &(driver->driver_link)); return EOK; } /** * @Description: support to register dev pointer to bus pointer * @param bus - bus pointer * @param device - device pointer * @return successful:EOK,failed:NONE */ int DeviceRegisterToBus(struct Bus *bus, struct HardwareDev *device) { NULL_PARAM_CHECK(bus); NULL_PARAM_CHECK(device); device->owner_bus = bus; bus->haldev_cnt++; DoubleLinkListInsertNodeAfter(&bus->bus_devlink, &(device->dev_link)); return EOK; } /** * @Description: support to delete driver pointer from bus pointer * @param bus - bus pointer * @param driver - driver pointer * @return successful:EOK,failed:NONE */ int DriverDeleteFromBus(struct Bus *bus, struct Driver *driver) { NULL_PARAM_CHECK(bus); NULL_PARAM_CHECK(driver); bus->driver_cnt--; DoubleLinkListRmNode(&(driver->driver_link)); free(driver); return EOK; } /** * @Description: support to delete dev pointer from bus pointer * @param bus - bus pointer * @param device - device pointer * @return successful:EOK,failed:NONE */ int DeviceDeleteFromBus(struct Bus *bus, struct HardwareDev *device) { NULL_PARAM_CHECK(bus); NULL_PARAM_CHECK(device); bus->haldev_cnt--; DoubleLinkListRmNode(&(device->dev_link)); free(device); return EOK; } /** * @Description: support to find bus pointer by bus name * @param bus_name - bus name * @return successful:bus pointer,failed:NONE */ BusType BusFind(const char *bus_name) { struct Bus *bus = NONE; DoubleLinklistType *node = NONE; DoubleLinklistType *head = &bus_linklist; for (node = head->node_next; node != head; node = node->node_next) { bus = SYS_DOUBLE_LINKLIST_ENTRY(node, struct Bus, bus_link); if(!strcmp(bus->bus_name, bus_name)) { return bus; } } KPrintf("BusFind cannot find the %s bus.return NULL\n", bus_name); return NONE; } /** * @Description: support to find driver pointer of certain bus by driver name * @param bus - bus pointer * @param driver_name - driver name * @return successful:EOK,failed:NONE */ DriverType BusFindDriver(struct Bus *bus, const char *driver_name) { NULL_PARAM_CHECK(bus); struct Driver *driver = NONE; DoubleLinklistType *node = NONE; DoubleLinklistType *head = &bus->bus_drvlink; for (node = head->node_next; node != head; node = node->node_next) { driver = SYS_DOUBLE_LINKLIST_ENTRY(node, struct Driver, driver_link); if(!strcmp(driver->drv_name, driver_name)) { return driver; } } KPrintf("BusFindDriver cannot find the %s driver.return NULL\n", driver_name); return NONE; } /** * @Description: support to find device pointer of certain bus by device name * @param bus - bus pointer * @param device_name - device name * @return successful:EOK,failed:NONE */ HardwareDevType BusFindDevice(struct Bus *bus, const char *device_name) { NULL_PARAM_CHECK(bus); struct HardwareDev *device = NONE; DoubleLinklistType *node = NONE; DoubleLinklistType *head = &bus->bus_devlink; for (node = head->node_next; node != head; node = node->node_next) { device = SYS_DOUBLE_LINKLIST_ENTRY(node, struct HardwareDev, dev_link); if(!strcmp(device->dev_name, device_name)) { return device; } } KPrintf("BusFindDevice cannot find the %s device.return NULL\n", device_name); return NONE; } /** * @Description: support to set dev receive function callback * @param dev - dev pointer * @param dev_recv_callback - callback function * @return successful:EOK,failed:ERROR */ uint32 BusDevRecvCallback(struct HardwareDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length)) { NULL_PARAM_CHECK(dev ); dev->dev_recv_callback = dev_recv_callback; return EOK; } /** * @Description: support to open dev * @param dev - dev pointer * @return successful:EOK,failed:ERROR */ uint32 BusDevOpen(struct HardwareDev *dev) { NULL_PARAM_CHECK(dev); x_err_t ret = EOK; if (dev->dev_done->open) { ret = dev->dev_done->open(dev); if(ret) { KPrintf("BusDevOpen error ret %u\n", ret); return ERROR; } } return ret; } /** * @Description: support to close dev * @param dev - dev pointer * @return successful:EOK,failed:ERROR */ uint32 BusDevClose(struct HardwareDev *dev) { NULL_PARAM_CHECK(dev); x_err_t ret = EOK; if (dev->dev_done->close) { ret = dev->dev_done->close(dev); if(ret) { KPrintf("BusDevClose error ret %u\n", ret); return ERROR; } } return ret; } /** * @Description: support to write data to dev * @param dev - dev pointer * @param write_param - BusBlockWriteParam * @return successful:EOK,failed:NONE */ uint32 BusDevWriteData(struct HardwareDev *dev, struct BusBlockWriteParam *write_param) { NULL_PARAM_CHECK(dev); if (dev->dev_done->write) { return dev->dev_done->write(dev, write_param); } return EOK; } /** * @Description: support to read data from dev * @param dev - dev pointer * @param read_param - BusBlockReadParam * @return successful:EOK,failed:NONE */ uint32 BusDevReadData(struct HardwareDev *dev, struct BusBlockReadParam *read_param) { NULL_PARAM_CHECK(dev); if (dev->dev_done->read) { return dev->dev_done->read(dev, read_param); } return EOK; } /** * @Description: support to configure drv, include OPE_CFG and OPE_INT * @param drv - drv pointer * @param configure_info - BusConfigureInfo * @return successful:EOK,failed:NONE */ uint32 BusDrvConfigure(struct Driver *drv, struct BusConfigureInfo *configure_info) { NULL_PARAM_CHECK(drv); NULL_PARAM_CHECK(configure_info); x_err_t ret = EOK; if (drv->configure) { ret = drv->configure(drv, configure_info); if(ret) { KPrintf("BusDrvCfg error, ret %u\n", ret); return ERROR; } } return ret; }