diff --git a/drivers/motor/Kconfig b/drivers/motor/Kconfig index a6a6f2f1f6b..7c220916b42 100644 --- a/drivers/motor/Kconfig +++ b/drivers/motor/Kconfig @@ -9,6 +9,56 @@ menuconfig MOTOR if MOTOR +config MOTOR_UPPER + bool "Motor generic upper-half driver" + default n + ---help--- + Enables building of a motor generic upper half driver. + +if MOTOR_UPPER + +config MOTOR_UPPER_HAVE_POSITION + bool "Have position control" + default n + +config MOTOR_UPPER_HAVE_DIRECTION + bool "Have direction control" + default n + +config MOTOR_UPPER_HAVE_SPEED + bool "Have speed control" + default n + +config MOTOR_UPPER_HAVE_TORQUE + bool "Have torque control (rotary motors)" + default n + +config MOTOR_UPPER_HAVE_FORCE + bool "Have force control (linear motors)" + default n + +config MOTOR_UPPER_HAVE_ACCELERATION + bool "Have acceleration control" + default n + +config MOTOR_UPPER_HAVE_DECELERATION + bool "Have deceleration control" + default n + +config MOTOR_UPPER_HAVE_INPUT_VOLTAGE + bool "Have input voltage protection" + default n + +config MOTOR_UPPER_HAVE_INPUT_CURRENT + bool "Have input current protection" + default n + +config MOTOR_UPPER_HAVE_INPUT_POWER + bool "Have input power protection" + default n + +endif + source "drivers/motor/foc/Kconfig" endif # MOTOR diff --git a/drivers/motor/Make.defs b/drivers/motor/Make.defs index d369148d45c..40080e5aa90 100644 --- a/drivers/motor/Make.defs +++ b/drivers/motor/Make.defs @@ -24,6 +24,12 @@ ifeq ($(CONFIG_MOTOR_FOC),y) include motor$(DELIM)foc$(DELIM)Make.defs endif +# Add generic upper-half motor driver + +ifeq ($(CONFIG_MOTOR_UPPER),y) +CSRCS += motor.c +endif + # Include motor drivers in the build MOTOR_DEPPATH := --dep-path motor diff --git a/drivers/power/motor.c b/drivers/motor/motor.c similarity index 85% rename from drivers/power/motor.c rename to drivers/motor/motor.c index fafba7fcda1..5b18c8f20a3 100644 --- a/drivers/power/motor.c +++ b/drivers/motor/motor.c @@ -1,5 +1,5 @@ /**************************************************************************** - * drivers/power/motor.c + * drivers/motor/motor.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -35,7 +35,7 @@ #include #include -#include +#include #include @@ -214,7 +214,7 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) switch (cmd) { - case PWRIOC_START: + case MTRIOC_START: { /* Allow motor start only when some limits available * and structure is locked. @@ -222,30 +222,30 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if ((motor->limits.lock == false) || ( -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION motor->limits.position <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED motor->limits.speed <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE motor->limits.torque <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE motor->limits.force <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_VOLTAGE +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_VOLTAGE motor->limits.v_in <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_CURRENT +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_CURRENT motor->limits.i_in <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_POWER +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_POWER motor->limits.p_in <= 0.0 && #endif 1)) { - pwrerr("ERROR: motor limits data must be set" + mtrerr("Motor limits data must be set" " and locked before motor start\n"); ret = -EPERM; @@ -256,7 +256,7 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if (motor->opmode == MOTOR_OPMODE_INIT) { - pwrerr("ERROR: motor operation mode not specified\n"); + mtrerr("Motor operation mode not specified\n"); ret = -EPERM; goto errout; @@ -269,43 +269,43 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ret = dev->ops->start(dev); if (ret != OK) { - pwrerr("ERROR: PWRIOC_START failed %d\n", ret); + mtrerr("MTRIOC_START failed %d\n", ret); } break; } - case PWRIOC_STOP: + case MTRIOC_STOP: { /* Call stop from lower-half driver */ ret = dev->ops->stop(dev); if (ret != OK) { - pwrerr("ERROR: PWRIOC_STOP failed %d\n", ret); + mtrerr("MTRIOC_STOP failed %d\n", ret); } break; } - case PWRIOC_SET_MODE: + case MTRIOC_SET_MODE: { uint8_t mode = ((uint8_t)arg); ret = dev->ops->mode_set(dev, mode); if (ret != OK) { - pwrerr("ERROR: PWRIOC_SET_MODE failed %d\n", ret); + mtrerr("MTRIOC_SET_MODE failed %d\n", ret); } break; } - case PWRIOC_SET_LIMITS: + case MTRIOC_SET_LIMITS: { FAR struct motor_limits_s *limits = (FAR struct motor_limits_s *)((uintptr_t)arg); if (motor->limits.lock == true) { - pwrerr("ERROR: motor limits locked!\n"); + mtrerr("Motor limits locked!\n"); ret = -EPERM; goto errout; @@ -316,12 +316,12 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ret = dev->ops->limits_set(dev, limits); if (ret != OK) { - pwrerr("ERROR: PWRIOC_SET_LIMITS failed %d\n", ret); + mtrerr("MTRIOC_SET_LIMITS failed %d\n", ret); } break; } - case PWRIOC_GET_STATE: + case MTRIOC_GET_STATE: { FAR struct motor_state_s *state = (FAR struct motor_state_s *)((uintptr_t)arg); @@ -329,55 +329,55 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ret = dev->ops->state_get(dev, state); if (ret != OK) { - pwrerr("ERROR: PWRIOC_GET_STATE failed %d\n", ret); + mtrerr("MTRIOC_GET_STATE failed %d\n", ret); } break; } - case PWRIOC_SET_FAULT: + case MTRIOC_SET_FAULT: { uint8_t fault = ((uint8_t)arg); ret = dev->ops->fault_set(dev, fault); if (ret != OK) { - pwrerr("ERROR: PWRIOC_SET_FAULT failed %d\n", ret); + mtrerr("MTRIOC_SET_FAULT failed %d\n", ret); } break; } - case PWRIOC_GET_FAULT: + case MTRIOC_GET_FAULT: { FAR uint8_t *fault = ((FAR uint8_t *)arg); ret = dev->ops->fault_get(dev, fault); if (ret != OK) { - pwrerr("ERROR: PWRIOC_GET_FAULT failed %d\n", ret); + mtrerr("MTRIOC_GET_FAULT failed %d\n", ret); } break; } - case PWRIOC_CLEAN_FAULT: + case MTRIOC_CLEAR_FAULT: { uint8_t fault = ((uint8_t)arg); - ret = dev->ops->fault_clean(dev, fault); + ret = dev->ops->fault_clear(dev, fault); if (ret != OK) { - pwrerr("ERROR: PWRIOC_CLEAN_FAULT failed %d\n", ret); + mtrerr("MTRIOC_CLEAR_FAULT failed %d\n", ret); } break; } - case PWRIOC_SET_PARAMS: + case MTRIOC_SET_PARAMS: { FAR struct motor_params_s *params = (FAR struct motor_params_s *)((uintptr_t)arg); if (motor->param.lock == true) { - pwrerr("ERROR: motor params locked!\n"); + mtrerr("Motor params locked!\n"); ret = -EPERM; goto errout; @@ -385,42 +385,42 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if ((motor->limits.lock == false) || ( -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION motor->limits.position <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED motor->limits.speed <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE motor->limits.torque <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE motor->limits.force <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_VOLTAGE +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_VOLTAGE motor->limits.v_in <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_CURRENT +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_CURRENT motor->limits.i_in <= 0.0 && #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_POWER +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_POWER motor->limits.p_in <= 0.0 && #endif 1)) { - pwrerr("ERROR: limits must be set prior to params!\n"); + mtrerr("Limits must be set prior to params!\n"); ret = -EPERM; goto errout; } -#ifdef CONFIG_MOTOR_HAVE_DIRECTION +#ifdef CONFIG_MOTOR_UPPER_HAVE_DIRECTION /* Check direction configuration */ if (params->direction != MOTOR_DIR_CCW && params->direction != MOTOR_DIR_CW) { - pwrerr("ERROR: invalid direction value %d\n", + mtrerr("Invalid direction value %d\n", params->direction); ret = -EPERM; @@ -428,13 +428,13 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } #endif -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION /* Check position configuration */ if (params->position < 0.0 || params->position > motor->limits.position) { - pwrerr("ERROR: params->position > limits.position: " + mtrerr("params->position > limits.position: " "%.2f > %.2f\n", params->position, motor->limits.position); @@ -443,13 +443,13 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED /* Check speed configuration */ if (motor->limits.speed > 0.0 && params->speed > motor->limits.speed) { - pwrerr("ERROR: params->speed > limits.speed: %.2f > %.2f\n", + mtrerr("params->speed > limits.speed: %.2f > %.2f\n", params->speed, motor->limits.speed); ret = -EPERM; @@ -457,13 +457,13 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE /* Check torque configuration */ if (motor->limits.torque > 0.0 && params->torque > motor->limits.torque) { - pwrerr("ERROR: params->torque > limits.torque: %.2f > %.2f\n", + mtrerr("params->torque > limits.torque: %.2f > %.2f\n", params->torque, motor->limits.torque); ret = -EPERM; @@ -471,13 +471,13 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE /* Check force configuration */ if (motor->limits.force > 0.0 && params->force > motor->limits.force) { - pwrerr("ERROR: params->force > limits.force: %.2f > %.2f\n", + mtrerr("params->force > limits.force: %.2f > %.2f\n", params->force, motor->limits.force); ret = -EPERM; @@ -488,14 +488,14 @@ static int motor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) ret = dev->ops->params_set(dev, params); if (ret != OK) { - pwrerr("ERROR: PWRIOC_SET_PARAMS failed %d\n", ret); + mtrerr("MTRIOC_SET_PARAMS failed %d\n", ret); } break; } default: { - pwrinfo("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); + mtrinfo("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); ret = dev->ops->ioctl(dev, cmd, arg); break; } @@ -537,7 +537,7 @@ int motor_register(FAR const char *path, FAR struct motor_dev_s *dev, DEBUGASSERT(dev->ops->fault_set != NULL); DEBUGASSERT(dev->ops->state_get != NULL); DEBUGASSERT(dev->ops->fault_get != NULL); - DEBUGASSERT(dev->ops->fault_clean != NULL); + DEBUGASSERT(dev->ops->fault_clear != NULL); DEBUGASSERT(dev->ops->ioctl != NULL); /* Initialize the motor device structure */ diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 5c3cf0da778..38a19941805 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -334,56 +334,6 @@ config SMPS_HAVE_EFFICIENCY endif -config DRIVERS_MOTOR - bool "Motor driver" - default n - ---help--- - Enables building of a motor upper half driver. - -if DRIVERS_MOTOR - -config MOTOR_HAVE_POSITION - bool "Have position control" - default n - -config MOTOR_HAVE_DIRECTION - bool "Have direction control" - default n - -config MOTOR_HAVE_SPEED - bool "Have speed control" - default n - -config MOTOR_HAVE_TORQUE - bool "Have torque control (rotary motors)" - default n - -config MOTOR_HAVE_FORCE - bool "Have force control (linear motors)" - default n - -config MOTOR_HAVE_ACCELERATION - bool "Have acceleration control" - default n - -config MOTOR_HAVE_DECELERATION - bool "Have deceleration control" - default n - -config MOTOR_HAVE_INPUT_VOLTAGE - bool "Have input voltage protection" - default n - -config MOTOR_HAVE_INPUT_CURRENT - bool "Have input current protection" - default n - -config MOTOR_HAVE_INPUT_POWER - bool "Have input power protection" - default n - -endif - menuconfig POWER bool "Power Management Support" default n diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs index 48f6aaa147b..ed7698ff491 100644 --- a/drivers/power/Make.defs +++ b/drivers/power/Make.defs @@ -71,18 +71,6 @@ POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power} endif -# Add motor driver - -ifeq ($(CONFIG_DRIVERS_MOTOR),y) - -CSRCS += motor.c - -POWER_DEPPATH := --dep-path power -POWER_VPATH := :power -POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power} - -endif - # Add battery charger drivers ifeq ($(CONFIG_BATTERY_CHARGER),y) diff --git a/include/nuttx/power/motor.h b/include/nuttx/motor/motor.h similarity index 87% rename from include/nuttx/power/motor.h rename to include/nuttx/motor/motor.h index d2674853110..f1f5f5dff54 100644 --- a/include/nuttx/power/motor.h +++ b/include/nuttx/motor/motor.h @@ -1,5 +1,5 @@ /**************************************************************************** - * include/nuttx/power/motor.h + * include/nuttx/motor/motor.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __INCLUDE_NUTTX_DRIVERS_POWER_MOTOR_H -#define __INCLUDE_NUTTX_DRIVERS_POWER_MOTOR_H +#ifndef __INCLUDE_NUTTX_DRIVERS_MOTOR_MOTOR_H +#define __INCLUDE_NUTTX_DRIVERS_MOTOR_MOTOR_H /* The motor driver is split into two parts: * @@ -42,10 +42,10 @@ #include #include -#include +#include #include -#ifdef CONFIG_DRIVERS_MOTOR +#ifdef CONFIG_MOTOR_UPPER /**************************************************************************** * Pre-processor Definitions @@ -103,25 +103,25 @@ enum motor_direction_e struct motor_feedback_s { -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION float position; /* Current motor position */ #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED float speed; /* Current motor speed */ #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE float torque; /* Current motor torque (rotary motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE float force; /* Current motor force (linear motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_VOLTAGE +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_VOLTAGE float v_in; /* Current input voltage */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_CURRENT +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_CURRENT float i_in; /* Current input current */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_POWER +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_POWER float p_in; /* Current input power */ #endif }; @@ -145,31 +145,31 @@ struct motor_limits_s bool lock; /* This bit must be set after * limits configuration. */ -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION float position; /* Maximum motor position */ #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED float speed; /* Maximum motor speed */ #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE float torque; /* Maximum motor torque (rotary motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE float force; /* Maximum motor force (linear motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_ACCELERATION +#ifdef CONFIG_MOTOR_UPPER_HAVE_ACCELERATION float acceleration; /* Maximum motor acceleration */ #endif -#ifdef CONFIG_MOTOR_HAVE_DECELERATION +#ifdef CONFIG_MOTOR_UPPER_HAVE_DECELERATION float deceleration; /* Maximum motor decelaration */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_VOLTAGE +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_VOLTAGE float v_in; /* Maximum input voltage */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_CURRENT +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_CURRENT float i_in; /* Maximum input current */ #endif -#ifdef CONFIG_MOTOR_HAVE_INPUT_POWER +#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_POWER float p_in; /* Maximum input power */ #endif }; @@ -184,7 +184,7 @@ struct motor_params_s * if there is no need to change motor * parameter during run-time. */ -#ifdef CONFIG_MOTOR_HAVE_DIRECTION +#ifdef CONFIG_MOTOR_UPPER_HAVE_DIRECTION int8_t direction; /* Motor movement direction. We do not * support negative values for parameters, * so this flag can be used to allow movement @@ -192,22 +192,22 @@ struct motor_params_s * a given coordinate system. */ #endif -#ifdef CONFIG_MOTOR_HAVE_POSITION +#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION float position; /* Motor position */ #endif -#ifdef CONFIG_MOTOR_HAVE_SPEED +#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED float speed; /* Motor speed */ #endif -#ifdef CONFIG_MOTOR_HAVE_TORQUE +#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE float torque; /* Motor torque (rotary motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_FORCE +#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE float force; /* Motor force (linear motor) */ #endif -#ifdef CONFIG_MOTOR_HAVE_ACCELERATION +#ifdef CONFIG_MOTOR_UPPER_HAVE_ACCELERATION float acceleration; /* Motor acceleration */ #endif -#ifdef CONFIG_MOTOR_HAVE_DECELERATION +#ifdef CONFIG_MOTOR_UPPER_HAVE_DECELERATION float deceleration; /* Motor deceleration */ #endif }; @@ -268,15 +268,15 @@ struct motor_ops_s /* Get motor state */ CODE int (*state_get)(FAR struct motor_dev_s *dev, - FAR struct motor_state_s *state); + FAR struct motor_state_s *state); /* Get current fault state */ CODE int (*fault_get)(FAR struct motor_dev_s *dev, FAR uint8_t *fault); - /* Clean fault state */ + /* Clear fault state */ - CODE int (*fault_clean)(FAR struct motor_dev_s *dev, uint8_t fault); + CODE int (*fault_clear)(FAR struct motor_dev_s *dev, uint8_t fault); /* Lower-half logic may support platform-specific ioctl commands */ @@ -331,5 +331,5 @@ int motor_register(FAR const char *path, FAR struct motor_dev_s *dev, } #endif -#endif /* CONFIG_DRIVERS_MOTOR */ -#endif /* __INCLUDE_NUTTX_DRIVERS_POWER_MOTOR_H */ +#endif /* CONFIG_MOTOR_UPPER */ +#endif /* __INCLUDE_NUTTX_DRIVERS_MOTOR_MOTOR_H */ diff --git a/include/nuttx/motor/motor_ioctl.h b/include/nuttx/motor/motor_ioctl.h index 725c51c55e6..51220643f68 100644 --- a/include/nuttx/motor/motor_ioctl.h +++ b/include/nuttx/motor/motor_ioctl.h @@ -45,5 +45,9 @@ #define MTRIOC_SET_PARAMS _MTRIOC(5) #define MTRIOC_SET_CONFIG _MTRIOC(6) #define MTRIOC_GET_INFO _MTRIOC(7) +#define MTRIOC_SET_MODE _MTRIOC(8) +#define MTRIOC_SET_LIMITS _MTRIOC(9) +#define MTRIOC_SET_FAULT _MTRIOC(10) +#define MTRIOC_GET_FAULT _MTRIOC(11) #endif /* __INCLUDE_NUTTX_MOTOR_MOTOR_IOCTL_H */