diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/Android.mk b/drivers/input/touchscreen/goodix_gt96x_mmi/Android.mk index b8a5ff7cf855..977c212fcdc2 100644 --- a/drivers/input/touchscreen/goodix_gt96x_mmi/Android.mk +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/Android.mk @@ -9,6 +9,9 @@ else endif endif +ifeq ($(DRM_PANEL_EVENT_NOTIFICATIONS),true) + KBUILD_OPTIONS += CONFIG_DRM_PANEL_EVENT_NOTIFICATIONS=y +endif include $(CLEAR_VARS) LOCAL_MODULE := goodix_gt96x_mmi.ko diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/Kbuild b/drivers/input/touchscreen/goodix_gt96x_mmi/Kbuild index 8d599929b010..fab6fa25a372 100644 --- a/drivers/input/touchscreen/goodix_gt96x_mmi/Kbuild +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/Kbuild @@ -20,4 +20,13 @@ ifneq ($(filter m y,$(CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI)),) EXTRA_CFLAGS += -DCONFIG_TOUCHSCREEN_GOODIX_BRL_SPI endif +ifneq ($(filter m y,$(CONFIG_INPUT_TOUCHSCREEN_MMI)),) + EXTRA_CFLAGS += -DCONFIG_INPUT_TOUCHSCREEN_MMI + goodix_gt96x_mmi-objs += goodix_ts_mmi.o +endif + +ifneq ($(filter m y, $(CONFIG_DRM_PANEL_EVENT_NOTIFICATIONS)),) + EXTRA_CFLAGS += -DCONFIG_DRM_PANEL_EVENT_NOTIFICATIONS +endif + KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../touchscreen_mmi/$(GKI_OBJ_MODULE_DIR)/Module.symvers diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_brl_spi.c b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_brl_spi.c index ebb58e111e1a..8d46aff6958c 100644 --- a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_brl_spi.c +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_brl_spi.c @@ -222,6 +222,8 @@ static int goodix_spi_probe(struct spi_device *spi) dev_res->pdev.id = dev_res->id; dev_res->pdev.num_resources = 0; + spi_set_drvdata(spi, &dev_res->pdev); + /* register platform device, then the goodix_ts_core * module will probe the touch deivce. */ diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.c b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.c index f540e7d21902..1cb01b727970 100644 --- a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.c +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.c @@ -23,12 +23,15 @@ #include #define INPUT_TYPE_B_PROTOCOL #endif +#include "goodix_ts_mmi.h" /* goodix fb test */ // #include "../../../video/fbdev/core/fb_firefly.h" #define GOODIX_DEFAULT_CFG_NAME "goodix_cfg_group.cfg" struct goodix_device_manager goodix_devices; +#define PINCTRL_STATE_ACTIVE "cli_pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "cli_pmx_ts_suspend" static void goodix_device_manager_init(void) { @@ -886,6 +889,16 @@ static int goodix_parse_dt(struct device_node *node, board_data->pen_enable = of_property_read_bool(node, "goodix,pen-enable"); + /* get ic compatible */ + r = of_property_read_string(node, "compatible", &name_tmp); + if (r) { + ts_err("get compatible failed"); + return r; + } else { + ts_info("ic_name form dt: %s", name_tmp); + strncpy(board_data->ic_name, name_tmp, sizeof(board_data->ic_name)); + } + ts_info("[DT]x:%d, y:%d, w:%d, p:%d sleep_enable:%d pen_enable:%d", board_data->panel_max_x, board_data->panel_max_y, board_data->panel_max_w, board_data->panel_max_p, @@ -1156,6 +1169,54 @@ int goodix_ts_power_off(struct goodix_ts_core *cd) return ret; } +/** + * goodix_ts_pinctrl_init - Get pinctrl handler and pinctrl_state + * @core_data: pointer to touch core data + * return: 0 ok, <0 failed + */ +static int goodix_ts_pinctrl_init(struct goodix_ts_core *core_data) +{ + int r = 0; + + /* get pinctrl handler from of node */ + core_data->pinctrl = devm_pinctrl_get(core_data->bus->dev); + if (IS_ERR_OR_NULL(core_data->pinctrl)) { + ts_info("Failed to get pinctrl handler[need confirm]"); + core_data->pinctrl = NULL; + return -EINVAL; + } + ts_debug("success get pinctrl"); + /* active state */ + core_data->pin_sta_active = pinctrl_lookup_state(core_data->pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(core_data->pin_sta_active)) { + r = PTR_ERR(core_data->pin_sta_active); + ts_err("Failed to get pinctrl state:%s, r:%d", + PINCTRL_STATE_ACTIVE, r); + core_data->pin_sta_active = NULL; + goto exit_pinctrl_put; + } + ts_info("success get avtive pinctrl state"); + + /* suspend state */ + core_data->pin_sta_suspend = pinctrl_lookup_state(core_data->pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(core_data->pin_sta_suspend)) { + r = PTR_ERR(core_data->pin_sta_suspend); + ts_err("Failed to get pinctrl state:%s, r:%d", + PINCTRL_STATE_SUSPEND, r); + core_data->pin_sta_suspend = NULL; + goto exit_pinctrl_put; + } + ts_info("success get suspend pinctrl state"); + + return 0; +exit_pinctrl_put: + devm_pinctrl_put(core_data->pinctrl); + core_data->pinctrl = NULL; + return r; +} + /** * goodix_ts_gpio_setup - Request gpio resources from GPIO subsysten * @core_data: pointer to touch core data @@ -1443,7 +1504,7 @@ int goodix_ts_esd_init(struct goodix_ts_core *cd) return 0; } -static void goodix_ts_release_connects(struct goodix_ts_core *core_data) +void goodix_ts_release_connects(struct goodix_ts_core *core_data) { struct input_dev *input_dev = core_data->input_dev; struct input_dev *pen_dev = core_data->pen_dev; @@ -1473,6 +1534,7 @@ static void goodix_ts_release_connects(struct goodix_ts_core *core_data) core_data->hw_ops->after_event_handler(core_data); } +#ifndef CONFIG_INPUT_TOUCHSCREEN_MMI /** * goodix_ts_suspend - Touchscreen suspend function * Called by PM/FB/EARLYSUSPEN module to put the device to sleep @@ -1552,6 +1614,7 @@ static void goodix_ts_resume_work(struct work_struct *work) container_of(work, struct goodix_ts_core, resume_work); goodix_ts_resume(cd); } +#endif #if IS_ENABLED(CONFIG_FB) /** @@ -1580,7 +1643,7 @@ int goodix_ts_fb_notifier_callback(struct notifier_block *self, return 0; } -#elif IS_ENABLED(CONFIG_PM) +#elif IS_ENABLED(CONFIG_PM) && !defined(CONFIG_INPUT_TOUCHSCREEN_MMI) /** * goodix_ts_pm_suspend - PM suspend function * Called by kernel during system suspend phrase @@ -1607,6 +1670,29 @@ static const struct dev_pm_ops dev_pm_ops = { .suspend = goodix_ts_pm_suspend, .resume = goodix_ts_pm_resume, }; +#else +/** + * goodix_ts_pm_suspend - PM suspend function + * Called by kernel during system suspend phrase + */ +static int goodix_ts_pm_suspend(struct device *dev) +{ + ts_info("system enters into pm_suspend"); + return 0; +} +/** + * goodix_ts_pm_resume - PM resume function + * Called by kernel during system wakeup + */ +static int goodix_ts_pm_resume(struct device *dev) +{ + ts_info("system resumes from pm_suspend"); + return 0; +} +static const struct dev_pm_ops dev_pm_ops = { + .suspend = goodix_ts_pm_suspend, + .resume = goodix_ts_pm_resume, +}; #endif static void goodix_self_check(struct work_struct *work) @@ -1679,7 +1765,9 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) /* inspect init */ inspect_module_init(cd); +#ifndef CONFIG_INPUT_TOUCHSCREEN_MMI INIT_WORK(&cd->resume_work, goodix_ts_resume_work); +#endif /* Do self check on first boot */ INIT_WORK(&cd->self_check_work, goodix_self_check); @@ -1867,6 +1955,24 @@ static int goodix_ts_probe(struct platform_device *pdev) goto err_out; } + /* Pinctrl handle is optional. */ + ret = goodix_ts_pinctrl_init(core_data); + if (!ret && core_data->pinctrl) { + ret = pinctrl_select_state(core_data->pinctrl, + core_data->pin_sta_active); + if (ret < 0) + ts_err("Failed to select active pinstate, r:%d", ret); + } + +#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI + ts_info("%s:goodix_ts_mmi_dev_register",__func__); + ret = goodix_ts_mmi_dev_register(pdev); + if (ret) { + ts_info("Failed register touchscreen mmi."); + goto err_out; + } +#endif + /* debug node init */ ret = goodix_tools_init(core_data); if (ret) { @@ -1900,6 +2006,11 @@ static int goodix_ts_remove(struct platform_device *pdev) struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; struct goodix_ts_esd *ts_esd = &core_data->ts_esd; +#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI + ts_info("%s:goodix_ts_mmi_dev_unregister",__func__); + goodix_ts_mmi_dev_unregister(pdev); +#endif + goodix_tools_exit(core_data); goodix_fw_update_uninit(core_data); diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.h b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.h index c93897a31f62..cf554d226193 100644 --- a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.h +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_core.h @@ -440,6 +440,7 @@ struct goodix_module { * @fw_name: name of the firmware image */ struct goodix_ts_board_data { + char ic_name[GOODIX_MAX_STR_LABLE_LEN]; char avdd_name[GOODIX_MAX_STR_LABLE_LEN]; char iovdd_name[GOODIX_MAX_STR_LABLE_LEN]; int reset_gpio; @@ -736,6 +737,9 @@ struct goodix_ts_core { struct goodix_ic_config ic_configs[GOODIX_MAX_CONFIG_GROUP]; struct regulator *avdd; struct regulator *iovdd; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_sta_active; + struct pinctrl_state *pin_sta_suspend; u32 gesture_type; char input_name[32]; @@ -785,6 +789,17 @@ extern bool debug_log_flag; {if (debug_log_flag) \ pr_info("[GDX-CLI-DBG][%s] "fmt"\n", __func__, ##arg);} +/* + * get board data pointer + */ +static inline struct goodix_ts_board_data *board_data( + struct goodix_ts_core *core) +{ + if (!core) + return NULL; + return &(core->board_data); +} + struct goodix_ts_hw_ops *goodix_get_hw_ops(void); int goodix_get_config_proc(struct goodix_ts_core *cd); @@ -815,4 +830,8 @@ void goodix_ts_esd_off(struct goodix_ts_core *cd); int goodix_ts_report_gesture(struct goodix_ts_core *cd, struct goodix_ts_event *event); +int goodix_ts_power_on(struct goodix_ts_core *cd); +int goodix_ts_power_off(struct goodix_ts_core *cd); +void goodix_ts_release_connects(struct goodix_ts_core *core_data); + #endif diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.c b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.c new file mode 100644 index 000000000000..5c4ac5171687 --- /dev/null +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2023 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "goodix_ts_mmi.h" +#include +#include + +#define GET_GOODIX_DATA(dev) { \ + pdev = dev_get_drvdata(dev); \ + if (!pdev) { \ + ts_err("Failed to get platform device"); \ + return -ENODEV; \ + } \ + core_data = platform_get_drvdata(pdev); \ + if (!core_data) { \ + ts_err("Failed to get driver data"); \ + return -ENODEV; \ + } \ +} + +static int goodix_ts_mmi_methods_get_vendor(struct device *dev, void *cdata) { + return scnprintf(TO_CHARP(cdata), TS_MMI_MAX_VENDOR_LEN, "%s", "goodix"); +} + +static int goodix_ts_mmi_methods_get_productinfo(struct device *dev, void *cdata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + struct goodix_ts_board_data *ts_bdata; + char* ic_info; + + GET_GOODIX_DATA(dev); + + ts_bdata = board_data(core_data); + if (!ts_bdata) { + ts_err("Failed to get ts board data"); + return -ENODEV; + } + + ic_info = strstr(ts_bdata->ic_name, ","); + ic_info++; + + return scnprintf(TO_CHARP(cdata), TS_MMI_MAX_VENDOR_LEN, "%s", ic_info); +} + +#define TOUCH_CFG_VERSION_ADDR 0x10076 +static int goodix_ts_mmi_methods_get_build_id(struct device *dev, void *cdata) { + int ret; + struct platform_device *pdev; + struct goodix_ts_core *core_data; + u32 cfg_id; + + GET_GOODIX_DATA(dev); + + ret = core_data->hw_ops->read(core_data, TOUCH_CFG_VERSION_ADDR, + (u8*)&cfg_id, sizeof(cfg_id)); + if (ret) { + ts_info("failed get fw version data, %d", ret); + return -EINVAL; + } + + return snprintf(TO_CHARP(cdata), TS_MMI_MAX_ID_LEN, "%04x", le32_to_cpu(cfg_id)); +} + +#define TOUCH_FW_VERSION_ADDR 0x1007E +/*return firmware version*/ +static int goodix_ts_mmi_methods_get_config_id(struct device *dev, void *cdata) { + int ret; + struct platform_device *pdev; + struct goodix_ts_core *core_data; + u8 fw_id[4] = {0}; + + GET_GOODIX_DATA(dev); + + ret = core_data->hw_ops->read(core_data, TOUCH_FW_VERSION_ADDR, + fw_id, sizeof(fw_id)); + if (ret) { + ts_info("failed get fw version data, %d", ret); + return -EINVAL; + } + + return snprintf(TO_CHARP(cdata), TS_MMI_MAX_ID_LEN, "%02x%02x%02x%02x", + fw_id[0], fw_id[1], fw_id[2], fw_id[3]); +} + +static int goodix_ts_mmi_methods_get_bus_type(struct device *dev, void *idata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + TO_INT(idata) = core_data->bus->bus_type == GOODIX_BUS_TYPE_I2C ? + TOUCHSCREEN_MMI_BUS_TYPE_I2C : TOUCHSCREEN_MMI_BUS_TYPE_SPI; + return 0; +} + +static int goodix_ts_mmi_methods_get_irq_status(struct device *dev, void *idata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + struct goodix_ts_board_data *ts_bdata; + + GET_GOODIX_DATA(dev); + + ts_bdata = board_data(core_data); + if (!ts_bdata) { + ts_err("Failed to get ts board data"); + return -ENODEV; + } + TO_INT(idata) = gpio_get_value(ts_bdata->irq_gpio); + return 0; +} + +static int goodix_ts_mmi_methods_get_drv_irq(struct device *dev, void *idata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + TO_INT(idata) = atomic_read(&core_data->irq_enabled); + return 0; +} + +static int goodix_ts_mmi_methods_get_poweron(struct device *dev, void *idata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + TO_INT(idata) = core_data->power_on; + return 0; +} + +static int goodix_ts_mmi_methods_get_flashprog(struct device *dev, void *idata) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + TO_INT(idata) = core_data->update_ctrl.status; + return 0; +} + +/* reset chip + * type:can control software reset and hardware reset, + * but GOODIX has no software reset, + * so the type parameter is not used here. + */ +static int goodix_ts_mmi_methods_reset(struct device *dev, int type) { + int ret = -ENODEV; + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + if (core_data->hw_ops->reset) + ret = core_data->hw_ops->reset(core_data, GOODIX_NORMAL_RESET_DELAY_MS); + return ret; +} + +static int goodix_ts_mmi_methods_drv_irq(struct device *dev, int state) { + int ret = -ENODEV; + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + if (core_data->hw_ops->irq_enable) + ret = core_data->hw_ops->irq_enable(core_data, !(!state)); + + return ret; +} + +static int goodix_ts_mmi_methods_power(struct device *dev, int on) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + if (on == TS_MMI_POWER_ON) + return goodix_ts_power_on(core_data); + else if(on == TS_MMI_POWER_OFF) + return goodix_ts_power_off(core_data); + else { + ts_err("Invalid power parameter %d.\n", on); + return -EINVAL; + } +} + +static int goodix_ts_mmi_pre_suspend(struct device *dev) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + ts_info("Suspend start"); + atomic_set(&core_data->suspended, 1); + + /* + * notify suspend event, inform the esd protector + * and charger detector to turn off the work + */ + goodix_ts_esd_off(core_data); + + return 0; +} + +static int goodix_ts_mmi_panel_state(struct device *dev, + enum ts_mmi_pm_mode from, enum ts_mmi_pm_mode to) +{ + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + switch (to) { + case TS_MMI_PM_GESTURE: + break; + case TS_MMI_PM_DEEPSLEEP: + break; + case TS_MMI_PM_ACTIVE: + break; + default: + ts_err("Invalid power state parameter %d.\n", to); + return -EINVAL; + } + + return 0; +} + +static int goodix_ts_mmi_post_suspend(struct device *dev) { + struct goodix_ts_core *core_data; + struct platform_device *pdev; + + GET_GOODIX_DATA(dev); + + goodix_ts_release_connects(core_data); + + ts_info("Suspend end"); + return 0; +} + +static int goodix_ts_mmi_pre_resume(struct device *dev) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + ts_info("Resume start"); + GET_GOODIX_DATA(dev); + + atomic_set(&core_data->suspended, 0); + return 0; +} + +static int goodix_ts_mmi_post_resume(struct device *dev) { + struct platform_device *pdev; + struct goodix_ts_core *core_data; + + GET_GOODIX_DATA(dev); + + /* open esd */ + goodix_ts_esd_on(core_data); + ts_info("Resume end"); + return 0; +} +static struct ts_mmi_methods goodix_ts_mmi_methods = { + .get_vendor = goodix_ts_mmi_methods_get_vendor, + .get_productinfo = goodix_ts_mmi_methods_get_productinfo, + .get_build_id = goodix_ts_mmi_methods_get_build_id, + .get_config_id = goodix_ts_mmi_methods_get_config_id, + .get_bus_type = goodix_ts_mmi_methods_get_bus_type, + .get_irq_status = goodix_ts_mmi_methods_get_irq_status, + .get_drv_irq = goodix_ts_mmi_methods_get_drv_irq, + .get_poweron = goodix_ts_mmi_methods_get_poweron, + .get_flashprog = goodix_ts_mmi_methods_get_flashprog, + /* SET methods */ + .reset = goodix_ts_mmi_methods_reset, + .drv_irq = goodix_ts_mmi_methods_drv_irq, + .power = goodix_ts_mmi_methods_power, + /* PM callback */ + .pre_suspend = goodix_ts_mmi_pre_suspend, + .panel_state = goodix_ts_mmi_panel_state, + .post_suspend = goodix_ts_mmi_post_suspend, + .pre_resume = goodix_ts_mmi_pre_resume, + .post_resume = goodix_ts_mmi_post_resume, +}; + +int goodix_ts_mmi_dev_register(struct platform_device *pdev) { + int ret; + struct goodix_ts_core *core_data; + + core_data = platform_get_drvdata(pdev); + if (!core_data) { + ts_err("Failed to get driver data"); + return -ENODEV; + } + ret = ts_mmi_dev_register(core_data->bus->dev, &goodix_ts_mmi_methods); + if (ret) { + dev_err(&pdev->dev, "Failed to register ts mmi\n"); + return ret; + } + + return 0; +} + +void goodix_ts_mmi_dev_unregister(struct platform_device *pdev) { + struct goodix_ts_core *core_data; + + core_data = platform_get_drvdata(pdev); + if (!core_data) + ts_err("Failed to get driver data"); + ts_mmi_dev_unregister(core_data->bus->dev); +} diff --git a/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.h b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.h new file mode 100644 index 000000000000..1abf4c84a06c --- /dev/null +++ b/drivers/input/touchscreen/goodix_gt96x_mmi/goodix_ts_mmi.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __GOODIX_TS_MMI_H__ +#define __GOODIX_TS_MMI_H__ + +#include +#include +#include +#include "goodix_ts_core.h" + +#ifdef CONFIG_INPUT_TOUCHSCREEN_MMI +int goodix_ts_mmi_dev_register(struct platform_device *ts_device); +void goodix_ts_mmi_dev_unregister(struct platform_device *ts_device); +#else +static int inline goodix_ts_mmi_dev_register(struct platform_device *ts_device) { + return -ENOSYS; +} +static int inline goodix_ts_mmi_dev_unregister(struct platform_device *ts_device) { + return -ENOSYS; +} +#endif + +#endif