diff --git a/sample/config/device_info/device_info.hcs b/sample/config/device_info/device_info.hcs new file mode 100755 index 00000000..091cf61d --- /dev/null +++ b/sample/config/device_info/device_info.hcs @@ -0,0 +1,38 @@ +root { + device_info { + platform :: host { + hostName = "platform_host"; + priority = 50; + device_gpio :: device { + device1 :: deviceNode { + policy = 2; + priority = 10; + permission = 0660; + moduleName = "GPIO_SAMPLE"; + serviceName = "GPIO_SAMPLE"; + deviceMatchAttr = "sample_gpio"; + } + } + device_uart :: device { + device5 :: deviceNode { + policy = 2; + priority = 10; + permission = 0660; + moduleName = "UART_SAMPLE"; + serviceName = "HDF_PLATFORM_UART_5"; + deviceMatchAttr = "sample_uart_5"; + } + } + device_spi :: device { + device3 :: deviceNode { + policy = 2; + priority = 60; + permission = 0660; + moduleName = "SPI_SAMPLE"; + serviceName = "HDF_PLATFORM_SPI_3"; + deviceMatchAttr = "sample_spi_3"; + } + } + } + } +} diff --git a/sample/config/gpio/gpio_config.hcs b/sample/config/gpio/gpio_config.hcs new file mode 100755 index 00000000..a7be8826 --- /dev/null +++ b/sample/config/gpio/gpio_config.hcs @@ -0,0 +1,15 @@ +root { + platform { + gpio_config { + gpio_sample { + match_attr = "sample_gpio"; + groupNum = 12; + bitNum = 8; + regBase = 0x120d0000; + regStep = 0x1000; + irqStart = 48; + irqShare = 0; + } + } + } +} \ No newline at end of file diff --git a/sample/config/spi/spi_config.hcs b/sample/config/spi/spi_config.hcs new file mode 100755 index 00000000..29064ea0 --- /dev/null +++ b/sample/config/spi/spi_config.hcs @@ -0,0 +1,19 @@ +root { + platform { + spi_config { + spi_sample { + serviceName = "SPI_SAMPLE"; + match_attr = "sample_spi_3"; + transferMode = 0; + busNum = 0; + clkRate = 100000000; + bitsPerWord = 8; + mode = 19; + speed = 2000000; + fifoSize = 256; + numCs = 1; + regBase = 0x120c0000; + } + } + } +} \ No newline at end of file diff --git a/sample/config/uart/uart_config.hcs b/sample/config/uart/uart_config.hcs new file mode 100755 index 00000000..2ea8900b --- /dev/null +++ b/sample/config/uart/uart_config.hcs @@ -0,0 +1,15 @@ +root { + platform { + uart_sample { + num = 5; + base = 0x120a0000; // UART base register address + irqNum = 38; + baudrate = 115200; + uartClk = 24000000; // 24 M + wlen = 0x60; // 8 bit width + parity = 0; + stopBit = 0; + match_attr = "sample_uart_5"; + } + } +} diff --git a/sample/platform/gpio/BUILD.gn b/sample/platform/gpio/BUILD.gn new file mode 100755 index 00000000..7578ab23 --- /dev/null +++ b/sample/platform/gpio/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("hello_gpio_sample") { + features = [ "dispatch:hello_gpio_dispatch" ] +} diff --git a/sample/platform/gpio/Kconfig b/sample/platform/gpio/Kconfig new file mode 100755 index 00000000..dc445d84 --- /dev/null +++ b/sample/platform/gpio/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +config DRIVERS_HDF_PLATFORM_GPIO_SAMPLE + bool "Enable HDF platform gpio sample driver" + default n + depends on DRIVERS_HDF_PLATFORM + help + Answer Y to enable HDF platform gpio sample driver. diff --git a/sample/platform/gpio/dispatch/BUILD.gn b/sample/platform/gpio/dispatch/BUILD.gn new file mode 100755 index 00000000..06291325 --- /dev/null +++ b/sample/platform/gpio/dispatch/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_gpio_dispatch") { + sources = [ + "gpio_if.c", + "hello_gpio_dispatch.c", + ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + "//drivers/framework/support/platform/include/gpio", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/gpio/dispatch/gpio_if.c b/sample/platform/gpio/dispatch/gpio_if.c new file mode 100755 index 00000000..dadccd69 --- /dev/null +++ b/sample/platform/gpio/dispatch/gpio_if.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "gpio_if.h" +#include "hdf_log.h" +#include "hdf_io_service_if.h" + +#define HDF_LOG_TAG gpio_if + +static struct HdfIoService *GetIoService() +{ + static struct HdfIoService *ioService = NULL; + if (ioService != NULL) { + return ioService; + } + + ioService = HdfIoServiceBind(GPIO_SERVICE_NAME); + if (ioService == NULL) { + HDF_LOGE("Failed to get service %s", GPIO_SERVICE_NAME); + } + return ioService; +} + +static int32_t GpioOperate(enum GpioOps ops, uint16_t gpio, uint16_t val) +{ + int ret = HDF_FAILURE; + struct HdfIoService *service = GetIoService(); + if (service == NULL) { + return ret; + } + struct HdfSBuf *data = HdfSBufObtainDefaultSize(); + if (data == NULL) { + HDF_LOGE("Failed to obtain sBuf"); + return ret; + } + + if (!HdfSbufWriteUint16(data, gpio) || !HdfSbufWriteUint16(data, val)) { + HDF_LOGE("Failed to write sBuf"); + HdfSBufRecycle(data); + return HDF_FAILURE; + } + ret = service->dispatcher->Dispatch(&service->object, ops, data, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send service call, ret: %d", ret); + } + HdfSBufRecycle(data); + return ret; +} + +static int32_t GpioQuery(enum GpioOps ops, uint16_t gpio, uint16_t *val) +{ + int ret = HDF_FAILURE; + struct HdfIoService *service = GetIoService(); + if (service == NULL) { + return ret; + } + struct HdfSBuf *data = HdfSBufObtainDefaultSize(); + struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); + if (data == NULL || reply == NULL) { + HDF_LOGE("Failed to obtain sBuf"); + return ret; + } + + if (!HdfSbufWriteUint16(data, gpio)) { + HDF_LOGE("Failed to write data sBuf"); + goto __ERR__; + } + ret = service->dispatcher->Dispatch(&service->object, ops, data, reply); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send service call"); + goto __ERR__; + + } + if (!HdfSbufReadUint16(reply, val)) { + HDF_LOGE("Failed to read reply sBuf"); + goto __ERR__; + } + goto __ERR__; + + __ERR__: + HdfSBufRecycle(data); + HdfSBufRecycle(reply); + return ret; +} + +int32_t GpioOpen() +{ + struct HdfIoService *ioService = GetIoService(); + if (ioService == NULL) { + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t GpioSetDir(uint16_t gpio, uint16_t dir) +{ + return GpioOperate(GPIO_OPS_SET_DIR, gpio, dir); +} + +int32_t GpioGetDir(uint16_t gpio, uint16_t *dir) +{ + return GpioQuery(GPIO_OPS_GET_DIR, gpio, dir); +} + +int32_t GpioWrite(uint16_t gpio, uint16_t val) +{ + return GpioOperate(GPIO_OPS_WRITE, gpio, val); +} + +int32_t GpioRead(uint16_t gpio, uint16_t *val) +{ + return GpioQuery(GPIO_OPS_READ, gpio, val); +} + +int32_t GpioClose() +{ + struct HdfIoService *ioService = GetIoService(); + if (ioService == NULL) { + return HDF_FAILURE; + } + HdfIoServiceRecycle(ioService); + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/sample/platform/gpio/dispatch/gpio_if.h b/sample/platform/gpio/dispatch/gpio_if.h new file mode 100755 index 00000000..4efb7870 --- /dev/null +++ b/sample/platform/gpio/dispatch/gpio_if.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef GPIO_IF_H +#define GPIO_IF_H + +#include + +#define GPIO_SERVICE_NAME "GPIO_SAMPLE" + +enum GpioValue { + GPIO_VAL_LOW = 0, + GPIO_VAL_HIGH = 1, + GPIO_VAL_ERR, +}; + +enum GpioDirType { + GPIO_DIR_IN = 0, + GPIO_DIR_OUT = 1, + GPIO_DIR_ERR, +}; + +enum GpioOps { + GPIO_OPS_SET_DIR = 1, + GPIO_OPS_GET_DIR, + GPIO_OPS_WRITE, + GPIO_OPS_READ +}; + +int32_t GpioOpen(); +int32_t GpioClose(); +int32_t GpioSetDir(uint16_t gpio, uint16_t dir); +int32_t GpioGetDir(uint16_t gpio, uint16_t *dir); +int32_t GpioWrite(uint16_t gpio, uint16_t val); +int32_t GpioRead(uint16_t gpio, uint16_t *val); + +#endif // GPIO_IF_H \ No newline at end of file diff --git a/sample/platform/gpio/dispatch/hello_gpio_dispatch.c b/sample/platform/gpio/dispatch/hello_gpio_dispatch.c new file mode 100755 index 00000000..c242acd0 --- /dev/null +++ b/sample/platform/gpio/dispatch/hello_gpio_dispatch.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "gpio_if.h" +#include "hdf_log.h" +#include "hdf_base.h" + +#define HDF_LOG_TAG hello_gpio_dispatch +#define GPIO_PIN 11 + +int main() +{ + uint16_t dir; + uint16_t val; + if (GpioOpen() != HDF_SUCCESS) { + HDF_LOGE("%s: GpioOpen failed", __func__); + return HDF_FAILURE; + } + if (GpioSetDir(GPIO_PIN, GPIO_DIR_IN) != HDF_SUCCESS) { + HDF_LOGE("%s: GpioSetDir failed, gpio %u, dir %u", __func__, GPIO_PIN, GPIO_DIR_IN); + return HDF_FAILURE; + } + if (GpioWrite(GPIO_PIN, GPIO_VAL_HIGH) != HDF_SUCCESS) { + HDF_LOGE("%s: GpioWrite failed, gpio %u, val %u", __func__, GPIO_PIN, GPIO_VAL_HIGH); + return HDF_FAILURE; + } + if (GpioGetDir(GPIO_PIN, &dir) != HDF_SUCCESS) { + HDF_LOGE("%s: GpioGetDir failed, gpio %u", __func__, GPIO_PIN); + return HDF_FAILURE; + } + if (GpioRead(GPIO_PIN, &val) != HDF_SUCCESS) { + HDF_LOGE("%s: GpioRead failed, gpio %u", __func__, GPIO_PIN); + return HDF_FAILURE; + } + if (GpioClose() != HDF_SUCCESS) { + HDF_LOGE("%s: GpioClose failed", __func__); + return HDF_FAILURE; + } + HDF_LOGD("GPIO %u direction is set to %u, value is set to %u", GPIO_PIN, dir, val); + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/sample/platform/gpio/include/gpio_dispatch_sample.h b/sample/platform/gpio/include/gpio_dispatch_sample.h new file mode 100755 index 00000000..cd33dc12 --- /dev/null +++ b/sample/platform/gpio/include/gpio_dispatch_sample.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef GPIO_DISPATCH_SAMPLE_H +#define GPIO_DISPATCH_SAMPLE_H + +#include "gpio_pl061_sample.h" + +enum GpioOps { + GPIO_OPS_SET_DIR = 1, + GPIO_OPS_GET_DIR, + GPIO_OPS_WRITE, + GPIO_OPS_READ +}; + +int32_t SampleGpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply); + +#endif // GPIO_DISPATCH_SAMPLE_H diff --git a/sample/platform/gpio/include/gpio_pl061_sample.h b/sample/platform/gpio/include/gpio_pl061_sample.h new file mode 100755 index 00000000..b133a7bd --- /dev/null +++ b/sample/platform/gpio/include/gpio_pl061_sample.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef GPIO_PL061_SAMPLE_H +#define GPIO_PL061_SAMPLE_H + +#include "gpio_core.h" +#include "gpio_if.h" +#include "osal.h" + +#define GROUP_MAX 32 +#define BIT_MAX 16 + +#define GPIO_DATA(base, bit) ((base) + 0x000 + (1 << ((bit) + 2))) +#define GPIO_DIR(base) ((base) + 0x400) +#define GPIO_IS(base) ((base) + 0x404) +#define GPIO_IBE(base) ((base) + 0x408) +#define GPIO_IEV(base) ((base) + 0x40C) +#define GPIO_IE(base) ((base) + 0x410) +#define GPIO_RIS(base) ((base) + 0x414) +#define GPIO_MIS(base) ((base) + 0x418) +#define GPIO_IC(base) ((base) + 0x41C) + +struct GpioGroup { + volatile unsigned char *regBase; + unsigned int index; + OsalSpinlock lock; +}; + +struct Pl061GpioCntlr { + struct GpioCntlr cntlr; + volatile unsigned char *regBase; + uint32_t phyBase; + uint32_t regStep; + uint32_t irqStart; + uint16_t groupNum; + uint16_t bitNum; + uint8_t irqShare; + struct GpioGroup *groups; +}; + +static struct Pl061GpioCntlr g_samplePl061GpioCntlr = { + .groups = NULL, + .groupNum = GROUP_MAX, + .bitNum = BIT_MAX, +}; + +static inline struct Pl061GpioCntlr *ToPl061GpioCntlr(struct GpioCntlr *cntlr) +{ + return (struct Pl061GpioCntlr *)cntlr; +} + +static inline uint16_t Pl061ToGroupNum(uint16_t gpio) +{ + return (uint16_t)(gpio / g_samplePl061GpioCntlr.bitNum); +} + +static inline uint16_t Pl061ToBitNum(uint16_t gpio) +{ + return (uint16_t)(gpio % g_samplePl061GpioCntlr.bitNum); +} + +static inline uint16_t Pl061ToGpioNum(uint16_t group, uint16_t bit) +{ + return (uint16_t)(group * g_samplePl061GpioCntlr.bitNum + bit); +} + +int32_t Pl061GetGroupByGpioNum(struct GpioCntlr *cntlr, uint16_t gpio, + struct GpioGroup **group); +#endif // GPIO_PL061_SAMPLE_H diff --git a/sample/platform/gpio/src/BUILD.gn b/sample/platform/gpio/src/BUILD.gn new file mode 100755 index 00000000..847987af --- /dev/null +++ b/sample/platform/gpio/src/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//drivers/adapter/khdf/liteos/hdf.gni") + +module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO_SAMPLE) +module_name = "hdf_gpio_sample" +hdf_driver(module_name) { + FRAMEWORK_GPIO_ROOT = "//drivers/framework/sample/platform/gpio/src" + sources = [ + "$FRAMEWORK_GPIO_ROOT/gpio_dispatch_sample.c", + "$FRAMEWORK_GPIO_ROOT/gpio_pl061_sample.c", + "$FRAMEWORK_GPIO_ROOT/gpio_sample.c", + ] + + include_dirs = [ + "//drivers/framework/sample/platform/gpio/include/", + "//drivers/framework/support/platform/include/gpio", + ] +} diff --git a/sample/platform/gpio/src/gpio_dispatch_sample.c b/sample/platform/gpio/src/gpio_dispatch_sample.c new file mode 100755 index 00000000..b93746ff --- /dev/null +++ b/sample/platform/gpio/src/gpio_dispatch_sample.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "gpio_dispatch_sample.h" + +#define HDF_LOG_TAG gpio_dispatch_sample + +static int32_t SampleGpioSetDir(struct GpioCntlr *cntlr, struct HdfSBuf *data) +{ + uint16_t gpio; + uint16_t dir; + if (!HdfSbufReadUint16(data, &gpio) || !HdfSbufReadUint16(data, &dir)) { + HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cntlr->ops->setDir == NULL) { + HDF_LOGE("%s: cntlr->ops->setDir is NULL", __func__); + return HDF_DEV_ERR_OP; + } + return cntlr->ops->setDir(cntlr, gpio, dir); +} + +static int32_t SampleGpioGetDir(struct GpioCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + uint16_t gpio; + uint16_t dir; + if (!HdfSbufReadUint16(data, &gpio)) { + HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cntlr->ops->getDir == NULL) { + HDF_LOGE("%s: cntlr->ops->getDir is NULL", __func__); + return HDF_DEV_ERR_OP; + } + ret = cntlr->ops->getDir(cntlr, gpio, &dir); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: cntlr->ops->getDir failed, ret: %d", __func__, ret); + return ret; + } + if (!HdfSbufWriteUint16(reply, dir)) { + HDF_LOGE("%s: HdfSbufWriteUint16 failed", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, struct HdfSBuf *data) +{ + uint16_t gpio; + uint16_t val; + if (!HdfSbufReadUint16(data, &gpio) || !HdfSbufReadUint16(data, &val)) { + HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cntlr->ops->write == NULL) { + HDF_LOGE("%s: cntlr->ops->read is NULL", __func__); + return HDF_DEV_ERR_OP; + } + return cntlr->ops->write(cntlr, gpio, val); +} + +static int32_t SampleGpioRead(struct GpioCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + uint16_t gpio; + uint16_t val; + if (!HdfSbufReadUint16(data, &gpio)) { + HDF_LOGE("%s: HdfSbufReadUint16 failed", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (cntlr->ops->read == NULL) { + HDF_LOGE("%s: cntlr->ops->read is NULL", __func__); + return HDF_DEV_ERR_OP; + } + ret = cntlr->ops->read(cntlr, gpio, &val); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: cntlr->ops->read failed, ret: %d", __func__, ret); + return ret; + } + if (!HdfSbufWriteUint16(reply, val)) { + HDF_LOGE("%s: HdfSbufWriteUint16 failed", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t SampleGpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + if (client == NULL || client->device == NULL) { + HDF_LOGE("%s: client or client->device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + + struct GpioCntlr *cntlr = (struct GpioCntlr *)client->device->service; + if (cntlr == NULL || cntlr->ops == NULL) { + HDF_LOGE("%s: cntlr or cntlr->ops is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + + switch (cmdId) { + case GPIO_OPS_SET_DIR: + return SampleGpioSetDir(cntlr, data); + case GPIO_OPS_GET_DIR: + return SampleGpioGetDir(cntlr, data, reply); + case GPIO_OPS_WRITE: + return SampleGpioWrite(cntlr, data); + case GPIO_OPS_READ: + return SampleGpioRead(cntlr, data, reply); + default: + HDF_LOGE("%s: invalid cmdId %d", __func__, cmdId); + return HDF_FAILURE; + } +} \ No newline at end of file diff --git a/sample/platform/gpio/src/gpio_pl061_sample.c b/sample/platform/gpio/src/gpio_pl061_sample.c new file mode 100755 index 00000000..fb8252b7 --- /dev/null +++ b/sample/platform/gpio/src/gpio_pl061_sample.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "gpio_pl061_sample.h" +#include "osal_irq.h" + +#define HDF_LOG_TAG gpio_pl061_sample + +int32_t Pl061GetGroupByGpioNum(struct GpioCntlr *cntlr, uint16_t gpio, struct GpioGroup **group) +{ + struct Pl061GpioCntlr *pl061 = NULL; + uint16_t groupIndex = Pl061ToGroupNum(gpio); + + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is NULL", __func__); + return HDF_ERR_INVALID_OBJECT; + } + pl061 = ToPl061GpioCntlr(cntlr); + if (groupIndex >= pl061->groupNum) { + HDF_LOGE("%s: err group index:%u", __func__, groupIndex); + return HDF_ERR_INVALID_PARAM; + } + *group = &pl061->groups[groupIndex]; + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/sample/platform/gpio/src/gpio_sample.c b/sample/platform/gpio/src/gpio_sample.c new file mode 100755 index 00000000..344929f2 --- /dev/null +++ b/sample/platform/gpio/src/gpio_sample.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "gpio_dispatch_sample.h" +#include "gpio_pl061_sample.h" +#include "device_resource_if.h" +#include "hdf_device_desc.h" +#include "gpio_if.h" +#include "osal.h" +#include "osal_io.h" +#include "gpio_core.h" + +#define HDF_LOG_TAG gpio_sample + +/* HdfDriverEntry hook function prototypes */ +static int32_t SampleGpioDriverBind(struct HdfDeviceObject *device); +static int32_t SampleGpioDriverInit(struct HdfDeviceObject *device); +static void SampleGpioDriverRelease(struct HdfDeviceObject *device); + +/* HdfDriverEntry definition */ +struct HdfDriverEntry g_sampleGpioDriverEntry = { + .moduleVersion = 1, + .moduleName = "GPIO_SAMPLE", + .Bind = SampleGpioDriverBind, + .Init = SampleGpioDriverInit, + .Release = SampleGpioDriverRelease, +}; + +/* Init HdfDriverEntry */ +HDF_INIT(g_sampleGpioDriverEntry); + +/* GPIO function prototypes */ +static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val); +static int32_t SampleGpioRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val); +static int32_t SampleGpioSetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir); +static int32_t SampleGpioGetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir); + +/* GpioMethod definition */ +struct GpioMethod g_sampleGpioMethod = { + .request = NULL, + .release = NULL, + .write = SampleGpioWrite, + .read = SampleGpioRead, + .setDir = SampleGpioSetDirection, + .getDir = SampleGpioGetDirection, + .toIrq = NULL, + .setIrq = NULL, + .unsetIrq = NULL, + .enableIrq = NULL, + .disableIrq = NULL, +}; + +/* Private function prototypes */ +/* Read GPIO device resource */ +static int32_t GetGpioDeviceResource(struct Pl061GpioCntlr *cntlr, const struct DeviceResourceNode *node); +/* Init GPIO controller memory */ +static int32_t InitGpioCntlrMem(struct Pl061GpioCntlr *cntlr); +/* Release GPIO controller memory */ +static void ReleaseGpioCntlrMem(struct Pl061GpioCntlr *cntlr); + +/* HdfDriverEntry hook function implementations */ +static int32_t SampleGpioDriverBind(struct HdfDeviceObject *device) +{ + HDF_LOGD("%s: Enter", __func__); + struct Pl061GpioCntlr *pl061Cntlr = &g_samplePl061GpioCntlr; + pl061Cntlr->cntlr.device = device; + device->service = &(pl061Cntlr->cntlr.service); + pl061Cntlr->cntlr.device->service->Dispatch = SampleGpioDispatch; + return HDF_SUCCESS; +} + +static int32_t SampleGpioDriverInit(struct HdfDeviceObject *device) +{ + int32_t ret; + struct Pl061GpioCntlr *pl061Cntlr = &g_samplePl061GpioCntlr; + + HDF_LOGD("%s: Enter", __func__); + if (device == NULL || device->property == NULL) { + HDF_LOGE("%s: device or property NULL!", __func__); + return HDF_ERR_INVALID_OBJECT; + } + + ret = GetGpioDeviceResource(pl061Cntlr, device->property); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: get gpio device resource fail:%d", __func__, ret); + return ret; + } + + if (pl061Cntlr->groupNum > GROUP_MAX || pl061Cntlr->groupNum <= 0 || pl061Cntlr->bitNum > BIT_MAX || + pl061Cntlr->bitNum <= 0) { + HDF_LOGE("%s: invalid groupNum:%u or bitNum:%u", __func__, pl061Cntlr->groupNum, + pl061Cntlr->bitNum); + return HDF_ERR_INVALID_PARAM; + } + + pl061Cntlr->regBase = OsalIoRemap(pl061Cntlr->phyBase, pl061Cntlr->groupNum * pl061Cntlr->regStep); + if (pl061Cntlr->regBase == NULL) { + HDF_LOGE("%s: err remap phy:0x%x", __func__, pl061Cntlr->phyBase); + return HDF_ERR_IO; + } + + ret = InitGpioCntlrMem(pl061Cntlr); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: err init cntlr mem:%d", __func__, ret); + OsalIoUnmap((void *)pl061Cntlr->regBase); + pl061Cntlr->regBase = NULL; + return ret; + } + pl061Cntlr->cntlr.count = pl061Cntlr->groupNum * pl061Cntlr->bitNum; + pl061Cntlr->cntlr.priv = (void *)device->property; + pl061Cntlr->cntlr.ops = &g_sampleGpioMethod; + ret = GpioCntlrAdd(&pl061Cntlr->cntlr); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: err add controller: %d", __func__, ret); + return ret; + } + HDF_LOGI("%s: dev service:%s init success!", __func__, HdfDeviceGetServiceName(device)); + return ret; +} + +static void SampleGpioDriverRelease(struct HdfDeviceObject *device) +{ + struct GpioCntlr *gpioCntlr = NULL; + struct Pl061GpioCntlr *pl061GpioCntlr = NULL; + + HDF_LOGD("%s: Enter", __func__); + if (device == NULL) { + HDF_LOGE("%s: device is null!", __func__); + return; + } + + gpioCntlr = GpioCntlrFromDevice(device); + if (gpioCntlr == NULL) { + HDF_LOGE("%s: no service bound!", __func__); + return; + } + GpioCntlrRemove(gpioCntlr); + + pl061GpioCntlr = (struct Pl061GpioCntlr *)gpioCntlr; + ReleaseGpioCntlrMem(pl061GpioCntlr); + OsalIoUnmap((void *)pl061GpioCntlr->regBase); + pl061GpioCntlr->regBase = NULL; +} + +/* Private function implementations */ +static int32_t GetGpioDeviceResource(struct Pl061GpioCntlr *cntlr, const struct DeviceResourceNode *node) +{ + int32_t ret; + struct DeviceResourceIface *dri = NULL; + + dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + if (dri == NULL || dri->GetUint8 == NULL || dri->GetUint16 == NULL || dri->GetUint32 == NULL) { + HDF_LOGE("%s: invalid dri ops fail!", __func__); + return HDF_FAILURE; + } + + ret = dri->GetUint32(node, "regBase", &cntlr->phyBase, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read regBase fail!", __func__); + return ret; + } + + ret = dri->GetUint32(node, "regStep", &cntlr->regStep, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read regStep fail!", __func__); + return ret; + } + + ret = dri->GetUint16(node, "groupNum", &cntlr->groupNum, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read groupNum fail!", __func__); + return ret; + } + + ret = dri->GetUint16(node, "bitNum", &cntlr->bitNum, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read bitNum fail!", __func__); + return ret; + } + + ret = dri->GetUint32(node, "irqStart", &cntlr->irqStart, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read irqStart fail!", __func__); + return ret; + } + + ret = dri->GetUint8(node, "irqShare", &cntlr->irqShare, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: read irqShare fail!", __func__); + return ret; + } + + return HDF_SUCCESS; +} + +static int32_t InitGpioCntlrMem(struct Pl061GpioCntlr *cntlr) +{ + size_t groupMemSize; + struct GpioGroup *groups = NULL; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + groupMemSize = sizeof(struct GpioGroup) * cntlr->groupNum; + groups = (struct GpioGroup *)OsalMemCalloc(groupMemSize); + if (groups == NULL) { + return HDF_ERR_MALLOC_FAIL; + } + cntlr->groups = groups; + + for (uint16_t i = 0; i < cntlr->groupNum; i++) { + groups[i].index = i; + groups[i].regBase = cntlr->regBase + (i * cntlr->regStep); + if (OsalSpinInit(&groups[i].lock) != HDF_SUCCESS) { + for (; i > 0; i--) { + (void)OsalSpinDestroy(&groups[i - 1].lock); + } + OsalMemFree(groups); + return HDF_FAILURE; + } + } + return HDF_SUCCESS; +} + +static void ReleaseGpioCntlrMem(struct Pl061GpioCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->groups != NULL) { + for (uint16_t i = 0; i < cntlr->groupNum; i++) { + (void)OsalSpinDestroy(&cntlr->groups[i].lock); + } + OsalMemFree(cntlr->groups); + cntlr->groups = NULL; + } +} + +/* GPIO function implementations */ +static int32_t SampleGpioWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val) +{ + HDF_LOGD("%s: Enter", __func__); + + int32_t ret; + uint32_t irqSave; + unsigned int valCur; + unsigned int bitNum = Pl061ToBitNum(gpio); + volatile unsigned char *addr = NULL; + struct GpioGroup *group = NULL; + + ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group); + if (ret != HDF_SUCCESS) { + return ret; + } + + addr = GPIO_DATA(group->regBase, bitNum); + if (OsalSpinLockIrqSave(&group->lock, &irqSave) != HDF_SUCCESS) { + return HDF_ERR_DEVICE_BUSY; + } + valCur = OSAL_READL(addr); + if (val == GPIO_VAL_LOW) { + valCur &= ~(1 << bitNum); + } else { + valCur |= (1 << bitNum); + } + OSAL_WRITEL(valCur, addr); + (void)OsalSpinUnlockIrqRestore(&group->lock, &irqSave); + HDF_LOGD("%s: gpio:%u, val:%u", __func__, gpio, val); + return HDF_SUCCESS; +} + +static int32_t SampleGpioRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val) +{ + HDF_LOGD("%s: Enter", __func__); + + int32_t ret; + unsigned int valCur; + volatile unsigned char *addr = NULL; + unsigned int bitNum = Pl061ToBitNum(gpio); + struct GpioGroup *group = NULL; + + ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group); + if (ret != HDF_SUCCESS) { + return ret; + } + + addr = GPIO_DATA(group->regBase, bitNum); + valCur = OSAL_READL(addr); + if (valCur & (1 << bitNum)) { + *val = GPIO_VAL_HIGH; + } else { + *val = GPIO_VAL_LOW; + } + HDF_LOGD("%s: gpio:%u, val:%u", __func__, gpio, *val); + return HDF_SUCCESS; +} + +static int32_t SampleGpioSetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir) +{ + HDF_LOGD("%s: Enter", __func__); + + int32_t ret; + uint32_t irqSave; + unsigned int val; + volatile unsigned char *addr = NULL; + unsigned int bitNum = Pl061ToBitNum(gpio); + struct GpioGroup *group = NULL; + + HDF_LOGD("%s: gpio:%u, dir:%d", __func__, gpio, dir); + ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group); + if (ret != HDF_SUCCESS) { + return ret; + } + + addr = GPIO_DIR(group->regBase); + if (OsalSpinLockIrqSave(&group->lock, &irqSave) != HDF_SUCCESS) { + return HDF_ERR_DEVICE_BUSY; + } + val = OSAL_READL(addr); + if (dir == GPIO_DIR_IN) { + val &= ~(1 << bitNum); + } else if (dir == GPIO_DIR_OUT) { + val |= 1 << bitNum; + } + OSAL_WRITEL(val, addr); + (void)OsalSpinUnlockIrqRestore(&group->lock, &irqSave); + return HDF_SUCCESS; +} +static int32_t SampleGpioGetDirection(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir) +{ + HDF_LOGD("%s: Enter", __func__); + + int32_t ret; + unsigned int val; + volatile unsigned char *addr = NULL; + unsigned int bitNum = Pl061ToBitNum(gpio); + struct GpioGroup *group = NULL; + + HDF_LOGD("%s: gpio:%u, dir:%p", __func__, gpio, dir); + ret = Pl061GetGroupByGpioNum(cntlr, gpio, &group); + if (ret != HDF_SUCCESS) { + return ret; + } + + addr = GPIO_DIR(group->regBase); + val = OSAL_READL(addr); + if (val & (1 << bitNum)) { + *dir = GPIO_DIR_OUT; + } else { + *dir = GPIO_DIR_IN; + } + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/sample/platform/spi/BUILD.gn b/sample/platform/spi/BUILD.gn new file mode 100755 index 00000000..8781560b --- /dev/null +++ b/sample/platform/spi/BUILD.gn @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("hello_spi_sample") { + features = [ "dispatch:hello_spi_dispatch" ] +} diff --git a/sample/platform/spi/Kconfig b/sample/platform/spi/Kconfig new file mode 100755 index 00000000..5141be9d --- /dev/null +++ b/sample/platform/spi/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +config DRIVERS_HDF_PLATFORM_SPI_SAMPLE + bool "Enable HDF platform spi sample driver" + default n + depends on DRIVERS_HDF_PLATFORM + help + Answer Y to enable HDF platform spi sample driver. diff --git a/sample/platform/spi/dispatch/BUILD.gn b/sample/platform/spi/dispatch/BUILD.gn new file mode 100755 index 00000000..cb5a2aeb --- /dev/null +++ b/sample/platform/spi/dispatch/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_spi_dispatch") { + sources = [ + "hello_spi_dispatch.c", + "spi_if.c", + ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/platform", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/spi/dispatch/hello_spi_dispatch.c b/sample/platform/spi/dispatch/hello_spi_dispatch.c new file mode 100755 index 00000000..30492d67 --- /dev/null +++ b/sample/platform/spi/dispatch/hello_spi_dispatch.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "spi_if.h" +#include "hdf_log.h" + +#define HDF_LOG_TAG hello_spi_dispatch + +int main() +{ + int32_t ret; + struct SpiDevInfo spiDevInfo; /* SPI device descriptor */ + struct DevHandle *spiHandle = NULL; /* SPI device handle */ + spiDevInfo.busNum = 3; /* SPI device bus number */ + spiDevInfo.csNum = 0; /* SPI device CS number */ + spiHandle = SpiOpen(&spiDevInfo); + if (spiHandle == NULL) { + HDF_LOGE("SpiOpen failed"); + return HDF_FAILURE; + } + + uint8_t wbuff[1] = {0x12}; + uint8_t rbuff[1] = {0}; + struct SpiMsg msg; /* Custom message to be transferred */ + msg.wbuf = wbuff; /* Pointer to the data to write */ + msg.rbuf = rbuff; /* Pointer to the data to read */ + msg.len = 1; /* The length of the data to be read or written is 1 bits. */ + msg.csChange = 1; /* Disable the CS before the next transfer. */ + msg.delayUs = 0; /* No delay before the next transfer */ + msg.speed = 115200; /* Speed of this transfer */ + ret = SpiTransfer(spiHandle, &msg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("SpiTransfer failed, ret %d", ret); + return ret; + } + SpiClose(spiHandle); + return ret; +} \ No newline at end of file diff --git a/sample/platform/spi/dispatch/spi_if.c b/sample/platform/spi/dispatch/spi_if.c new file mode 100755 index 00000000..be095836 --- /dev/null +++ b/sample/platform/spi/dispatch/spi_if.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "spi_if.h" +#include "osal_mem.h" +#include "hdf_io_service_if.h" +#include "hdf_log.h" +#include "securec.h" + +#define HDF_LOG_TAG spi_if + +DevHandle SpiOpen(const struct SpiDevInfo *info) +{ + int32_t ret; + void *devHandle = NULL; + uint32_t port; + char *serviceName = NULL; + + if (info == NULL) { + HDF_LOGW("info is NULL"); + return NULL; + } + port = info->busNum; + + serviceName = (char *)OsalMemCalloc(MAX_DEV_NAME_SIZE + 1); + if (serviceName == NULL) { + HDF_LOGE("Failed to OsalMemCalloc serviceName"); + return NULL; + } + ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, SPI_DEV_SERVICE_NAME_PREFIX, port); + if (ret < 0) { + HDF_LOGE("Failed to snprintf_s"); + OsalMemFree(serviceName); + return NULL; + } + devHandle = (void *)HdfIoServiceBind(serviceName); + OsalMemFree(serviceName); + return devHandle; +} + +void SpiClose(DevHandle handle) +{ + if (handle == NULL) { + HDF_LOGW("handle is NULL"); + return; + } + struct HdfIoService *service = (struct HdfIoService *)handle; + HdfIoServiceRecycle(service); + OsalMemFree(handle); +} + +int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs) +{ + int32_t ret; + if (handle == NULL || msgs == NULL) { + HDF_LOGW("handle or msgs is NULL"); + return HDF_ERR_INVALID_PARAM; + } + struct HdfIoService *service = (struct HdfIoService *)handle; + if (service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("service->dispatcher or service->dispatcher->Dispatch is NULL"); + return HDF_FAILURE; + } + + struct HdfSBuf *sBuf = HdfSBufObtainDefaultSize(); + if (sBuf == NULL) { + HDF_LOGE("Failed to obtain sBuf"); + return HDF_FAILURE; + } + + if (!HdfSbufWriteBuffer(sBuf, msgs, sizeof(struct SpiMsg))) { + HDF_LOGE("Failed to write sbuf"); + HdfSBufRecycle(sBuf); + return HDF_FAILURE; + } + ret = service->dispatcher->Dispatch(&service->object, SPI_TRANSFER, sBuf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send service call"); + } + HdfSBufRecycle(sBuf); + return ret; +} diff --git a/sample/platform/spi/dispatch/spi_if.h b/sample/platform/spi/dispatch/spi_if.h new file mode 100755 index 00000000..544c5174 --- /dev/null +++ b/sample/platform/spi/dispatch/spi_if.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef SPI_IF_H +#define SPI_IF_H + +#include "hdf_platform.h" + +#define SPI_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_SPI_%u" +#define MAX_DEV_NAME_SIZE 32 + +struct SpiDevInfo { + uint32_t busNum; + uint32_t csNum; +}; + +struct SpiMsg { + uint8_t *wbuf; + uint8_t *rbuf; + uint32_t len; + uint32_t speed; + uint16_t delayUs; + uint8_t csChange; +}; + +enum { + SPI_TRANSFER = 1 +}; + +DevHandle SpiOpen(const struct SpiDevInfo *info); +void SpiClose(DevHandle handle); +int32_t SpiTransfer(DevHandle handle, struct SpiMsg *msgs); + +#endif // SPI_IF_H diff --git a/sample/platform/spi/include/spi_dispatch_sample.h b/sample/platform/spi/include/spi_dispatch_sample.h new file mode 100755 index 00000000..e1de7454 --- /dev/null +++ b/sample/platform/spi/include/spi_dispatch_sample.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef SPI_DISPATCH_SAMPLE_H +#define SPI_DISPATCH_SAMPLE_H + +#include "spi_pl022_sample.h" +#include "spi_core.h" + +enum { + SPI_TRANSFER = 1 +}; + +int32_t SampleSpiDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply); + +#endif // SPI_DISPATCH_SAMPLE_H diff --git a/sample/platform/spi/include/spi_pl022_sample.h b/sample/platform/spi/include/spi_pl022_sample.h new file mode 100755 index 00000000..95e12a83 --- /dev/null +++ b/sample/platform/spi/include/spi_pl022_sample.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef SPI_PL022_SAMPLE_H +#define SPI_PL022_SAMPLE_H + +#include "spi_if.h" +#include "osal.h" + +/* ********** spi reg offset define start *************** */ +#define REG_SPI_PL022_CR0 0x00 +#define SPI_PL022_CR0_SCR_SHIFT 8 +#define SPI_PL022_CR0_SPH_SHIFT 7 +#define SPI_PL022_CR0_SPO_SHIFT 6 +#define SPI_PL022_CR0_FRF_SHIFT 4 +#define SPI_PL022_CR0_DSS_SHIFT 0 +#define SPI_PL022_CR0_SCR (0xff << 8) /* clkout=clk/(cpsdvsr*(scr+1)) */ +#define SPI_PL022_CR0_SPH (0x1 << 7) /* spi phase */ +#define SPI_PL022_CR0_SPO (0x1 << 6) /* spi clk polarity */ +#define SPI_PL022_CR0_FRF (0x3 << 4) /* frame format set */ +#define SPI_PL022_CR0_DSS (0xf << 0) /* data bits width */ + +#define REG_SPI_PL022_CR1 0x04 +#define SPI_PL022_CR1_WAIT_EN_SHIFT 15 +#define SPI_PL022_CR1_WAIT_VAL_SHIFT 8 +#define SPI_PL022_CR1_ALT_SHIFT 6 +#define SPI_PL022_CR1_BIG_END_SHIFT 4 +#define SPI_PL022_CR1_MS_SHIFT 2 +#define SPI_PL022_CR1_SSE_SHIFT 1 +#define SPI_PL022_CR1_LBN_SHIFT 0 +#define SPI_PL022_CR1_WAIT_EN (0x1 << 15) +#define SPI_PL022_CR1_WAIT_VAL (0x7f << 8) + +/* alt mode:spi enable csn is select; spi disable csn is cancel */ +#define SPI_PL022_CR1_ALT (0x1 << 6) +#define SPI_PL022_CR1_BIG_END (0x1 << 4) /* big end or little */ +#define SPI_PL022_CR1_MS (0x1 << 2) /* cntlr-device mode */ +#define SPI_PL022_CR1_SSE (0x1 << 1) /* spi enable set */ +#define SPI_PL022_CR1_LBM (0x1 << 0) /* loopback mode */ + +#define REG_SPI_PL022_DR 0x08 + +#define REG_SPI_PL022_SR 0x0c +#define SPI_PL022_SR_BSY_SHIFT 4 +#define SPI_PL022_SR_RFF_SHIFT 3 +#define SPI_PL022_SR_RNE_SHIFT 2 +#define SPI_PL022_SR_TNF_SHIFT 1 +#define SPI_PL022_SR_TFE_SHIFT 0 +#define SPI_PL022_SR_BSY (0x1 << 4) /* spi busy flag */ +#define SPI_PL022_SR_RFF (0x1 << 3) /* Whether to send fifo is full */ +#define SPI_PL022_SR_RNE (0x1 << 2) /* Whether to send fifo is no empty */ +#define SPI_PL022_SR_TNF (0x1 << 1) /* Whether to send fifo is no full */ +#define SPI_PL022_SR_TFE (0x1 << 0) /* Whether to send fifo is empty */ + +#define REG_SPI_PL022_CPSR 0x10 +#define SPI_PL022_CPSR_CPSDVSR_SHIFT 0 +#define SPI_PL022_CPSR_CPSDVSR (0xff << 0) /* even 2~254 */ + +#define REG_SPI_PL022_IMSC 0x14 +#define REG_SPI_PL022_RIS 0x18 +#define REG_SPI_PL022_MIS 0x1c +#define REG_SPI_PL022_ICR 0x20 + +#define REG_SPI_CRG 0x120100e4 /* CRG_REG_BASE(0x12010000) + 0x0e4 */ +#define SPI_CRG_CLK_EN 0 +#define SPI_CRG_CLK_RST 0 + +#define REG_SPI_MISC_CTRL 0x12030024 /* MISC_REG_BASE(0x12030000) + 0x24 */ +#define SPI_MISC_CTRL_CS 0 +#define SPI_MISC_CTRL_CS_SHIFT 0 +/* ********** spi reg offset define end *************** */ + +#define MAX_WAIT 5000 +#define DEFAULT_SPEED 2000000 + +#define SCR_MAX 255 +#define SCR_MIN 0 +#define CPSDVSR_MAX 254 +#define CPSDVSR_MIN 2 +#define SPI_CS_ACTIVE 0 +#define SPI_CS_INACTIVE 1 +#define TWO_BYTES 2 +#define BITS_PER_WORD_MIN 4 +#define BITS_PER_WORD_DEFAULT 8 +#define BITS_PER_WORD_MAX 16 + +struct Pl022SpiCntlr { + struct SpiCntlr *cntlr; + struct DListHead deviceList; + volatile unsigned char *regBase; + uint32_t busNum; + uint32_t numCs; + uint32_t curCs; + uint32_t speed; + uint32_t fifoSize; + uint32_t clkRate; + uint32_t maxSpeedHz; + uint32_t minSpeedHz; + uint32_t regCrg; + uint32_t clkEnBit; + uint32_t clkRstBit; + uint32_t regMiscCtrl; + uint32_t miscCtrlCsShift; + uint32_t miscCtrlCs; + uint16_t mode; + uint8_t bitsPerWord; + uint8_t transferMode; +}; + +int ConfigPl022SpiCntlr(struct Pl022SpiCntlr *cntlr); +int32_t TransferOneMessage(struct Pl022SpiCntlr *cntlr, struct SpiMsg *msg); + +#endif // SPI_PL022_SAMPLE_H diff --git a/sample/platform/spi/include/spi_sample.h b/sample/platform/spi/include/spi_sample.h new file mode 100755 index 00000000..64b32bfc --- /dev/null +++ b/sample/platform/spi/include/spi_sample.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef SPI_SAMPLE_H +#define SPI_SAMPLE_H + +#include "spi_core.h" + +int32_t SampleSpiCntlrTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count); +int32_t SampleSpiCntlrSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg); +int32_t SampleSpiCntlrGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg); + +#endif // SPI_SAMPLE_H diff --git a/sample/platform/spi/src/BUILD.gn b/sample/platform/spi/src/BUILD.gn new file mode 100755 index 00000000..1aa16f22 --- /dev/null +++ b/sample/platform/spi/src/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//drivers/adapter/khdf/liteos/hdf.gni") + +module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_SPI_SAMPLE) +module_name = "hdf_spi_sample" +hdf_driver(module_name) { + FRAMEWORK_SPI_ROOT = "//drivers/framework/sample/platform/spi/src" + sources = [ + "$FRAMEWORK_SPI_ROOT/spi_dispatch_sample.c", + "$FRAMEWORK_SPI_ROOT/spi_pl022_sample.c", + "$FRAMEWORK_SPI_ROOT/spi_sample.c", + ] + + include_dirs = [ + "//drivers/framework/sample/platform/spi/include/", + "//drivers/framework/support/platform/include/spi", + ] +} diff --git a/sample/platform/spi/src/spi_dispatch_sample.c b/sample/platform/spi/src/spi_dispatch_sample.c new file mode 100755 index 00000000..99bf1d7d --- /dev/null +++ b/sample/platform/spi/src/spi_dispatch_sample.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "spi_dispatch_sample.h" +#include "spi_sample.h" +#include "hdf_log.h" +#include "hdf_sbuf.h" + +#define HDF_LOG_TAG spi_dispatch_sample + +static int32_t SampleSpiTransfer(struct SpiCntlr *cntlr, struct HdfSBuf *txBuf) +{ + HDF_LOGD("%s: Enter", __func__); + uint32_t readSize = sizeof(struct SpiMsg); + struct SpiMsg *msg = NULL; + + if (cntlr == NULL || cntlr->priv == NULL || txBuf == NULL) { + HDF_LOGE("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (!HdfSbufReadBuffer(txBuf, (const void **)&msg, &readSize)) { + HDF_LOGE("%s: Failed to read sbuf", __func__); + return HDF_DEV_ERR_NO_MEMORY; + } + + if (SampleSpiCntlrTransfer(cntlr, msg, msg->len) != HDF_SUCCESS) { + HDF_LOGE("%s: SampleSpiCntlrTransfer error", __func__); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +int32_t SampleSpiDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + if (client == NULL || client->device == NULL) { + HDF_LOGE("%s: client or client->device is NULL", __func__); + return HDF_FAILURE; + } + + struct SpiCntlr *cntlr = (struct SpiCntlr *)client->device->service; + if (cntlr == NULL || cntlr->method == NULL) { + HDF_LOGE("%s: cntlr or cntlr->method is NULL", __func__); + return HDF_FAILURE; + } + + switch (cmdId) { + case SPI_TRANSFER: + return SampleSpiTransfer(cntlr, data); + default: + HDF_LOGE("%s: invalid cmdId %d", __func__, cmdId); + return HDF_FAILURE; + } +} \ No newline at end of file diff --git a/sample/platform/spi/src/spi_pl022_sample.c b/sample/platform/spi/src/spi_pl022_sample.c new file mode 100755 index 00000000..58ae8d24 --- /dev/null +++ b/sample/platform/spi/src/spi_pl022_sample.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "spi_pl022_sample.h" +#include "osal_io.h" + +#define HDF_LOG_TAG spi_pl022_sample + +/* Private function prototypes */ +static int Pl022SampleSetCs(struct Pl022SpiCntlr *cntlr, uint32_t cs, uint32_t flag); +static int Pl022SampleFlushFifo(const struct Pl022SpiCntlr *cntlr); +static int Pl022SampleTxRx8(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg); +static int Pl022SampleTxRx16(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg); +static void Pl022SampleEnableCntlr(const struct Pl022SpiCntlr *cntlr); +static void Pl022SampleConfigCPSR(const struct Pl022SpiCntlr *cntlr, uint32_t cpsdvsr); +static void Pl022SampleConfigCR0(const struct Pl022SpiCntlr *cntlr, uint32_t scr); +static void Pl022SampleConfigCR1(const struct Pl022SpiCntlr *cntlr); +static int32_t Pl022SampleCfgCs(struct Pl022SpiCntlr *cntlr, uint32_t cs); +static void Pl022SampleDisableCntlr(const struct Pl022SpiCntlr *cntlr); +static int Pl022SampleCheckTimeout(const struct Pl022SpiCntlr *cntlr); + +int ConfigPl022SpiCntlr(struct Pl022SpiCntlr *cntlr) +{ + uint32_t tmp; + uint32_t scr; + uint32_t cpsdvsr; + + Pl022SampleEnableCntlr(cntlr); + /* Check if we can provide the requested rate */ + if (cntlr->speed > cntlr->maxSpeedHz) { + cntlr->speed = cntlr->maxSpeedHz; + } + /* Min possible */ + if ((cntlr->speed < cntlr->minSpeedHz) || (cntlr->speed == 0)) { + HDF_LOGE("%s: cntlr->speed is %u not support, max %u, min %u", __func__, + cntlr->speed, cntlr->maxSpeedHz, cntlr->minSpeedHz); + return HDF_FAILURE; + } + /* Check if we can provide the requested bits_per_word */ + if ((cntlr->bitsPerWord < BITS_PER_WORD_MIN) || (cntlr->bitsPerWord > BITS_PER_WORD_MAX)) { + HDF_LOGE("%s: cntlr->bitsPerWord is %u not support", __func__, cntlr->bitsPerWord); + return HDF_FAILURE; + } + /* compute spi speed, speed=clk/(cpsdvsr*(scr+1)) */ + tmp = (cntlr->clkRate) / (cntlr->speed); + if (tmp < CPSDVSR_MIN) { + cpsdvsr = CPSDVSR_MIN; + scr = 0; + } else if (tmp <= CPSDVSR_MAX) { + cpsdvsr = tmp & (~0x1); + scr = (tmp / cpsdvsr) - 1; + } else { + cpsdvsr = CPSDVSR_MAX; + scr = (tmp / cpsdvsr) - 1; + } + /* config SPICPSR register */ + Pl022SampleConfigCPSR(cntlr, cpsdvsr); + /* config SPICR0 register */ + Pl022SampleConfigCR0(cntlr, scr); + /* config SPICR1 register */ + Pl022SampleConfigCR1(cntlr); + return HDF_SUCCESS; +} + +int32_t TransferOneMessage(struct Pl022SpiCntlr *cntlr, struct SpiMsg *msg) +{ + int32_t ret; + + if (msg->speed != 0) { + cntlr->speed = msg->speed; + } + ret = ConfigPl022SpiCntlr(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + ret = Pl022SampleSetCs(cntlr, cntlr->curCs, SPI_CS_ACTIVE); + if (ret != HDF_SUCCESS) { + return ret; + } + ret = Pl022SampleFlushFifo(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + if (cntlr->bitsPerWord <= BITS_PER_WORD_DEFAULT) { + ret = Pl022SampleTxRx8(cntlr, msg); + } else { + ret = Pl022SampleTxRx16(cntlr, msg); + } + if (ret || msg->csChange) { + Pl022SampleSetCs(cntlr, cntlr->curCs, SPI_CS_INACTIVE); + } + return ret; +} + +/* Private function implementations */ +static int Pl022SampleSetCs(struct Pl022SpiCntlr *cntlr, uint32_t cs, uint32_t flag) +{ + if (Pl022SampleCfgCs(cntlr, cs) != HDF_SUCCESS) { + return HDF_FAILURE; + } + if (flag == SPI_CS_ACTIVE) { + Pl022SampleEnableCntlr(cntlr); + } else { + Pl022SampleDisableCntlr(cntlr); + } + return HDF_SUCCESS; +} + +static int Pl022SampleFlushFifo(const struct Pl022SpiCntlr *cntlr) +{ + uint32_t value; + uint32_t ret; + uint32_t tmp = 0; + + ret = Pl022SampleCheckTimeout(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + while (true) { + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR); + if (!(value & SPI_PL022_SR_RNE)) { + break; + } + if (tmp++ > cntlr->fifoSize) { + HDF_LOGE("%s: spi transfer check rx fifo wait timeout", __func__); + return HDF_ERR_TIMEOUT; + } + OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR); + } + return HDF_SUCCESS; +} + +static int Pl022SampleTxRx8(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg) +{ + uint32_t len = msg->len; + uint32_t tmpLen; + uint32_t count; + const uint8_t *tx = (const uint8_t *)(msg->wbuf); + uint8_t *rx = (uint8_t *)(msg->rbuf); + uint8_t value; + uint32_t ret; + + if (tx == NULL && rx == NULL) { + return HDF_ERR_INVALID_PARAM; + } + while (len > 0) { + if (len > cntlr->fifoSize) { + tmpLen = cntlr->fifoSize; + } else { + tmpLen = len; + } + len -= tmpLen; + /* write fifo */ + count = tmpLen; + value = 0; + while (count > 0) { + if (tx != NULL) { + value = *tx++; + } + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR); + count -= 1; + OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR); + } + ret = Pl022SampleCheckTimeout(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + /* read fifo */ + count = tmpLen; + while (count > 0) { + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR); + if (rx != NULL) { + *rx++ = value; + } + count -= 1; + OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR); + } + } + return HDF_SUCCESS; +} + +static int Pl022SampleTxRx16(const struct Pl022SpiCntlr *cntlr, const struct SpiMsg *msg) +{ + uint32_t len = msg->len; + uint32_t tmpLen; + uint32_t count; + const uint16_t *tx = (const uint16_t *)(msg->wbuf); + uint16_t *rx = (uint16_t *)(msg->rbuf); + uint16_t value; + uint32_t ret; + + if (tx == NULL && rx == NULL) { + return HDF_ERR_INVALID_PARAM; + } + while (len > 0) { + ret = cntlr->fifoSize * TWO_BYTES; + if (len > ret) { + tmpLen = ret; + } else { + tmpLen = len; + } + len -= tmpLen; + /* write fifo */ + count = tmpLen; + value = 0; + while (count >= TWO_BYTES) { + if (tx != NULL) { + value = *tx++; + } + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR); + count -= TWO_BYTES; + } + ret = Pl022SampleCheckTimeout(cntlr); + if (ret != 0) { + return ret; + } + /* read fifo */ + count = tmpLen; + while (count >= TWO_BYTES) { + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_DR); + if (rx != NULL) { + *rx++ = value; + } + count -= TWO_BYTES; + } + } + return 0; +} + +static void Pl022SampleEnableCntlr(const struct Pl022SpiCntlr *cntlr) +{ + uint32_t value; + + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); + value |= SPI_PL022_CR1_SSE; + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); +} + +static void Pl022SampleConfigCPSR(const struct Pl022SpiCntlr *cntlr, uint32_t cpsdvsr) +{ + uint32_t value; + + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CPSR); + value &= ~SPI_PL022_CPSR_CPSDVSR; + value |= cpsdvsr << SPI_PL022_CPSR_CPSDVSR_SHIFT; + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CPSR); +} + +static void Pl022SampleConfigCR0(const struct Pl022SpiCntlr *cntlr, uint32_t scr) +{ + uint32_t tmp; + uint32_t value; + + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR0); + value &= ~SPI_PL022_CR0_DSS; + value |= (cntlr->bitsPerWord - 1) << SPI_PL022_CR0_DSS_SHIFT; + value &= ~SPI_PL022_CR0_FRF; + value &= ~SPI_PL022_CR0_SPO; + tmp = (!!(cntlr->mode & SPI_CLK_POLARITY)) ? (1 << SPI_PL022_CR0_SPO_SHIFT) : 0; + value |= tmp; + value &= ~SPI_PL022_CR0_SPH; + tmp = (!!(cntlr->mode & SPI_CLK_PHASE)) ? (1 << SPI_PL022_CR0_SPH_SHIFT) : 0; + value |= tmp; + value &= ~SPI_PL022_CR0_SCR; + value |= (scr << SPI_PL022_CR0_SCR_SHIFT); + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR0); +} + +static void Pl022SampleConfigCR1(const struct Pl022SpiCntlr *cntlr) +{ + uint32_t tmp; + uint32_t value; + + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); + value &= ~SPI_PL022_CR1_LBM; + tmp = (!!(cntlr->mode & SPI_MODE_LOOP)) ? (1 << SPI_PL022_CR1_LBN_SHIFT) : 0; + value |= tmp; + value &= ~SPI_PL022_CR1_MS; + value &= ~SPI_PL022_CR1_BIG_END; + tmp = (!!(cntlr->mode & SPI_MODE_LSBFE)) ? (1 << SPI_PL022_CR1_BIG_END_SHIFT) : 0; + value |= tmp; + value &= ~SPI_PL022_CR1_ALT; + value |= 0x1 << SPI_PL022_CR1_ALT_SHIFT; + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); +} + +static int32_t Pl022SampleCfgCs(struct Pl022SpiCntlr *cntlr, uint32_t cs) +{ + uint32_t value; + uint32_t miscCtrlCs; + + if ((cs + 1) > cntlr->numCs) { + HDF_LOGE("%s: cs %u is big than cntlr csNum %u", __func__, cs, cntlr->numCs); + return HDF_FAILURE; + } + if (cntlr->numCs == 1) { + return HDF_SUCCESS; + } + miscCtrlCs = (UINTPTR)(cntlr->regBase) + REG_SPI_MISC_CTRL; + value = OSAL_READL(miscCtrlCs); + value &= ~miscCtrlCs; + value |= (cs << cntlr->miscCtrlCsShift); + OSAL_WRITEL(value, miscCtrlCs); + return HDF_SUCCESS; +} + +static void Pl022SampleDisableCntlr(const struct Pl022SpiCntlr *cntlr) +{ + uint32_t value; + + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); + value &= ~SPI_PL022_CR1_SSE; + OSAL_WRITEL(value, (UINTPTR)(cntlr->regBase) + REG_SPI_PL022_CR1); +} + +static int Pl022SampleCheckTimeout(const struct Pl022SpiCntlr *cntlr) +{ + uint32_t value; + uint32_t tmp = 0; + + while (true) { + value = OSAL_READL((UINTPTR)(cntlr->regBase) + REG_SPI_PL022_SR); + if ((value & SPI_PL022_SR_TFE) && (!(value & SPI_PL022_SR_BSY))) { + break; + } + if (tmp++ > MAX_WAIT) { + HDF_LOGE("%s: spi transfer wait timeout", __func__); + return HDF_ERR_TIMEOUT; + } + OsalUDelay(1); + } + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/sample/platform/spi/src/spi_sample.c b/sample/platform/spi/src/spi_sample.c new file mode 100755 index 00000000..52679236 --- /dev/null +++ b/sample/platform/spi/src/spi_sample.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "spi_sample.h" +#include "spi_pl022_sample.h" +#include "spi_dispatch_sample.h" +#include "device_resource_if.h" +#include "hdf_base.h" +#include "osal_mem.h" +#include "hdf_log.h" +#include "spi_core.h" +#include "los_vm_zone.h" + +#define HDF_LOG_TAG spi_sample + +/* HdfDriverEntry hook function prototypes */ +static int32_t SampleSpiDriverBind(struct HdfDeviceObject *device); +static int32_t SampleSpiDriverInit(struct HdfDeviceObject *device); +static void SampleSpiDriverRelease(struct HdfDeviceObject *device); + +/* SpiCntlrMethod definition */ +struct SpiCntlrMethod g_sampleSpiMethod = { + .Transfer = SampleSpiCntlrTransfer, + .SetCfg = SampleSpiCntlrSetCfg, + .GetCfg = SampleSpiCntlrGetCfg, +}; + +/* HdfDriverEntry definition */ +struct HdfDriverEntry g_sampleSpiDriverEntry = { + .moduleVersion = 1, + .moduleName = "SPI_SAMPLE", + .Bind = SampleSpiDriverBind, + .Init = SampleSpiDriverInit, + .Release = SampleSpiDriverRelease, +}; + +/* Init HdfDriverEntry */ +HDF_INIT(g_sampleSpiDriverEntry); + +/* Private function prototypes */ +static int InitSpiDevice(struct SpiCntlr *cntlr, const struct DeviceResourceNode *property); +static int ConfigSpiDevice(struct Pl022SpiCntlr *pl022Cntlr); +static int32_t InitSpiDeviceResource(struct Pl022SpiCntlr *pl022Cntlr, const struct DeviceResourceNode *node); +static int32_t CreateSpiDev(struct Pl022SpiCntlr *pl022Cntlr); +static void ReleaseSpiDev(struct Pl022SpiCntlr *pl022Cntlr); +static struct SpiDev *FindDeviceByCsNum(const struct Pl022SpiCntlr *pl022Cntlr, uint32_t cs); + +/* HdfDriverEntry hook function implementations */ +static int32_t SampleSpiDriverBind(struct HdfDeviceObject *device) +{ + HDF_LOGD("%s: Enter", __func__); + struct SpiCntlr *cntlr = NULL; + if (device == NULL) { + HDF_LOGE("%s: device is NULL", __func__); + return HDF_ERR_INVALID_OBJECT; + } + + cntlr = SpiCntlrCreate(device); + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is NULL", __func__); + return HDF_FAILURE; + } + + cntlr->service.Dispatch = SampleSpiDispatch; + return HDF_SUCCESS; +} + +static int32_t SampleSpiDriverInit(struct HdfDeviceObject *device) +{ + HDF_LOGD("%s: Enter", __func__); + int ret; + struct SpiCntlr *cntlr = NULL; + if (device == NULL || device->property == NULL) { + HDF_LOGE("%s: device or device->property is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + cntlr = SpiCntlrFromDevice(device); + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + ret = InitSpiDevice(cntlr, device->property); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: InitSpiDevice failed", __func__); + return ret; + } + ret = ConfigSpiDevice(cntlr->priv); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: ConfigSpiDevice failed", __func__); + return ret; + } + return ret; +} + +static void SampleSpiDriverRelease(struct HdfDeviceObject *device) +{ + HDF_LOGD("%s: Enter", __func__); + struct SpiCntlr *cntlr = NULL; + if (device == NULL) { + HDF_LOGE("%s: device is null", __func__); + return; + } + cntlr = SpiCntlrFromDevice(device); + if (cntlr == NULL) { + HDF_LOGE("%s: cntlr is null", __func__); + return; + } + if (cntlr->priv != NULL) { + ReleaseSpiDev((struct Pl022SpiCntlr *)cntlr->priv); + } + SpiCntlrDestroy(cntlr); +} + +/* SPI function implementations */ +int32_t SampleSpiCntlrTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count) +{ + HDF_LOGD("%s: Enter", __func__); + int ret; + struct Pl022SpiCntlr *pl022Cntlr = NULL; + struct SpiDev *spiDev = NULL; + + if (cntlr == NULL || cntlr->priv == NULL || msg == NULL || count == 0) { + HDF_LOGE("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv; + spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs); + if (spiDev == NULL) { + HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs); + return HDF_FAILURE; + } + pl022Cntlr->mode = spiDev->cfg.mode; + pl022Cntlr->transferMode = spiDev->cfg.transferMode; + pl022Cntlr->bitsPerWord = spiDev->cfg.bitsPerWord; + pl022Cntlr->maxSpeedHz = spiDev->cfg.maxSpeedHz; + pl022Cntlr->curCs = spiDev->csNum; + for (uint32_t i = 0; i < count; i++) { + ret = TransferOneMessage(pl022Cntlr, &(msg[i])); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: transfer error", __func__); + return ret; + } + } + return ret; +} + +int32_t SampleSpiCntlrSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg) +{ + HDF_LOGD("%s: Enter", __func__); + struct Pl022SpiCntlr *pl022Cntlr = NULL; + struct SpiDev *spiDev = NULL; + + if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) { + HDF_LOGE("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv; + spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs); + if (spiDev == NULL) { + HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs); + return HDF_FAILURE; + } + spiDev->cfg.mode = cfg->mode; + spiDev->cfg.transferMode = cfg->transferMode; + spiDev->cfg.bitsPerWord = cfg->bitsPerWord; + if ((cfg->bitsPerWord < BITS_PER_WORD_MIN) || (cfg->bitsPerWord > BITS_PER_WORD_MAX)) { + HDF_LOGE("%s: bitsPerWord %u not support, use default bitsPerWord %u", + __func__, cfg->bitsPerWord, BITS_PER_WORD_DEFAULT); + spiDev->cfg.bitsPerWord = BITS_PER_WORD_DEFAULT; + } + if (cfg->maxSpeedHz != 0) { + spiDev->cfg.maxSpeedHz = cfg->maxSpeedHz; + } + return HDF_SUCCESS; +} + +int32_t SampleSpiCntlrGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg) +{ + HDF_LOGD("%s: Enter", __func__); + struct Pl022SpiCntlr *pl022Cntlr = NULL; + struct SpiDev *spiDev = NULL; + + if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) { + HDF_LOGE("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + pl022Cntlr = (struct Pl022SpiCntlr *)cntlr->priv; + spiDev = FindDeviceByCsNum(pl022Cntlr, cntlr->curCs); + if (spiDev == NULL) { + HDF_LOGE("%s: spiDev is null, curCs %u", __func__, cntlr->curCs); + return HDF_FAILURE; + } + cfg->mode = spiDev->cfg.mode; + cfg->transferMode = spiDev->cfg.transferMode; + cfg->bitsPerWord = spiDev->cfg.bitsPerWord; + cfg->maxSpeedHz = spiDev->cfg.maxSpeedHz; + return HDF_SUCCESS; +} + +/* Private function implementations */ +static int InitSpiDevice(struct SpiCntlr *cntlr, const struct DeviceResourceNode *property) +{ + int ret; + struct Pl022SpiCntlr *pl022Cntlr = NULL; + + pl022Cntlr = (struct Pl022SpiCntlr *)OsalMemCalloc(sizeof(*pl022Cntlr)); + if (pl022Cntlr == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_FAILURE; + } + ret = InitSpiDeviceResource(pl022Cntlr, property); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: InitSpiDeviceResource error", __func__); + OsalMemFree(pl022Cntlr); + return HDF_FAILURE; + } + pl022Cntlr->maxSpeedHz = (pl022Cntlr->clkRate) / ((SCR_MIN + 1) * CPSDVSR_MIN); + pl022Cntlr->minSpeedHz = (pl022Cntlr->clkRate) / ((SCR_MAX + 1) * CPSDVSR_MAX); + DListHeadInit(&pl022Cntlr->deviceList); + pl022Cntlr->cntlr = cntlr; + cntlr->priv = pl022Cntlr; + cntlr->busNum = pl022Cntlr->busNum; + cntlr->method = &g_sampleSpiMethod; + ret = CreateSpiDev(pl022Cntlr); + if (ret != HDF_SUCCESS) { + ReleaseSpiDev(pl022Cntlr); + return ret; + } + return HDF_SUCCESS; +} + +static int ConfigSpiDevice(struct Pl022SpiCntlr *pl022Cntlr) +{ + int ret; + + ret = ConfigPl022SpiCntlr(pl022Cntlr); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: HiPl022Config error", __func__); + } + return ret; +} + +static int32_t InitSpiDeviceResource(struct Pl022SpiCntlr *pl022Cntlr, const struct DeviceResourceNode *node) +{ + uint32_t tmp; + struct DeviceResourceIface *resIf = NULL; + + resIf = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + if (resIf == NULL || resIf->GetUint8 == NULL || resIf->GetUint16 == NULL || resIf->GetUint32 == NULL) { + HDF_LOGE("%s: resource is invalid", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint32(node, "regBase", &tmp, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read regBase fail", __func__); + return HDF_FAILURE; + } + pl022Cntlr->regBase = (void *)(uintptr_t)(IO_DEVICE_ADDR(tmp)); + if (resIf->GetUint32(node, "busNum", &pl022Cntlr->busNum, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read busNum fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint32(node, "numCs", &pl022Cntlr->numCs, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read numCs fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint32(node, "speed", &pl022Cntlr->speed, DEFAULT_SPEED) != HDF_SUCCESS) { + HDF_LOGE("%s: read speed fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint32(node, "fifoSize", &pl022Cntlr->fifoSize, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read fifoSize fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint32(node, "clkRate", &pl022Cntlr->clkRate, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read clkRate fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint16(node, "mode", &pl022Cntlr->mode, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read mode fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint8(node, "bitsPerWord", &pl022Cntlr->bitsPerWord, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read bitsPerWord fail", __func__); + return HDF_FAILURE; + } + if (resIf->GetUint8(node, "transferMode", &pl022Cntlr->transferMode, 0) != HDF_SUCCESS) { + HDF_LOGE("%s: read comMode fail", __func__); + return HDF_FAILURE; + } + pl022Cntlr->regCrg = REG_SPI_CRG; + pl022Cntlr->clkEnBit = SPI_CRG_CLK_EN; + pl022Cntlr->clkRstBit = SPI_CRG_CLK_RST; + pl022Cntlr->regMiscCtrl = REG_SPI_MISC_CTRL; + pl022Cntlr->miscCtrlCs = SPI_MISC_CTRL_CS; + pl022Cntlr->miscCtrlCsShift = SPI_MISC_CTRL_CS_SHIFT; + return HDF_SUCCESS; +} + +static int32_t CreateSpiDev(struct Pl022SpiCntlr *pl022Cntlr) +{ + uint32_t i; + struct SpiDev *device = NULL; + + for (i = 0; i < pl022Cntlr->numCs; i++) { + device = (struct SpiDev *)OsalMemCalloc(sizeof(*device)); + if (device == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_FAILURE; + } + device->cntlr = pl022Cntlr->cntlr; + device->csNum = i; + device->cfg.bitsPerWord = pl022Cntlr->bitsPerWord; + device->cfg.transferMode = pl022Cntlr->transferMode; + device->cfg.maxSpeedHz = pl022Cntlr->maxSpeedHz; + device->cfg.mode = pl022Cntlr->mode; + DListHeadInit(&device->list); + DListInsertTail(&device->list, &pl022Cntlr->deviceList); + } + return HDF_SUCCESS; +} + +static void ReleaseSpiDev(struct Pl022SpiCntlr *pl022Cntlr) +{ + struct SpiDev *dev = NULL; + struct SpiDev *tmpDev = NULL; + + DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(pl022Cntlr->deviceList), struct SpiDev, list) { + if (dev != NULL) { + DListRemove(&(dev->list)); + OsalMemFree(dev); + } + } + OsalMemFree(pl022Cntlr); +} + +static struct SpiDev *FindDeviceByCsNum(const struct Pl022SpiCntlr *pl022Cntlr, uint32_t cs) +{ + struct SpiDev *dev = NULL; + struct SpiDev *tmpDev = NULL; + + if (pl022Cntlr == NULL || pl022Cntlr->numCs <= cs) { + return NULL; + } + DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(pl022Cntlr->deviceList), struct SpiDev, list) { + if (dev->csNum == cs) { + break; + } + } + return dev; +} \ No newline at end of file diff --git a/sample/platform/uart/BUILD.gn b/sample/platform/uart/BUILD.gn new file mode 100755 index 00000000..9404df09 --- /dev/null +++ b/sample/platform/uart/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("hello_uart_sample") { + features = [ + "dev:hello_uart", + "dispatch:hello_uart_dispatch", + ] +} diff --git a/sample/platform/uart/Kconfig b/sample/platform/uart/Kconfig new file mode 100755 index 00000000..2a317abf --- /dev/null +++ b/sample/platform/uart/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +config DRIVERS_HDF_PLATFORM_UART_SAMPLE + bool "Enable HDF platform uart sample driver" + default n + depends on DRIVERS_HDF_PLATFORM + help + Answer Y to enable HDF platform uart sample driver. diff --git a/sample/platform/uart/dev/BUILD.gn b/sample/platform/uart/dev/BUILD.gn new file mode 100755 index 00000000..25f7815c --- /dev/null +++ b/sample/platform/uart/dev/BUILD.gn @@ -0,0 +1,41 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_uart") { + sources = [ "hello_uart_dev.c" ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/uart/dev/hello_uart_dev.c b/sample/platform/uart/dev/hello_uart_dev.c new file mode 100755 index 00000000..ffacc5df --- /dev/null +++ b/sample/platform/uart/dev/hello_uart_dev.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 +#include +#include "hdf_log.h" + +#define HDF_LOG_TAG hello_uart +#define INFO_SIZE 16 + +int main(void) +{ + int ret; + int fd; + const char info[INFO_SIZE] = {" HELLO UART! "}; + + fd = open("/dev/uartdev-5", O_RDWR); + if (fd < 0) { + HDF_LOGE("uartdev-5 open failed %d", fd); + return -1; + } + ret = write(fd, info, INFO_SIZE); + if (ret != 0) { + HDF_LOGE("write uartdev-5 ret is %d", ret); + } + ret = close(fd); + if (ret != 0) { + HDF_LOGE("uartdev-5 close failed %d", fd); + return -1; + } + return ret; +} \ No newline at end of file diff --git a/sample/platform/uart/dispatch/BUILD.gn b/sample/platform/uart/dispatch/BUILD.gn new file mode 100755 index 00000000..6813ed10 --- /dev/null +++ b/sample/platform/uart/dispatch/BUILD.gn @@ -0,0 +1,44 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +HDF_FRAMEWORKS = "//drivers/framework" + +executable("hello_uart_dispatch") { + sources = [ + "hello_uart_dispatch.c", + "uart_if.c", + ] + + include_dirs = [ + "$HDF_FRAMEWORKS/ability/sbuf/include", + "$HDF_FRAMEWORKS/core/shared/include", + "$HDF_FRAMEWORKS/core/host/include", + "$HDF_FRAMEWORKS/core/master/include", + "$HDF_FRAMEWORKS/include/core", + "$HDF_FRAMEWORKS/include/utils", + "$HDF_FRAMEWORKS/utils/include", + "$HDF_FRAMEWORKS/include/osal", + "//drivers/adapter/uhdf/posix/include", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + + deps = [ + "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared", + "//drivers/adapter/uhdf/manager:hdf_core", + "//drivers/adapter/uhdf/posix:hdf_posix_osal", + ] + + public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + defines = [ "__USER__" ] + + cflags = [ + "-Wall", + "-Wextra", + "-Wno-format", + "-Wno-format-extra-args", + ] +} diff --git a/sample/platform/uart/dispatch/hello_uart_dispatch.c b/sample/platform/uart/dispatch/hello_uart_dispatch.c new file mode 100755 index 00000000..ea123de1 --- /dev/null +++ b/sample/platform/uart/dispatch/hello_uart_dispatch.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "hdf_log.h" +#include "osal_mem.h" +#include "uart_if.h" + +#define HDF_LOG_TAG hello_uart_dispatch +#define UART_PORT 5 + +int main() +{ + const char *info = " HELLO UART! "; + + struct DevHandle *handle = UartOpen(UART_PORT); + if (handle == NULL) { + HDF_LOGE("Failed to open uart %d", UART_PORT); + return HDF_FAILURE; + } + + int ret = UartWrite(handle, (uint8_t *)info, strlen(info)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send data to uart"); + } + + UartClose(handle); + return ret; +} \ No newline at end of file diff --git a/sample/platform/uart/dispatch/uart_if.c b/sample/platform/uart/dispatch/uart_if.c new file mode 100755 index 00000000..e3f6152c --- /dev/null +++ b/sample/platform/uart/dispatch/uart_if.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "uart_if.h" +#include "securec.h" +#include "hdf_log.h" +#include "osal_mem.h" +#include "hdf_io_service_if.h" + +#define HDF_LOG_TAG uart_if + +struct DevHandle *UartOpen(uint32_t port) +{ + int32_t ret; + struct DevHandle *handle = NULL; + char *serviceName = NULL; + + handle = (struct DevHandle *)OsalMemCalloc(sizeof(struct DevHandle)); + if (handle == NULL) { + HDF_LOGE("Failed to OsalMemCalloc handle"); + return NULL; + } + + serviceName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1)); + if (serviceName == NULL) { + HDF_LOGE("Failed to OsalMemCalloc serviceName"); + OsalMemFree(handle); + return NULL; + } + ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, UART_DEV_SERVICE_NAME_PREFIX, port); + if (ret < 0) { + HDF_LOGE("Failed to snprintf_s"); + OsalMemFree(handle); + OsalMemFree(serviceName); + return NULL; + } + + struct HdfIoService *service = HdfIoServiceBind(serviceName); + if (service == NULL) { + HDF_LOGE("Failed to get service %s", serviceName); + OsalMemFree(handle); + OsalMemFree(serviceName); + return NULL; + } + OsalMemFree(serviceName); + handle->object = service; + return handle; +} + +int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size) +{ + int ret; + struct HdfIoService *service = NULL; + + if (handle == NULL || handle->object == NULL) { + HDF_LOGE("handle or handle->object is NULL"); + return HDF_FAILURE; + } + + struct HdfSBuf *sBuf = HdfSBufObtainDefaultSize(); + if (sBuf == NULL) { + HDF_LOGE("Failed to obtain sBuf"); + return HDF_FAILURE; + } + + if (!HdfSbufWriteBuffer(sBuf, data, size)) { + HDF_LOGE("Failed to write sbuf"); + HdfSBufRecycle(sBuf); + return HDF_FAILURE; + } + + service = (struct HdfIoService *)handle->object; + ret = service->dispatcher->Dispatch(&service->object, UART_WRITE, sBuf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("Failed to send service call"); + } + HdfSBufRecycle(sBuf); + return ret; +} + +void UartClose(struct DevHandle *handle) +{ + struct HdfIoService *service = NULL; + + if (handle == NULL || handle->object == NULL) { + HDF_LOGE("handle or handle->object is NULL"); + return; + } + service = (struct HdfIoService *)handle->object; + HdfIoServiceRecycle(service); + OsalMemFree(handle); +} diff --git a/sample/platform/uart/dispatch/uart_if.h b/sample/platform/uart/dispatch/uart_if.h new file mode 100755 index 00000000..61ca0ad3 --- /dev/null +++ b/sample/platform/uart/dispatch/uart_if.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef UART_IF_H +#define UART_IF_H + +#include + +#define UART_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_UART_%d" +#define MAX_DEV_NAME_SIZE 32 + +enum { + UART_WRITE = 1 +}; + +struct DevHandle { + void *object; +}; + +struct DevHandle *UartOpen(uint32_t port); +int32_t UartWrite(struct DevHandle *handle, uint8_t *data, uint32_t size); +void UartClose(struct DevHandle *handle); + +#endif // UART_IF_H \ No newline at end of file diff --git a/sample/platform/uart/include/buf_fifo.h b/sample/platform/uart/include/buf_fifo.h new file mode 100755 index 00000000..ba9dab7d --- /dev/null +++ b/sample/platform/uart/include/buf_fifo.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef BUF_FIFO_H +#define BUF_FIFO_H + +#include +#include +#include + +struct BufferFifo { + volatile uint32_t readPosition; + volatile uint32_t writePosition; + uint16_t bufSizeMask; + uint8_t *buffer; +}; + +static inline uint16_t BufferFifoGetDataSize(struct BufferFifo *fifo) +{ + return (fifo->writePosition - fifo->readPosition); +} + +static inline bool IsPowerOfTwo(int num) +{ + return (num > 0) && (num & (num - 1)) == 0; +} + +bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *buf, uint16_t bufSize); + +#endif // BUF_FIFO_H + diff --git a/sample/platform/uart/include/uart_dev_sample.h b/sample/platform/uart/include/uart_dev_sample.h new file mode 100755 index 00000000..87150de3 --- /dev/null +++ b/sample/platform/uart/include/uart_dev_sample.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef UART_DEV_SAMPLE_H +#define UART_DEV_SAMPLE_H + +#include "sys/ioctl.h" +#include "uart_core.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define UART_IOC_MAGIC 'u' + +/* baudrate config */ +#define UART_CFG_BAUDRATE _IO(UART_IOC_MAGIC, 1) + +void AddUartDevice(struct UartHost *host); +void RemoveUartDevice(struct UartHost *host); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* UART_DEV_SAMPLE_H */ diff --git a/sample/platform/uart/include/uart_dispatch_sample.h b/sample/platform/uart/include/uart_dispatch_sample.h new file mode 100755 index 00000000..42ca3c5b --- /dev/null +++ b/sample/platform/uart/include/uart_dispatch_sample.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef UART_DISPATCH_SAMPLE_H +#define UART_DISPATCH_SAMPLE_H + +#include "uart_pl011_sample.h" + +enum { + UART_WRITE = 1 +}; + +int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply); + +#endif // UART_DISPATCH_SAMPLE_H diff --git a/sample/platform/uart/include/uart_pl011_sample.h b/sample/platform/uart/include/uart_pl011_sample.h new file mode 100755 index 00000000..a11448f6 --- /dev/null +++ b/sample/platform/uart/include/uart_pl011_sample.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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. + */ + +#ifndef UART_PL011_SAMPLE_H +#define UART_PL011_SAMPLE_H + +#include +#include +#include "hdf_device_desc.h" +#include "buf_fifo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct UartRegisterMap { + volatile uint32_t dr; /* Offset: 0x000 TYPE: (RW) Data register */ + union { + volatile uint32_t rsr; /* Offset: 0x004 TYPE: (RO) Receive status register */ + volatile uint32_t ecr; /* Offset: 0x004 TYPE: (WO) Error clear register */ + }; + volatile uint32_t reserved0[4]; /* Offset: 0x008-0x014 Reserved */ + volatile uint32_t fr; /* Offset: 0x018 TYPE: (RO) Flag register */ + volatile uint32_t reserved1; /* Offset: 0x01C Reserved */ + volatile uint32_t ilpr; /* Offset: 0x020 TYPE: (RW) IrDA low-power counter register */ + volatile uint32_t ibrd; /* Offset: 0x024 TYPE: (RW) Integer baud rate register */ + volatile uint32_t fbrd; /* Offset: 0x028 TYPE: (RW) Fractional baud rate register */ + volatile uint32_t lcr; /* Offset: 0x02C TYPE: (RW) Line control register */ + volatile uint32_t cr; /* Offset: 0x030 TYPE: (RW) Control register */ + volatile uint32_t ifls; /* Offset: 0x034 TYPE: (RW) Interrupt FIFO level select register */ + volatile uint32_t imsc; /* Offset: 0x038 TYPE: (RW) Interrupt mask set/clear register */ + volatile uint32_t ris; /* Offset: 0x03C TYPE: (RO) Raw interrupt status register */ + volatile uint32_t mis; /* Offset: 0x040 TYPE: (RO) Masked interrupt status register */ + volatile uint32_t icr; /* Offset: 0x044 TYPE: (WO) Interrupt clear register */ + volatile uint32_t dmacr; /* Offset: 0x048 TYPE: (RW) DMA control register */ +}; + +struct UartResource { + uint32_t num; /* UART port num */ + uint32_t base; /* UART PL011 base address */ + uint32_t irqNum; /* UART PL011 IRQ num */ + uint32_t baudrate; /* Default baudrate */ + uint32_t wlen; /* Default word length */ + uint32_t parity; /* Default parity */ + uint32_t stopBit; /* Default stop bits */ + uint32_t uartClk; /* UART clock */ + unsigned long physBase; +}; + +enum UartDeviceState { + UART_DEVICE_UNINITIALIZED = 0x0u, + UART_DEVICE_INITIALIZED = 0x1u, +}; + +struct UartDevice { + struct IDeviceIoService ioService; + struct UartResource resource; + enum UartDeviceState state; /* UART State */ + uint32_t uartClk; /* UART clock */ + uint32_t baudrate; /* Baudrate */ + struct BufferFifo rxFifo; +}; + +/* Receive Status Register/Error Clear Register data */ +#define UART_PL011_RSR_FRAMING_ERROR_MASK (1 << 0x0u) /* Framing error bit mask */ +#define UART_PL011_RSR_PARITY_ERROR_MASK (1 << 0x1u) /* Parity error bit mask */ +#define UART_PL011_RSR_BREAK_ERROR_MASK (1 << 0x2u) /* Break error bit mask */ +#define UART_PL011_RSR_OVERRUN_ERROR_MASK (1 << 0x3u) /* Overrun error bit mask */ + +/* Receive Status Register Error Mask */ +#define UART_PL011_RSR_RX_ERROR_MASK ( \ + UART_PL011_RSR_FRAMING_ERROR_MASK \ + | UART_PL011_RSR_PARITY_ERROR_MASK \ + | UART_PL011_RSR_BREAK_ERROR_MASK \ + | UART_PL011_RSR_OVERRUN_ERROR_MASK) + +#define UART_PL011_FR_CTS_MASK (1 << 0x0u) /* Clear to send bit mask */ +#define UART_PL011_FR_DSR_MASK (1 << 0x1u) /* Data set ready bit mask */ +#define UART_PL011_FR_DCD_MASK (1 << 0x2u) /* Data carrier detect bit mask */ +#define UART_PL011_FR_BUSY_MASK (1 << 0x3u) /* UART busy bit mask */ +#define UART_PL011_FR_RX_FIFO_EMPTY_MASK (1 << 0x4u) /* Receive FIFO empty bit mask */ +#define UART_PL011_FR_TX_FIFO_FULL_MASK (1 << 0x5u) /* Transmit FIFO full bit mask */ +#define UART_PL011_FR_RX_FIFO_FULL_MASK (1 << 0x6u) /* Receive FIFO full bit mask */ +#define UART_PL011_FR_TX_FIFO_EMPTY_MASK (1 << 0x7u) /* Transmit FIFO empty. bit mask */ +#define UART_PL011_FR_RI_MASK (1 << 0x8u) /* Ring indicator bit mask */ + +/* PL011 Line Control Register Data bits */ +#define UART_PL011_LCR_H_BRK_MASK (1 << 0x0u) /* Send Break bit mask */ +#define UART_PL011_LCR_H_PEN_MASK (1 << 0x1u) /* Parity enable bit mask */ +#define UART_PL011_LCR_H_EPS_MASK (1 << 0x2u) /* Even parity select bit mask . */ +#define UART_PL011_LCR_H_FEN_MASK (1 << 0x4u) /* Enable FIFOs bit mask */ +#define UART_PL011_LCR_H_SPS_MASK (1 << 0x7u) /* Stick parity select bit mask */ + +#define UART_PL011_LCR_H_WLEN_BIT_OFFSET 0x5u /* Word length bit offset */ +#define UART_PL011_LCR_H_WLEN_MASK ( \ + 0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) + +#define UART_PL011_WLEN_5BITS (0x0u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_6BITS (0x1u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_7BITS (0x2u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) +#define UART_PL011_WLEN_8BITS (0x3u << UART_PL011_LCR_H_WLEN_BIT_OFFSET) + +#define UART_PL011_NONE_PARITY_CHECKED 0 + +#define UART_PL011_LCR_H_STP2_BIT_OFFSET 0x3u /* Two stop bits select */ + +#define UART_PL011_STOPBIT_1 (0x0u << UART_PL011_LCR_H_STP2_BIT_OFFSET) +#define UART_PL011_STOPBIT_2 (0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET) + +#define UART_PL011_LCR_H_PARITY_MASK ( \ + UART_PL011_LCR_H_PEN_MASK \ + | UART_PL011_LCR_H_EPS_MASK \ + | UART_PL011_LCR_H_SPS_MASK) + +#define UART_PL011_LCR_H_STOPBIT_MASK \ + (0x1u << UART_PL011_LCR_H_STP2_BIT_OFFSET) + +#define UART_PL011_DATA_FORMAT_MASK ( \ + UART_PL011_LCR_H_PARITY_MASK \ + | UART_PL011_LCR_H_STOPBIT_MASK \ + | UART_PL011_LCR_H_WLEN_MASK) + +/* Control Register */ +#define UART_PL011_CR_UARTEN_MASK (0x1u << 0x0u) /* Uart enable bit mask */ +#define UART_PL011_CR_SIREN_MASK (0x1u << 0x1u) /* Sir enable bit mask */ +#define UART_PL011_CR_SIRLP_MASK (0x1u << 0x2u) /* SIR low-power IrDA mode bit mask */ +#define UART_PL011_CR_LBE_MASK (0x1u << 0x7u) /* Loopback enable bit mask */ +#define UART_PL011_CR_TXE_MASK (0x1u << 0x8u) /* Transmit enable bit mask */ +#define UART_PL011_CR_RXE_MASK (0x1u << 0x9u) /* Receive enable bit mask */ +#define UART_PL011_CR_DTR_MASK (0x1u << 0xAu) /* Data transmit ready.bit mask */ +#define UART_PL011_CR_RTS_MASK (0x1u << 0xBu) /* Request to send bit mask */ +#define UART_PL011_CR_OUT1_MASK (0x1u << 0xCu) /* Out1 bit field mask */ +#define UART_PL011_CR_OUT2_MASK (0x1u << 0xDu) /* Out2 bit field mask */ +#define UART_PL011_CR_RTSE_MASK (0x1u << 0xEu) /* RTS hardware flow control enable bit mask */ +#define UART_PL011_CR_CTSE_MASK (0x1u << 0xFu) /* CTS hardware flow control enable bit mask */ + + +/* Interrupt FIFO Level Select Register Transmit bit offset */ +#define UART_PL011_IFLS_TX_BIT_OFFSET 0x0u +/* Interrupt FIFO Level Select Register Receive bit offset */ +#define UART_PL011_IFLS_RX_BIT_OFFSET 0x3u + +#define UART_PL011_RX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_RX_BIT_OFFSET) +#define UART_PL011_RX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_RX_BIT_OFFSET) + +#define UART_PL011_TX_FIFO_LVL_1_8 (0x0u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_1_4 (0x1u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_1_2 (0x2u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_3_4 (0x3u << UART_PL011_IFLS_TX_BIT_OFFSET) +#define UART_PL011_TX_FIFO_LVL_7_8 (0x4u << UART_PL011_IFLS_TX_BIT_OFFSET) + +/* Default register values of UART PL011 */ +#define UART_PL011_DEFAULT_DATA_REG_VALUE (0x0u) +#define UART_PL011_DEFAULT_ECR_VALUE (0xFFu) +#define UART_PL011_DEFAULT_ILPR_VALUE (0x0u) +#define UART_PL011_DEFAULT_IBRD_REG_VALUE (0x0u) +#define UART_PL011_DEFAULT_FBRD_REG_VALUE (0x0u) +/* Clear UARTLCR */ +#define UART_PL011_DEFAULT_LCR_H_VALUE (0x0u) +#define UART_PL011_DEFAULT_CTRL_REG_VALUE (0x0300u) + +#define UART_PL011_DEFAULT_IFLS_REG_VALUE ( \ + UART_PL011_RX_FIFO_LVL_1_2 \ + | UART_PL011_TX_FIFO_LVL_7_8) + +/* Clear interrupt mask */ +#define UART_PL011_DEFAULT_IMSC_REG_VALUE (0x0u) +/* Clear interrupt */ +#define UART_PL011_DEFAULT_ICR_VALUE (0x7FFu) +#define UART_PL011_DEFAULT_DMACR_VALUE (0x0u) + +#define FREQ_IRLPBAUD16_MIN (1420000u) /* 1.42 MHz */ +#define FREQ_IRLPBAUD16_MAX (2120000u) /* 2.12 MHz */ +#define SAMPLING_FACTOR (16u) +#define UART_PL011_FBRD_WIDTH (6u) + +/** + * \brief ARM UART PL011 error enumeration types + */ +typedef enum UartPl011Error { + UART_PL011_ERR_NONE = (0x0u), + UART_PL011_ERR_RX_FRAME = UART_PL011_RSR_FRAMING_ERROR_MASK, + UART_PL011_ERR_RX_PARITY = UART_PL011_RSR_PARITY_ERROR_MASK, + UART_PL011_ERR_RX_BREAK = UART_PL011_RSR_BREAK_ERROR_MASK, + UART_PL011_ERR_RX_OVERFLOW = UART_PL011_RSR_OVERRUN_ERROR_MASK, + UART_PL011_ERR_INVALID_ARG = (UART_PL011_RSR_RX_ERROR_MASK + 1), + UART_PL011_ERR_NOT_READY, + UART_PL011_ERR_INVALID_BAUD, + UART_PL011_ERR_NOT_INIT, +} UartPl011Error; + +static inline void UartPl011Enable(struct UartRegisterMap *regMap) +{ + regMap->cr |= UART_PL011_CR_UARTEN_MASK; +} + +static inline void UartPl011Disable(struct UartRegisterMap *regMap) +{ + regMap->cr &= ~UART_PL011_CR_UARTEN_MASK; +} + +static inline bool UartPl011IsEnabled(struct UartRegisterMap *regMap) +{ + return (bool)(regMap->cr & UART_PL011_CR_UARTEN_MASK); +} + +static inline bool UartPl011IsBusy(struct UartRegisterMap *regMap) +{ + return (bool)(regMap->fr & UART_PL011_FR_BUSY_MASK); +} + +void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits); + +static inline void UartPl011Write(struct UartRegisterMap *regMap, uint8_t byte) +{ + while (UartPl011IsBusy(regMap)); + regMap->dr = byte; +} + +UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate); + +void UartPl011SetDataFormat(struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits); + +void UartPl011ResetRegisters(struct UartRegisterMap *regMap); + +static inline void UartPl011EnableFifo(struct UartRegisterMap *regMap) +{ + UartPl011SetLcrBits(regMap, UART_PL011_LCR_H_FEN_MASK); +} + +#ifdef __cplusplus +} +#endif +#endif /* UART_PL011_SAMPLE_H */ + diff --git a/sample/platform/uart/src/BUILD.gn b/sample/platform/uart/src/BUILD.gn new file mode 100755 index 00000000..a979792d --- /dev/null +++ b/sample/platform/uart/src/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# +# HDF 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. + +import("//drivers/adapter/khdf/liteos/hdf.gni") + +module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_UART_SAMPLE) +module_name = "hdf_uart_sample" +hdf_driver(module_name) { + FRAMEWORK_UART_ROOT = "//drivers/framework/sample/platform/uart/src" + sources = [ + "$FRAMEWORK_UART_ROOT/buf_fifo.c", + "$FRAMEWORK_UART_ROOT/uart_dev_sample.c", + "$FRAMEWORK_UART_ROOT/uart_dispatch_sample.c", + "$FRAMEWORK_UART_ROOT/uart_pl011_sample.c", + "$FRAMEWORK_UART_ROOT/uart_sample.c", + ] + + include_dirs = [ "//drivers/framework/sample/platform/uart/include/" ] +} diff --git a/sample/platform/uart/src/buf_fifo.c b/sample/platform/uart/src/buf_fifo.c new file mode 100755 index 00000000..19da2dff --- /dev/null +++ b/sample/platform/uart/src/buf_fifo.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "buf_fifo.h" + +bool BufferFifoInit(struct BufferFifo *fifo, uint8_t *fifoBuffer, uint16_t fifoSize) +{ + if (fifoBuffer == NULL) { + return false; + } + if (!IsPowerOfTwo(fifoSize)) { + return false; + } + fifo->buffer = fifoBuffer; + fifo->bufSizeMask = fifoSize - 1; + fifo->readPosition = 0; + fifo->writePosition = 0; + return true; +} \ No newline at end of file diff --git a/sample/platform/uart/src/uart_dev_sample.c b/sample/platform/uart/src/uart_dev_sample.c new file mode 100755 index 00000000..b9b85a43 --- /dev/null +++ b/sample/platform/uart/src/uart_dev_sample.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "uart_dev_sample.h" +#include "fs/fs.h" +#include "securec.h" +#include "user_copy.h" +#include "hdf_log.h" +#include "osal_mem.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_dev_sample +#define HDF_UART_FS_MODE 0660 + +static int32_t UartSampleDevOpen(struct file *filep) +{ + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + HDF_LOGI("%s: open uart%d success", __func__, host->num); + return HDF_SUCCESS; +} +static int32_t UartSampleRelease(struct file *filep) +{ + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + HDF_LOGI("%s: close uart%d success", __func__, host->num); + return HDF_SUCCESS; +} + +static ssize_t UartSampleRead(struct file *filep, char *buf, size_t count) +{ + int32_t ret; + uint8_t *tmpBuf = NULL; + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + + if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) { + tmpBuf = (uint8_t *)OsalMemCalloc(count); + if (tmpBuf == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_ERR_MALLOC_FAIL; + } + ret = UartHostRead(host, tmpBuf, count); + if (ret == HDF_SUCCESS) { + ret = LOS_ArchCopyToUser(buf, tmpBuf, count); + } + OsalMemFree(tmpBuf); + return ret; + } else { + return UartHostRead(host, (uint8_t *)buf, count); + } +} + +static ssize_t UartSampleWrite(struct file *filep, const char *buf, size_t count) +{ + int32_t ret; + uint8_t *tmpBuf = NULL; + struct UartHost *host = NULL; + + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + + if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, count)) { + tmpBuf = (uint8_t *)OsalMemCalloc(count); + if (tmpBuf == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return HDF_ERR_MALLOC_FAIL; + } + ret = LOS_ArchCopyFromUser(tmpBuf, buf, count); + if (ret != LOS_OK) { + OsalMemFree(tmpBuf); + return ret; + } + ret = UartHostWrite(host, tmpBuf, count); + OsalMemFree(tmpBuf); + return ret; + } else { + return UartHostWrite(host, (uint8_t *)buf, count); + } +} + +static int32_t UartSampleDevIoctl(struct file *filep, int32_t cmd, unsigned long arg) +{ + int32_t ret = HDF_FAILURE; + struct UartHost *host = NULL; + if (filep == NULL || filep->f_vnode == NULL) { + return HDF_ERR_INVALID_PARAM; + } + struct drv_data *drv = (struct drv_data *)filep->f_vnode->data; + host = (struct UartHost *)drv->priv; + if (host->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + switch (cmd) { + case UART_CFG_BAUDRATE: + ret = UartHostSetBaud(host, arg); + break; + default: + HDF_LOGE("%s cmd %d not support", __func__, cmd); + ret = HDF_ERR_NOT_SUPPORT; + break; + } + return ret; +} + +const struct file_operations_vfs g_uartSampleDevFops = { + .open = UartSampleDevOpen, + .close = UartSampleRelease, + .read = UartSampleRead, + .write = UartSampleWrite, + .ioctl = UartSampleDevIoctl, +}; + +#define MAX_DEV_NAME_SIZE 32 +static void AddRemoveUartDev(struct UartHost *host, bool add) +{ + int32_t ret; + char *devName = NULL; + + if (host == NULL || host->priv == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return; + } + devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1)); + if (devName == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return; + } + ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num); + if (ret < 0) { + HDF_LOGE("%s: snprintf_s failed", __func__); + OsalMemFree(devName); + return; + } + if (add) { + if (register_driver(devName, &g_uartSampleDevFops, HDF_UART_FS_MODE, host)) { + HDF_LOGE("%s: gen /dev/uartdev-%d fail!", __func__, host->num); + OsalMemFree(devName); + return; + } + } else { + if (unregister_driver(devName)) { + HDF_LOGE("%s: remove /dev/uartdev-%d fail!", __func__, host->num); + OsalMemFree(devName); + return; + } + } + OsalMemFree(devName); +} + +void AddUartDevice(struct UartHost *host) +{ + AddRemoveUartDev(host, true); +} + +void RemoveUartDevice(struct UartHost *host) +{ + AddRemoveUartDev(host, false); +} diff --git a/sample/platform/uart/src/uart_dispatch_sample.c b/sample/platform/uart/src/uart_dispatch_sample.c new file mode 100755 index 00000000..e69ef5d8 --- /dev/null +++ b/sample/platform/uart/src/uart_dispatch_sample.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "uart_core.h" +#include "uart_dispatch_sample.h" +#include "hdf_log.h" +#include "hdf_sbuf.h" +#include "osal_mem.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_dispatch_sample + +static int32_t SampleDispatchWrite(struct UartDevice *device, struct HdfSBuf *txBuf) +{ + uint32_t idx; + uint32_t dataSize = 0; + const uint8_t *data = NULL; + struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase; + + if (regMap == NULL) { + HDF_LOGE("%s: regMap is NULL", __func__); + return HDF_FAILURE; + } + + if (!HdfSbufReadBuffer(txBuf, (const void **)&data, &dataSize)) { + HDF_LOGE("%s: Failed to read sbuf", __func__); + return HDF_FAILURE; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + for (idx = 0; idx < dataSize; idx++) { + UartPl011Write(regMap, data[idx]); + } + return HDF_SUCCESS; +} + +int32_t SampleDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t result = HDF_FAILURE; + if (client == NULL || client->device == NULL) { + HDF_LOGE("%s: client or client->device is NULL", __func__); + return result; + } + struct UartHost *uartHost = (struct UartHost *)client->device->service; + if (uartHost == NULL) { + HDF_LOGE("%s: uartHost is NULL", __func__); + return result; + } + struct UartDevice *uartDevice = (struct UartDevice *)uartHost->priv; + if (uartDevice == NULL) { + HDF_LOGE("%s: uartDevice is NULL", __func__); + return result; + } + switch (cmdId) { + case UART_WRITE: { + result = SampleDispatchWrite(uartDevice, data); + break; + } + default: + break; + } + return result; +} diff --git a/sample/platform/uart/src/uart_pl011_sample.c b/sample/platform/uart/src/uart_pl011_sample.c new file mode 100755 index 00000000..12f2c6cf --- /dev/null +++ b/sample/platform/uart/src/uart_pl011_sample.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "uart_pl011_sample.h" + +void UartPl011SetLcrBits(struct UartRegisterMap *regMap, uint32_t bits) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr |= (bits); + /* Restore uart enable state */ + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +void UartPl011UpdateLcr(struct UartRegisterMap *regMap) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr = regMap->lcr; + /* restore uart enable state */ + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate) +{ + if (baudrate == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + uint32_t value = SAMPLING_FACTOR * baudrate; + uint32_t divider = clk / value; + uint32_t remainder = clk % value; + uint32_t fraction; + value = (SAMPLING_FACTOR * remainder) / baudrate; + fraction = (value >> 1) + (value & 1); + + regMap->ibrd = divider; + regMap->fbrd = fraction; + /* to internally update the contents of UARTIBRD or + * UARTFBRD, a UARTLCR_H write must always be performed at the end. + */ + UartPl011UpdateLcr(regMap); + return UART_PL011_ERR_NONE; +} + +void UartPl011SetDataFormat( + struct UartRegisterMap *regMap, uint32_t wordLen, uint32_t parity, uint32_t stopBits) +{ + bool uartEnabled = UartPl011IsEnabled(regMap); + uint32_t lcr = regMap->lcr & (~UART_PL011_DATA_FORMAT_MASK); + lcr |= wordLen & UART_PL011_LCR_H_WLEN_MASK; + lcr |= parity & UART_PL011_LCR_H_PARITY_MASK; + lcr |= stopBits & UART_PL011_LCR_H_STOPBIT_MASK; + /* UART must be disabled before UARTLCR_H are reprogrammed */ + UartPl011Disable(regMap); + regMap->lcr = lcr; + if (uartEnabled) { + UartPl011Enable(regMap); + } +} + +void UartPl011ResetRegisters(struct UartRegisterMap *regMap) +{ + regMap->cr = UART_PL011_DEFAULT_CTRL_REG_VALUE; + regMap->dr = UART_PL011_DEFAULT_DATA_REG_VALUE; + /* Clear all the errors */ + regMap->ecr = UART_PL011_DEFAULT_ECR_VALUE; + regMap->ilpr = UART_PL011_DEFAULT_ILPR_VALUE; + regMap->ibrd = UART_PL011_DEFAULT_IBRD_REG_VALUE; + regMap->fbrd = UART_PL011_DEFAULT_FBRD_REG_VALUE; + regMap->lcr = UART_PL011_DEFAULT_LCR_H_VALUE; + regMap->ifls = UART_PL011_DEFAULT_IFLS_REG_VALUE; + /* Clear all interrupt mask */ + regMap->imsc = UART_PL011_DEFAULT_IMSC_REG_VALUE; + /* Clear all interrupts */ + regMap->icr = UART_PL011_DEFAULT_ICR_VALUE; + regMap->dmacr = UART_PL011_DEFAULT_DMACR_VALUE; +} + diff --git a/sample/platform/uart/src/uart_sample.c b/sample/platform/uart/src/uart_sample.c new file mode 100755 index 00000000..89a16b28 --- /dev/null +++ b/sample/platform/uart/src/uart_sample.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * + * HDF 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 "device_resource_if.h" +#include "buf_fifo.h" +#include "hdf_device_desc.h" +#include "hdf_log.h" +#include "hisoc/uart.h" +#include "osal_io.h" +#include "osal_mem.h" +#include "uart_core.h" +#include "uart_dev_sample.h" +#include "uart_dispatch_sample.h" +#include "uart_pl011_sample.h" + +#define HDF_LOG_TAG uart_sample +#define UART_RX_FIFO_SIZE 128 + +static uint8_t g_fifoBuffer[UART_RX_FIFO_SIZE] = {0}; + +/* HdfDriverEntry method definitions */ +static int32_t SampleUartDriverBind(struct HdfDeviceObject *device); +static int32_t SampleUartDriverInit(struct HdfDeviceObject *device); +static void SampleUartDriverRelease(struct HdfDeviceObject *device); + +/* HdfDriverEntry definitions */ +struct HdfDriverEntry g_sampleUartDriverEntry = { + .moduleVersion = 1, + .moduleName = "UART_SAMPLE", + .Bind = SampleUartDriverBind, + .Init = SampleUartDriverInit, + .Release = SampleUartDriverRelease, +}; + +// Initialize HdfDriverEntry +HDF_INIT(g_sampleUartDriverEntry); + +/* UartHostMethod method definitions */ +static int32_t SampleUartHostInit(struct UartHost *host); +static int32_t SampleUartHostDeinit(struct UartHost *host); +static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size); +static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate); +static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate); + +/* UartHostMethod definitions */ +struct UartHostMethod g_sampleUartHostMethod = { + .Init = SampleUartHostInit, + .Deinit = SampleUartHostDeinit, + .Read = NULL, + .Write = SampleUartHostWrite, + .SetBaud = SampleUartHostSetBaud, + .GetBaud = SampleUartHostGetBaud, + .SetAttribute = NULL, + .GetAttribute = NULL, + .SetTransMode = NULL, +}; + +/* UartHostMethod implementations */ +static int32_t SampleUartHostInit(struct UartHost *host) +{ + HDF_LOGD("%s: Enter", __func__); + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostDeinit(struct UartHost *host) +{ + HDF_LOGD("%s: Enter", __func__); + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size) +{ + uint32_t idx; + struct UartRegisterMap *regMap = NULL; + struct UartDevice *device = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL || data == NULL || size == 0) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + for (idx = 0; idx < size; idx++) { + UartPl011Write(regMap, data[idx]); + } + return HDF_SUCCESS; +} + +static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate) +{ + struct UartDevice *device = NULL; + struct UartRegisterMap *regMap = NULL; + UartPl011Error err; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + regMap = (struct UartRegisterMap *)device->resource.physBase; + if (device->state != UART_DEVICE_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + if (baudRate == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate); + if (err == UART_PL011_ERR_NONE) { + device->baudrate = baudRate; + } + return err; +} + +static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate) +{ + struct UartDevice *device = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (host == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return HDF_ERR_INVALID_PARAM; + } + device = (struct UartDevice *)host->priv; + if (device == NULL) { + HDF_LOGW("%s: device is NULL", __func__); + return HDF_ERR_INVALID_PARAM; + } + *baudRate = device->baudrate; + return HDF_SUCCESS; +} + +static int InitUartDevice(struct UartDevice *device) +{ + UartPl011Error err; + struct UartResource *resource = &device->resource; + struct UartRegisterMap *regMap = (struct UartRegisterMap *)resource->physBase; + if ((resource->uartClk == 0) || (resource->baudrate == 0)) { + return HDF_ERR_INVALID_PARAM; + } + /* Updating the system clock */ + device->uartClk = resource->uartClk; + uart_clk_cfg(0, true); + /* clear and reset registers. */ + UartPl011ResetRegisters(regMap); + /* set baud rate as device config */ + err = UartPl011SetBaudrate(regMap, resource->uartClk, resource->baudrate); + if (err != UART_PL011_ERR_NONE) { + return HDF_FAILURE; + } + /* set the data format as device config */ + UartPl011SetDataFormat(regMap, resource->wlen, resource->parity, resource->stopBit); + /* Enabling the FIFOs */ + UartPl011EnableFifo(regMap); + UartPl011Enable(regMap); + BufferFifoInit(&device->rxFifo, g_fifoBuffer, UART_RX_FIFO_SIZE); + device->state = UART_DEVICE_INITIALIZED; + return HDF_SUCCESS; +} + +static uint32_t GetUartDeviceResource( + struct UartDevice *device, const struct DeviceResourceNode *resourceNode) +{ + struct UartResource *resource = &device->resource; + struct DeviceResourceIface *dri = NULL; + dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + if (dri == NULL || dri->GetUint32 == NULL) { + HDF_LOGE("DeviceResourceIface is invalid"); + return HDF_FAILURE; + } + + if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read num fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read base fail"); + return HDF_FAILURE; + } + resource->physBase = (unsigned long)OsalIoRemap(resource->base, 0x48); + if (resource->physBase == 0) { + HDF_LOGE("uart config fail to remap physBase"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read irqNum fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read baudrate fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read wlen fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read parity fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read stopBit fail"); + return HDF_FAILURE; + } + if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) { + HDF_LOGE("uart config read uartClk fail"); + return HDF_FAILURE; + } + return HDF_SUCCESS; +} + +static int32_t AttachUartDevice(struct UartHost *host, struct HdfDeviceObject *device) +{ + int32_t ret; + struct UartDevice *uartDevice = NULL; + if (device->property == NULL) { + HDF_LOGW("%s: property is NULL", __func__); + return HDF_FAILURE; + } + uartDevice = (struct UartDevice *)OsalMemCalloc(sizeof(struct UartDevice)); + if (uartDevice == NULL) { + HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__); + return HDF_ERR_MALLOC_FAIL; + } + ret = GetUartDeviceResource(uartDevice, device->property); + if (ret != HDF_SUCCESS) { + (void)OsalMemFree(uartDevice); + return HDF_FAILURE; + } + host->num = uartDevice->resource.num; + host->priv = uartDevice; + AddUartDevice(host); + return InitUartDevice(uartDevice); +} + +static void DeinitUartDevice(struct UartDevice *device) +{ + struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase; + /* wait for uart enter idle. */ + while (UartPl011IsBusy(regMap)); + UartPl011ResetRegisters(regMap); + uart_clk_cfg(0, false); + OsalIoUnmap((void *)device->resource.physBase); + device->state = UART_DEVICE_UNINITIALIZED; +} + +static void DetachUartDevice(struct UartHost *host) +{ + struct UartDevice *uartDevice = NULL; + + if (host->priv == NULL) { + HDF_LOGW("%s: invalid parameter", __func__); + return; + } + uartDevice = host->priv; + DeinitUartDevice(uartDevice); + (void)OsalMemFree(uartDevice); + host->priv = NULL; +} + +/* HdfDriverEntry implementations */ +static int32_t SampleUartDriverBind(struct HdfDeviceObject *device) +{ + struct UartHost *uartHost = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (device == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + uartHost = UartHostCreate(device); + if (uartHost == NULL) { + HDF_LOGE("%s: UartHostCreate failed", __func__); + return HDF_FAILURE; + } + uartHost->service.Dispatch = SampleDispatch; + return HDF_SUCCESS; +} + +static int32_t SampleUartDriverInit(struct HdfDeviceObject *device) +{ + int32_t ret; + struct UartHost *host = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (device == NULL) { + HDF_LOGE("%s: device is NULL", __func__); + return HDF_ERR_INVALID_OBJECT; + } + host = UartHostFromDevice(device); + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return HDF_FAILURE; + } + ret = AttachUartDevice(host, device); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%s: attach error", __func__); + return HDF_FAILURE; + } + host->method = &g_sampleUartHostMethod; + return ret; +} + +static void SampleUartDriverRelease(struct HdfDeviceObject *device) +{ + struct UartHost *host = NULL; + HDF_LOGD("%s: Enter", __func__); + + if (device == NULL) { + HDF_LOGE("%s: device is NULL", __func__); + return; + } + host = UartHostFromDevice(device); + if (host == NULL) { + HDF_LOGE("%s: host is NULL", __func__); + return; + } + if (host->priv != NULL) { + DetachUartDevice(host); + } + UartHostDestroy(host); +}