input/ff: support force feedback driver framework
Add new driver frameworks: force feedback for vibrator, like linux, unify vendor vibrator driver using. Incorporating a force feedback-based driving framework to replace the conventional driver/motor setup for controlling vibrators not only enhances the precision and responsiveness of the haptic feedback but also aligns better with the advancements in Linux-based driver systems. refs docs link: https://www.kernel.org/doc/html/v4.19/input/ff.html Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
00e878e848
commit
f65491ba44
|
@ -27,6 +27,10 @@ if(CONFIG_INPUT)
|
|||
list(APPEND SRCS touchscreen_upper.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_FF)
|
||||
list(APPEND SRCS ff_upper.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_MOUSE)
|
||||
list(APPEND SRCS mouse_upper.c)
|
||||
endif()
|
||||
|
|
|
@ -25,6 +25,13 @@ config INPUT_GOLDFISH_NBUFFER
|
|||
depends on INPUT_GOLDFISH_EVENTS
|
||||
default 8
|
||||
|
||||
config INPUT_FF
|
||||
bool "Support Force Feedback device"
|
||||
default n
|
||||
---help---
|
||||
Enable support for force feedback devices.
|
||||
The doc link: https://www.kernel.org/doc/html/v4.19/input/ff.html.
|
||||
|
||||
config INPUT_MOUSE
|
||||
bool
|
||||
default n
|
||||
|
|
|
@ -28,6 +28,10 @@ ifeq ($(CONFIG_INPUT_TOUCHSCREEN),y)
|
|||
CSRCS += touchscreen_upper.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_FF),y)
|
||||
CSRCS += ff_upper.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_MOUSE),y)
|
||||
CSRCS += mouse_upper.c
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,548 @@
|
|||
/****************************************************************************
|
||||
* drivers/input/ff_upper.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/input/ff.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ff_effect_s
|
||||
{
|
||||
struct ff_effect data;
|
||||
FAR struct file *owner;
|
||||
};
|
||||
|
||||
/* This structure is for force feedback device upper half driver */
|
||||
|
||||
struct ff_upperhalf_s
|
||||
{
|
||||
/* A pointer of lower half instance */
|
||||
|
||||
FAR struct ff_lowerhalf_s *lower;
|
||||
|
||||
/* Manages exclusive access to this structure */
|
||||
|
||||
mutex_t lock;
|
||||
|
||||
/* Maximum number of effects supported by device. */
|
||||
|
||||
int max_effects;
|
||||
|
||||
/* The pointer to an array of effects context currently loaded into device.
|
||||
* when file handle owning an effect gets closed the effect is
|
||||
* automatically erased.
|
||||
*/
|
||||
|
||||
FAR struct ff_effect_s *effects;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_open(FAR struct file *filep);
|
||||
static int ff_close(FAR struct file *filep);
|
||||
static ssize_t ff_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
static int ff_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct file_operations g_ff_fops =
|
||||
{
|
||||
ff_open, /* open */
|
||||
ff_close, /* close */
|
||||
NULL, /* read */
|
||||
ff_write, /* write */
|
||||
NULL, /* seek */
|
||||
ff_ioctl, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
NULL, /* truncate */
|
||||
NULL /* poll */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_check_effect_access
|
||||
*
|
||||
* Description:
|
||||
* Check that the effect_id is a valid effect and whether the user
|
||||
* is the owner.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_check_effect_access(FAR struct ff_upperhalf_s *upper,
|
||||
int effect_id, FAR struct file * filep)
|
||||
{
|
||||
if (effect_id < 0 || effect_id >= upper->max_effects ||
|
||||
upper->effects[effect_id].owner == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (filep != NULL && upper->effects[effect_id].owner != filep)
|
||||
{
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_check_effects_compatible
|
||||
*
|
||||
* Description:
|
||||
* Checks whether 2 effects can be combined together.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool ff_check_effects_compatible(FAR struct ff_effect *e1,
|
||||
FAR struct ff_effect *e2)
|
||||
{
|
||||
return e1->type == e2->type &&
|
||||
(e1->type != FF_PERIODIC ||
|
||||
e1->u.periodic.waveform == e2->u.periodic.waveform);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_compat_effect
|
||||
*
|
||||
* Description:
|
||||
* Convert an effect into compatible one.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_compat_effect(FAR struct ff_lowerhalf_s *lower,
|
||||
FAR struct ff_effect *effect)
|
||||
{
|
||||
switch (effect->type)
|
||||
{
|
||||
case FF_RUMBLE:
|
||||
{
|
||||
int magnitude;
|
||||
|
||||
if (!test_bit(FF_PERIODIC, lower->ffbit))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Calculate magnitude of sine wave as average of rumble's
|
||||
* 2/3 of strong magnitude and 1/3 of weak magnitude
|
||||
*/
|
||||
|
||||
magnitude = effect->u.rumble.strong_magnitude / 3 +
|
||||
effect->u.rumble.weak_magnitude / 6;
|
||||
|
||||
effect->type = FF_PERIODIC;
|
||||
effect->u.periodic.waveform = FF_SINE;
|
||||
effect->u.periodic.period = 50;
|
||||
effect->u.periodic.magnitude = magnitude;
|
||||
effect->u.periodic.offset = 0;
|
||||
effect->u.periodic.phase = 0;
|
||||
effect->u.periodic.envelope.attack_length = 0;
|
||||
effect->u.periodic.envelope.attack_level = 0;
|
||||
effect->u.periodic.envelope.fade_length = 0;
|
||||
effect->u.periodic.envelope.fade_level = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_erase_effect
|
||||
*
|
||||
* Description:
|
||||
* Erases the effect if the requester is also the effect owner. The mutex
|
||||
* should already be locked before calling this function.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_erase_effect(FAR struct ff_upperhalf_s *upper, int effect_id,
|
||||
FAR struct file *filep)
|
||||
{
|
||||
FAR struct ff_lowerhalf_s *lower = upper->lower;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
ret = ff_check_effect_access(upper, effect_id, filep);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
lower->playback(lower, effect_id, 0);
|
||||
leave_critical_section(flags);
|
||||
|
||||
upper->effects[effect_id].owner = NULL;
|
||||
if (lower->erase != NULL)
|
||||
{
|
||||
ret = lower->erase(lower, effect_id);
|
||||
if (ret < 0)
|
||||
{
|
||||
upper->effects[effect_id].owner = filep;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_upload
|
||||
*
|
||||
* Description:
|
||||
* Upload effect into force-feedback device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_upload(FAR struct ff_upperhalf_s *upper,
|
||||
FAR struct ff_effect *effect, FAR struct file *filep)
|
||||
{
|
||||
FAR struct ff_lowerhalf_s *lower = upper->lower;
|
||||
FAR struct ff_effect *old;
|
||||
int ret = 0;
|
||||
int id;
|
||||
|
||||
if (effect->type > FF_EFFECT_MAX)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (effect->type == FF_PERIODIC &&
|
||||
(effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
|
||||
effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
|
||||
!test_bit(effect->u.periodic.waveform, lower->ffbit)))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!test_bit(effect->type, lower->ffbit))
|
||||
{
|
||||
ret = ff_compat_effect(lower, effect);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect->id == -1)
|
||||
{
|
||||
for (id = 0; id < upper->max_effects; id++)
|
||||
{
|
||||
if (upper->effects[id].owner == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id >= upper->max_effects)
|
||||
{
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
effect->id = id;
|
||||
old = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = effect->id;
|
||||
ret = ff_check_effect_access(upper, id, filep);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
old = &upper->effects[id].data;
|
||||
if (!ff_check_effects_compatible(effect, old))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = lower->upload(lower, effect, old);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
upper->effects[id].data = *effect;
|
||||
upper->effects[id].owner = filep;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_open
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_open(FAR struct file *filep)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_close
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_close(FAR struct file *filep)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ff_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ff_upperhalf_s *upper = inode->i_private;
|
||||
FAR struct ff_event_s *event = (FAR struct ff_event_s *)buffer;
|
||||
|
||||
DEBUGASSERT(buflen == sizeof(*event));
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
ff_event(upper->lower, event->code, event->value);
|
||||
nxmutex_unlock(&upper->lock);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_ioctl
|
||||
****************************************************************************/
|
||||
|
||||
static int ff_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ff_upperhalf_s *upper = inode->i_private;
|
||||
int ret = OK;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
switch (cmd)
|
||||
{
|
||||
case EVIOCGBIT:
|
||||
{
|
||||
memcpy((FAR unsigned long *)(uintptr_t)arg, upper->lower->ffbit,
|
||||
sizeof(upper->lower->ffbit));
|
||||
}
|
||||
break;
|
||||
|
||||
case EVIOCSFF:
|
||||
{
|
||||
ret = ff_upload(upper, (FAR struct ff_effect *)(uintptr_t)arg,
|
||||
filep);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVIOCRMFF:
|
||||
{
|
||||
ret = ff_erase_effect(upper, (int)arg, filep);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVIOCGEFFECTS:
|
||||
{
|
||||
*(FAR int *)(uintptr_t)arg = upper->max_effects;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_event
|
||||
*
|
||||
* Description:
|
||||
* The lower half driver pushes force feedback events through this
|
||||
* interface, provided by force feedback upper half.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - lower half driver handle.
|
||||
* code - event code.
|
||||
* value - event value.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ff_event(FAR struct ff_lowerhalf_s *lower, uint32_t code, int value)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret = OK;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case FF_GAIN:
|
||||
{
|
||||
if (!test_bit(FF_GAIN, lower->ffbit) || value > 0xffffu)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
lower->set_gain(lower, value);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
break;
|
||||
|
||||
case FF_AUTOCENTER:
|
||||
{
|
||||
if (!test_bit(FF_AUTOCENTER, lower->ffbit) || value > 0xffffu)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
lower->set_autocenter(lower, value);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if (ff_check_effect_access(lower->priv, code, NULL) == 0)
|
||||
{
|
||||
flags = enter_critical_section();
|
||||
ret = lower->playback(lower, code, value);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_register
|
||||
*
|
||||
* Description:
|
||||
* This function registers a force feedback device, the upper half binds
|
||||
* with hardware device through the lower half instance.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - A pointer of lower half instance.
|
||||
* path - The path of force feedback device. such as "/dev/input_ff0".
|
||||
* max_effects - Maximum number of effects supported by device.
|
||||
*
|
||||
* Return:
|
||||
* OK if the driver was successfully registered; A negated errno value is
|
||||
* returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ff_register(FAR struct ff_lowerhalf_s *lower, FAR const char *path,
|
||||
int max_effects)
|
||||
{
|
||||
FAR struct ff_upperhalf_s *upper;
|
||||
int ret;
|
||||
|
||||
if (lower == NULL || max_effects == 0 || max_effects > FF_MAX_EFFECTS)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
upper = kmm_zalloc(sizeof(struct ff_upperhalf_s) +
|
||||
sizeof(struct ff_effect_s) * max_effects);
|
||||
if (upper == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
upper->lower = lower;
|
||||
lower->priv = upper;
|
||||
upper->max_effects = max_effects;
|
||||
upper->effects = (FAR struct ff_effect_s *)(upper + 1);
|
||||
nxmutex_init(&upper->lock);
|
||||
|
||||
ret = register_driver(path, &g_ff_fops, 0666, upper);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_destroy(&upper->lock);
|
||||
kmm_free(upper);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_unregister
|
||||
*
|
||||
* Description:
|
||||
* This function is used to force feedback driver to unregister and
|
||||
* release the occupied resources.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - A pointer to an insatnce of force feedback lower half driver.
|
||||
* path - The path of force feedback device. such as "/dev/input0"
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ff_unregister(FAR struct ff_lowerhalf_s *lower, FAR const char *path)
|
||||
{
|
||||
FAR struct ff_upperhalf_s *upper;
|
||||
|
||||
if (unregister_driver(path) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lower->destroy != NULL)
|
||||
{
|
||||
lower->destroy(lower);
|
||||
}
|
||||
|
||||
upper = lower->priv;
|
||||
nxmutex_destroy(&upper->lock);
|
||||
kmm_free(upper);
|
||||
}
|
|
@ -100,6 +100,7 @@
|
|||
#define _SYSLOGBASE (0x3c00) /* Syslog device ioctl commands */
|
||||
#define _STEPIOBASE (0x3d00) /* Stepper device ioctl commands */
|
||||
#define _FPGACFGBASE (0x3e00) /* FPGA configuration ioctl commands */
|
||||
#define _FFIOCBASE (0x3f00) /* Force feedback ioctl commands */
|
||||
#define _PCIBASE (0x4100) /* Pci ioctl commands */
|
||||
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
|
||||
|
||||
|
@ -724,6 +725,13 @@
|
|||
#define _PCIIOCVALID(c) (_IOC_TYPE(c)==_PCIBASE)
|
||||
#define _PCIIOC(nr) _IOC(_PCIBASE,nr)
|
||||
|
||||
/* Force Feedback driver command definitions ********************************/
|
||||
|
||||
/* see nuttx/include/input/ff.h */
|
||||
|
||||
#define _FFIOCVALID(c) (_IOC_TYPE(c)==_FFIOCBASE)
|
||||
#define _FFIOC(nr) _IOC(_FFIOCBASE,nr)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/input/ff.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_INPUT_FF_H
|
||||
#define __INCLUDE_NUTTX_INPUT_FF_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/bits.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Force feedback effect types. */
|
||||
|
||||
#define FF_RUMBLE 0x00
|
||||
#define FF_PERIODIC 0x01
|
||||
#define FF_CONSTANT 0x02
|
||||
#define FF_SPRING 0x03
|
||||
#define FF_FRICTION 0x04
|
||||
#define FF_DAMPER 0x05
|
||||
#define FF_INERTIA 0x06
|
||||
#define FF_RAMP 0x07
|
||||
|
||||
#define FF_EFFECT_MIN FF_RUMBLE
|
||||
#define FF_EFFECT_MAX FF_RAMP
|
||||
|
||||
/* Force feedback periodic effect types. */
|
||||
|
||||
#define FF_SQUARE 0x08
|
||||
#define FF_TRIANGLE 0x09
|
||||
#define FF_SINE 0x0a
|
||||
#define FF_SAW_UP 0x0b
|
||||
#define FF_SAW_DOWN 0x0c
|
||||
#define FF_CUSTOM 0x0d
|
||||
|
||||
#define FF_WAVEFORM_MIN FF_SQUARE
|
||||
#define FF_WAVEFORM_MAX FF_CUSTOM
|
||||
|
||||
/* Set ff device properties. */
|
||||
|
||||
#define FF_GAIN 0x0e
|
||||
#define FF_AUTOCENTER 0x0f
|
||||
|
||||
/* Total number of effects should never exceed FF_MAX_EFFECTS. */
|
||||
|
||||
#define FF_MAX_EFFECTS FF_GAIN
|
||||
|
||||
#define FF_MAX 0x1f
|
||||
#define FF_CNT (FF_MAX + 1)
|
||||
|
||||
/* Values describing the status of a force-feedback effect. */
|
||||
|
||||
#define FF_STATUS_STOPPED 0x00
|
||||
#define FF_STATUS_PLAYING 0x01
|
||||
#define FF_STATUS_MAX 0x01
|
||||
|
||||
/* IOCTL commands unique to the force feedback device */
|
||||
|
||||
/* This cmd use to querying device capabilities.
|
||||
* Arg: pointer to address of
|
||||
* "unsigned long features[BITS_TO_LONGS(FF_CNT)]".
|
||||
*/
|
||||
|
||||
#define EVIOCGBIT _FFIOC(0)
|
||||
|
||||
/* This cmd use to send a force effect to a force feedback device.
|
||||
* Arg: pointer to address of struct ff_effect.
|
||||
*/
|
||||
|
||||
#define EVIOCSFF _FFIOC(1)
|
||||
|
||||
/* This cmd use to erase a force effect.
|
||||
* Arg: int value, the effect id.
|
||||
*/
|
||||
|
||||
#define EVIOCRMFF _FFIOC(2)
|
||||
|
||||
/* This cmd use to report number of effects playable at the same time.
|
||||
* Arg: pointer to address of int value, return the number of effects.
|
||||
*/
|
||||
|
||||
#define EVIOCGEFFECTS _FFIOC(3)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Structures used in ioctls to upload effects to a device
|
||||
* They are pieces of a bigger structure (called ff_effect).
|
||||
*/
|
||||
|
||||
/* All duration values are expressed in ms. Values above 32767 ms (0x7fff)
|
||||
* should not be used and have unspecified results.
|
||||
*/
|
||||
|
||||
/* struct ff_replay - defines scheduling of the force-feedback effect */
|
||||
|
||||
struct ff_replay
|
||||
{
|
||||
/* Duration of the effect */
|
||||
|
||||
uint16_t length;
|
||||
|
||||
/* Delay before effect should start playing */
|
||||
|
||||
uint16_t delay;
|
||||
};
|
||||
|
||||
/* struct ff_trigger - defines what triggers the force-feedback effect */
|
||||
|
||||
struct ff_trigger
|
||||
{
|
||||
/* Number of the button triggering the effect */
|
||||
|
||||
uint16_t button;
|
||||
|
||||
/* Controls how soon the effect can be re-triggered */
|
||||
|
||||
uint16_t interval;
|
||||
};
|
||||
|
||||
/* struct ff_envelope - generic force-feedback effect envelope
|
||||
*
|
||||
* The attack_level and fade_level are absolute values; when applying
|
||||
* envelope force-feedback core will convert to positive/negative
|
||||
* value based on polarity of the default level of the effect.
|
||||
* Valid range for the attack and fade levels is 0x0000 - 0x7fff
|
||||
*/
|
||||
|
||||
struct ff_envelope
|
||||
{
|
||||
/* Duration of the attack (ms). */
|
||||
|
||||
uint16_t attack_length;
|
||||
|
||||
/* Level at the beginning of the attack. */
|
||||
|
||||
uint16_t attack_level;
|
||||
|
||||
/* Duration of fade (ms). */
|
||||
|
||||
uint16_t fade_length;
|
||||
|
||||
/* Level at the end of fade. */
|
||||
|
||||
uint16_t fade_level;
|
||||
};
|
||||
|
||||
/* struct ff_constant_effect - defines parameters of a constant
|
||||
* force-feedback effect.
|
||||
*/
|
||||
|
||||
struct ff_constant_effect
|
||||
{
|
||||
/* Strength of the effect; may be negative. */
|
||||
|
||||
int16_t level;
|
||||
|
||||
/* Envelope data. */
|
||||
|
||||
struct ff_envelope envelope;
|
||||
};
|
||||
|
||||
/* struct ff_ramp_effect - defines parameters of a ramp force-feedback
|
||||
* effect.
|
||||
*/
|
||||
|
||||
struct ff_ramp_effect
|
||||
{
|
||||
/* Beginning strength of the effect; may be negative. */
|
||||
|
||||
int16_t start_level;
|
||||
|
||||
/* Final strength of the effect; may be negative. */
|
||||
|
||||
int16_t end_level;
|
||||
|
||||
/* Envelope data. */
|
||||
|
||||
struct ff_envelope envelope;
|
||||
};
|
||||
|
||||
/* struct ff_condition_effect - defines a spring or friction force-feedback
|
||||
* effect
|
||||
*/
|
||||
|
||||
struct ff_condition_effect
|
||||
{
|
||||
/* Maximum level when joystick moved all way to the right. */
|
||||
|
||||
uint16_t right_saturation;
|
||||
|
||||
/* Same for the left side. */
|
||||
|
||||
uint16_t left_saturation;
|
||||
|
||||
/* Controls how fast the force grows when the joystick moves
|
||||
* to the right.
|
||||
*/
|
||||
|
||||
int16_t right_coeff;
|
||||
|
||||
/* Same for the left side */
|
||||
|
||||
int16_t left_coeff;
|
||||
|
||||
/* Size of the dead zone, where no force is produced */
|
||||
|
||||
uint16_t deadband;
|
||||
|
||||
/* Position of the dead zone */
|
||||
|
||||
int16_t center;
|
||||
};
|
||||
|
||||
/* struct ff_periodic_effect - defines parameters of a periodic
|
||||
* force-feedback effect.
|
||||
*
|
||||
* Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
|
||||
* FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
|
||||
* for the time being as no driver supports it yet.
|
||||
*
|
||||
* Note: the data pointed by custom_data is copied by the driver.
|
||||
* You can therefore dispose of the memory after the upload/update.
|
||||
*/
|
||||
|
||||
struct ff_periodic_effect
|
||||
{
|
||||
/* Kind of the effect (wave). */
|
||||
|
||||
uint16_t waveform;
|
||||
|
||||
/* Period of the wave (ms). */
|
||||
|
||||
uint16_t period;
|
||||
|
||||
/* Peak value. */
|
||||
|
||||
int16_t magnitude;
|
||||
|
||||
/* Mean value of the wave (roughly). */
|
||||
|
||||
int16_t offset;
|
||||
|
||||
/* 'horizontal' shift. */
|
||||
|
||||
uint16_t phase;
|
||||
|
||||
/* Envelope data. */
|
||||
|
||||
struct ff_envelope envelope;
|
||||
|
||||
/* Number of samples (FF_CUSTOM only). */
|
||||
|
||||
uint32_t custom_len;
|
||||
|
||||
/* Buffer of samples (FF_CUSTOM only). */
|
||||
|
||||
FAR int16_t *custom_data;
|
||||
};
|
||||
|
||||
/* struct ff_rumble_effect - defines parameters of a periodic
|
||||
* force-feedback effect
|
||||
*
|
||||
* Some rumble pads have two motors of different weight. Strong_magnitude
|
||||
* represents the magnitude of the vibration generated by the heavy one.
|
||||
*/
|
||||
|
||||
struct ff_rumble_effect
|
||||
{
|
||||
/* Magnitude of the heavy motor. */
|
||||
|
||||
uint16_t strong_magnitude;
|
||||
|
||||
/* Magnitude of the light one */
|
||||
|
||||
uint16_t weak_magnitude;
|
||||
};
|
||||
|
||||
/* struct ff_effect - defines force feedback effect
|
||||
* This structure is sent through ioctl from the application to the driver.
|
||||
* To create a new effect application should set its @id to -1; the kernel
|
||||
* will return assigned @id which can later be used to update or delete
|
||||
* this effect.
|
||||
*/
|
||||
|
||||
struct ff_effect
|
||||
{
|
||||
/* Type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
|
||||
* FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM).
|
||||
*/
|
||||
|
||||
uint16_t type;
|
||||
|
||||
/* An unique id assigned to an effect. */
|
||||
|
||||
int16_t id;
|
||||
|
||||
/* Direction of the effect is encoded as follows:
|
||||
* 0 deg -> 0x0000 (down)
|
||||
* 90 deg -> 0x4000 (left)
|
||||
* 180 deg -> 0x8000 (up)
|
||||
* 270 deg -> 0xC000 (right)
|
||||
*/
|
||||
|
||||
uint16_t direction;
|
||||
|
||||
/* Trigger conditions (struct ff_trigger). */
|
||||
|
||||
struct ff_trigger trigger;
|
||||
|
||||
/* Scheduling of the effect (struct ff_replay). */
|
||||
|
||||
struct ff_replay replay;
|
||||
|
||||
/* Effect-specific structure (one of ff_constant_effect,
|
||||
* ff_ramp_effect, ff_periodic_effect, ff_rumble_effect) further
|
||||
* defining effect parameters.
|
||||
*/
|
||||
|
||||
union
|
||||
{
|
||||
struct ff_constant_effect constant;
|
||||
struct ff_ramp_effect ramp;
|
||||
struct ff_periodic_effect periodic;
|
||||
struct ff_condition_effect condition[2];
|
||||
struct ff_rumble_effect rumble;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* The structure is used to description the event by userspace specified. */
|
||||
|
||||
struct ff_event_s
|
||||
{
|
||||
uint32_t code; /* Event code, eg: FF_GAIN, FF_AUTOCENTER, effect id */
|
||||
int value; /* Event value corresponding to Event code */
|
||||
};
|
||||
|
||||
/* struct ff_lowerhalf_s - force-feedback device lower half driver
|
||||
*
|
||||
* Every force-feedback device must implement upload() and playback()
|
||||
* methods; erase() is optional. set_gain() and set_autocenter() need
|
||||
* only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
|
||||
* bits.
|
||||
*
|
||||
* Note that playback(), set_gain() and set_autocenter() are called
|
||||
* with lock held and interrupts off and thus may not sleep.
|
||||
*/
|
||||
|
||||
struct ff_lowerhalf_s
|
||||
{
|
||||
/* Called to upload an new effect into device. */
|
||||
|
||||
CODE int (*upload)(FAR struct ff_lowerhalf_s *lower,
|
||||
FAR struct ff_effect *effect,
|
||||
FAR struct ff_effect *old);
|
||||
|
||||
/* Called to erase an effect from device. */
|
||||
|
||||
CODE int (*erase)(FAR struct ff_lowerhalf_s *lower, int effect_id);
|
||||
|
||||
/* Called to request device to start playing specified effect. */
|
||||
|
||||
CODE int (*playback)(FAR struct ff_lowerhalf_s *lower, int effect_id,
|
||||
int value);
|
||||
|
||||
/* Called to set specified gain. */
|
||||
|
||||
CODE void (*set_gain)(FAR struct ff_lowerhalf_s *lower, uint16_t gain);
|
||||
|
||||
/* Called to auto-center device. */
|
||||
|
||||
CODE void (*set_autocenter)(FAR struct ff_lowerhalf_s *lower,
|
||||
uint16_t magnitude);
|
||||
|
||||
/* Called by ff upper half when device is being destroyed. */
|
||||
|
||||
CODE void (*destroy)(FAR struct ff_lowerhalf_s *lower);
|
||||
|
||||
/* The bitmap of force feedback capabilities truly supported by device */
|
||||
|
||||
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
|
||||
|
||||
/* The private opaque pointer to be passed to upper-layer during callback */
|
||||
|
||||
FAR void *priv;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_event
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_event
|
||||
*
|
||||
* Description:
|
||||
* The lower half driver pushes force feedback events through this
|
||||
* interface, provided by force feedback upper half.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - lower half driver handle.
|
||||
* code - event code.
|
||||
* value - event value.
|
||||
*
|
||||
* Return:
|
||||
* OK if the driver was successfully process event; A negated errno value
|
||||
* is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ff_event(FAR struct ff_lowerhalf_s *lower, uint32_t code, int value);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_register
|
||||
*
|
||||
* Description:
|
||||
* This function registers a force feedback device, the upper half binds
|
||||
* with hardware device through the lower half instance.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - A pointer of lower half instance.
|
||||
* path - The path of force feedback device. such as "/dev/input0".
|
||||
* max_effects - Maximum number of effects supported by device.
|
||||
*
|
||||
* Return:
|
||||
* OK if the driver was successfully registered; A negated errno value is
|
||||
* returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ff_register(FAR struct ff_lowerhalf_s *lower, FAR const char *path,
|
||||
int max_effects);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ff_unregister
|
||||
*
|
||||
* Description:
|
||||
* This function is used to force feedback driver to unregister and
|
||||
* release the occupied resources.
|
||||
*
|
||||
* Arguments:
|
||||
* lower - A pointer to an insatnce of force feedback lower half driver.
|
||||
* path - The path of force feedback device. such as "/dev/input0"
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ff_unregister(FAR struct ff_lowerhalf_s *lower, FAR const char *path);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_INPUT_FF_H */
|
Loading…
Reference in New Issue