Re: [PATCH 4/5] iio: mechanical: new HID sensor boolean switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07/08/2013 04:17 PM, Alexandre Relange wrote:
> Le 07/07/2013 17:36, Jonathan Cameron a écrit :
>> On 06/11/2013 03:52 PM, Alexandre Relange wrote:
>>> Implements the Boolean Switch sensor from the USB sensor usage
>>> tables http://www.usb.org/developers/hidpage/HUTRR39b.pdf
>>>
>>> This code is based on drivers/iio/light/hid-sensor-als.c
>>>
>>> Signed-off-by: Alexandre Relange <alexandre@xxxxxxxxxxx>
>>
>> Other than the issue of what to call this it mostly looks fine. But
>> what is hysterisis when applied to a mechanical switch?
> 
> Unfortunately, if the use is explicit (for reference, p124 generic field
> SENSITIVITY_ABS) the use case is NOT explicit. This is a generic field
> that is valid for every hid-sensor devices. Although, without more
> details in the standard, the behavior of this field will be vendor specific.
> As an example, I guess it could be used to set what are 'on' and 'off'
> states of a switch accord to the pressure on a button.
The wonders of over generalization.  This is downright silly and we
would want any thing like pressure on a button to be explicit, not
hidden behind a random term that really does not apply.

> 
>>
>>> --- drivers/iio/mechanical/Kconfig             |  14 ++
>>> drivers/iio/mechanical/Makefile            |   1 +
>>> drivers/iio/mechanical/hid-sensor-switch.c | 359
>>> +++++++++++++++++++++++++++++ include/linux/hid-sensor-ids.h
>>> |   4 + 4 files changed, 378 insertions(+) create mode 100644
>>> drivers/iio/mechanical/hid-sensor-switch.c
>>>
>>> diff --git a/drivers/iio/mechanical/Kconfig
>>> b/drivers/iio/mechanical/Kconfig index b536fa2..e449588 100644 ---
>>> a/drivers/iio/mechanical/Kconfig +++
>>> b/drivers/iio/mechanical/Kconfig @@ -3,4 +3,18 @@ # menu
>>> "Mechanical sensors"
>>>
>>> +config HID_SENSOR_SWITCH +    depends on HID_SENSOR_HUB +    select
>>> IIO_BUFFER +    select IIO_TRIGGERED_BUFFER +    select
>>> HID_SENSOR_IIO_COMMON +    select HID_SENSOR_IIO_TRIGGER +    tristate
>>> "HID Boolean Switch" +    help +      Say yes here to build support for
>>> the HID SENSOR +      Boolean Switch sensor. + +      This driver can
>>> also be built as a module.  If so, the module +      will be called
>>> hid-sensor-switch. + endmenu diff --git
>>> a/drivers/iio/mechanical/Makefile
>>> b/drivers/iio/mechanical/Makefile index 716098f..30931c5 100644 ---
>>> a/drivers/iio/mechanical/Makefile +++
>>> b/drivers/iio/mechanical/Makefile @@ -1,3 +1,4 @@ # # Makefile for
>>> IIO Mechanical sensors # +obj-$(CONFIG_HID_SENSOR_SWITCH)    +=
>>> hid-sensor-switch.o diff --git
>>> a/drivers/iio/mechanical/hid-sensor-switch.c
>>> b/drivers/iio/mechanical/hid-sensor-switch.c new file mode 100644
>>> index 0000000..7027305 --- /dev/null +++
>>> b/drivers/iio/mechanical/hid-sensor-switch.c @@ -0,0 +1,359 @@ +/*
>>> + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. +
>>> * Copyright (c) 2013, Alexandre Relange + * + * This program is
>>> free software; you can redistribute it and/or modify it + * under
>>> the terms and conditions of the GNU General Public License, + *
>>> version 2, as published by the Free Software Foundation. + * + *
>>> This program is distributed in the hope 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. + * + * You should
>>> have received a copy of the GNU General Public License along with +
>>> * this program; if not, write to the Free Software Foundation,
>>> Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>>> + * + */ +#include <linux/device.h> +#include
>>> <linux/platform_device.h> +#include <linux/module.h> +#include
>>> <linux/interrupt.h> +#include <linux/irq.h> +#include
>>> <linux/slab.h> +#include <linux/hid-sensor-hub.h> +#include
>>> <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include
>>> <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h>
>>> +#include <linux/iio/triggered_buffer.h> +#include
>>> "../common/hid-sensors/hid-sensor-trigger.h" + +/*Format:
>>> HID-SENSOR-usage_id_in_hex*/ +/*Usage ID from spec for
>>> Boolean-Switch: 0x200061*/ +#define DRIVER_NAME
>>> "HID-SENSOR-200061" + +#define CHANNEL_SCAN_INDEX_SWITCH 0 +
>>> +struct switch_state { +    struct hid_sensor_hub_callbacks
>>> callbacks; +    struct hid_sensor_common common_attributes; +    struct
>>> hid_sensor_hub_attribute_info switch_attr; +    u32 value; +}; + +/*
>>> Channel definitions */ +static const struct iio_chan_spec
>>> switch_channels[] = { +    { +        .type = IIO_STATE, +
>>> .info_mask_shared_by_type = +            BIT(IIO_CHAN_INFO_SAMP_FREQ) | +
>>> BIT(IIO_CHAN_INFO_HYSTERESIS), +        .scan_index =
>>> CHANNEL_SCAN_INDEX_SWITCH, +    } +}; + +/* Adjust channel real bits
>>> based on report descriptor */ +static void
>>> switch_adjust_channel_bit_mask(struct iio_chan_spec *channels, +
>>> int channel, int size) +{ +    channels[channel].scan_type.sign =
>>> 'u'; +    /* Real storage bits will change based on the report desc.
>>> */ +    channels[channel].scan_type.realbits = size * 8; +    /* Maximum
>>> size of a sample to capture is u32 */ +
>>> channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/*
>>> Channel read_raw handler */ +static int switch_read_raw(struct
>>> iio_dev *indio_dev, +                  struct iio_chan_spec const
> *chan, +
>>> int *val, int *val2, +                  long mask) +{ +    struct
> switch_state
>>> *switch_state = iio_priv(indio_dev); +    int report_id = -1; +    u32
>>> address; +    int ret; +    int ret_type; + +    *val = 0; +    *val2
> = 0; +
>>> switch (mask) { +    case IIO_CHAN_INFO_RAW: +        switch
>>> (chan->scan_index) { +        case  CHANNEL_SCAN_INDEX_SWITCH: +
>>> report_id = switch_state->switch_attr.report_id; +            address = +
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH_STATE; +            break; +   
>     default: +
>>> report_id = -1; +            break; +        } +        if (report_id
>> = 0) +            *val =
>>> sensor_hub_input_attr_get_raw_value( +
>>> switch_state->common_attributes.hsdev, +
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH, address, +               
> report_id); +
>>> else { +            *val = 0; +            return -EINVAL; +        }
> +        ret_type =
>>> IIO_VAL_INT; +        break; +    case IIO_CHAN_INFO_SAMP_FREQ: +   
>     ret =
>>> hid_sensor_read_samp_freq_value( +
>>> &switch_state->common_attributes, val, val2); +        ret_type =
>>> IIO_VAL_INT_PLUS_MICRO; +        break; +    case
> IIO_CHAN_INFO_HYSTERESIS:
>>> +        ret = hid_sensor_read_raw_hyst_value( +
>>> &switch_state->common_attributes, val, val2); +        ret_type =
>>> IIO_VAL_INT_PLUS_MICRO; +        break; +    default: +        ret_type =
>>> -EINVAL; +        break; +    } + +    return ret_type; +} + +/* Channel
>>> write_raw handler */ +static int switch_write_raw(struct iio_dev
>>> *indio_dev, +                   struct iio_chan_spec const *chan, +
>>> int val, +                   int val2, +                   long mask)
> +{ +    struct
>>> switch_state *switch_state = iio_priv(indio_dev); +    int ret = 0; +
>>> +    switch (mask) { +    case IIO_CHAN_INFO_SAMP_FREQ: +        ret =
>>> hid_sensor_write_samp_freq_value( +
>>> &switch_state->common_attributes, val, val2); +        break; +    case
>>> IIO_CHAN_INFO_HYSTERESIS: +        ret =
>>> hid_sensor_write_raw_hyst_value( +
>>> &switch_state->common_attributes, val, val2); +        break; +   
> default:
>>> +        ret = -EINVAL; +    } + +    return ret; +} + +static int
>>> switch_write_raw_get_fmt(struct iio_dev *indio_dev, +
>>> struct iio_chan_spec const *chan, +                   long mask) +{
> +    return
>>> IIO_VAL_INT_PLUS_MICRO; +} + +static const struct iio_info
>>> switch_info = { +    .driver_module = THIS_MODULE, +    .read_raw =
>>> &switch_read_raw, +    .write_raw = &switch_write_raw, +
>>> .write_raw_get_fmt = &switch_write_raw_get_fmt, +}; + +/* Function
>>> to push data to buffer */ +static void hid_sensor_push_data(struct
>>> iio_dev *indio_dev, u8 *data, int len) +{ +
>>> dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); +
>>> iio_push_to_buffers(indio_dev, (u8 *)data); +} + +/* Callback
>>> handler to send event after all samples are received and captured
>>> */ +static int switch_proc_event(struct hid_sensor_hub_device
>>> *hsdev, +                unsigned usage_id, +                void
> *priv) +{ +    struct
>>> iio_dev *indio_dev = platform_get_drvdata(priv); +    struct
>>> switch_state *switch_state = iio_priv(indio_dev); + +
>>> dev_dbg(&indio_dev->dev, "switch_proc_event [%d]\n", +
>>> switch_state->common_attributes.data_ready); +    if
>>> (switch_state->common_attributes.data_ready) +
>>> hid_sensor_push_data(indio_dev, +                (u8
> *)&switch_state->value, +
>>> sizeof(switch_state->value)); + +    return 0; +} + +/* Capture
>>> samples in local storage */ +static int
>>> switch_capture_sample(struct hid_sensor_hub_device *hsdev, +
>>> unsigned usage_id, +                size_t raw_len, char *raw_data,
> +                void
>>> *priv) +{ +    struct iio_dev *indio_dev =
>>> platform_get_drvdata(priv); +    struct switch_state *switch_state =
>>> iio_priv(indio_dev); +    int ret = -EINVAL; + +    switch (usage_id) { +
>>> case HID_USAGE_SENSOR_MECHA_BOOL_SWITCH_STATE: +
>>> switch_state->value = *(u32 *)raw_data; +        ret = 0; +       
> break; +
>>> default: +        break; +    } + +    return ret; +} + +/* Parse
> report which
>>> is specific to an usage id*/ +static int switch_parse_report(struct
>>> platform_device *pdev, +                struct hid_sensor_hub_device
> *hsdev, +
>>> struct iio_chan_spec *channels, +                unsigned usage_id,
> +                struct
>>> switch_state *st) +{ +    int ret; + +    ret =
>>> sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, +
>>> usage_id, +            HID_USAGE_SENSOR_MECHA_BOOL_SWITCH_STATE, +
>>> &st->switch_attr); +    if (ret < 0) +        return ret; +
>>> switch_adjust_channel_bit_mask(channels,
>>> CHANNEL_SCAN_INDEX_SWITCH, +                   
> st->switch_attr.size); + +
>>> dev_dbg(&pdev->dev, "switch %x:%x\n", st->switch_attr.index, +
>>> st->switch_attr.report_id); + +    return ret; +} + +/* Function to
>>> initialize the processing for usage id */ +static int
>>> hid_switch_probe(struct platform_device *pdev) +{ +    int ret = 0; +
>>> static const char *name = "switch"; +    struct iio_dev *indio_dev; +
>>> struct switch_state *switch_state; +    struct hid_sensor_hub_device
>>> *hsdev = pdev->dev.platform_data; +    struct iio_chan_spec
>>> *channels; + +    indio_dev = iio_device_alloc(sizeof(struct
>>> switch_state)); +    if (indio_dev == NULL) { +        ret = -ENOMEM; +
>>> goto error_ret; +    } +    platform_set_drvdata(pdev, indio_dev); + +
>>> switch_state = iio_priv(indio_dev); +
>>> switch_state->common_attributes.hsdev = hsdev; +
>>> switch_state->common_attributes.pdev = pdev; + +    ret =
>>> hid_sensor_parse_common_attributes(hsdev,
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH, +
>>> &switch_state->common_attributes); +    if (ret) { +
>>> dev_err(&pdev->dev, "failed to setup common attributes\n"); +        goto
>>> error_free_dev; +    } + +    channels = kmemdup(switch_channels,
>>> sizeof(switch_channels), GFP_KERNEL); +    if (!channels) { +       
> ret =
>>> -ENOMEM; +        dev_err(&pdev->dev, "failed to duplicate channels\n");
>>> +        goto error_free_dev; +    } + +    ret =
> switch_parse_report(pdev,
>>> hsdev, channels, +                HID_USAGE_SENSOR_MECHA_BOOL_SWITCH,
>>> switch_state); +    if (ret) { +        dev_err(&pdev->dev, "failed
> to setup
>>> attributes\n"); +        goto error_free_dev_mem; +    } + +
>>> indio_dev->channels = channels; +    indio_dev->num_channels = +
>>> ARRAY_SIZE(switch_channels); +    indio_dev->dev.parent = &pdev->dev;
>>> +    indio_dev->info = &switch_info; +    indio_dev->name = name; +
>>> indio_dev->modes = INDIO_DIRECT_MODE; + +    ret =
>>> iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, +
>>> NULL, NULL); +    if (ret) { +        dev_err(&pdev->dev, "failed to
>>> initialize trigger buffer\n"); +        goto error_free_dev_mem; +    } +
>>> switch_state->common_attributes.data_ready = false; +    ret =
>>> hid_sensor_setup_trigger(indio_dev, name, +
>>> &switch_state->common_attributes); +    if (ret < 0) { +
>>> dev_err(&pdev->dev, "trigger setup failed\n"); +        goto
>>> error_unreg_buffer_funcs; +    } + +    ret =
>>> iio_device_register(indio_dev); +    if (ret) { +       
> dev_err(&pdev->dev,
>>> "device register failed\n"); +        goto error_remove_trigger; +   
> } + +
>>> switch_state->callbacks.send_event = switch_proc_event; +
>>> switch_state->callbacks.capture_sample = switch_capture_sample; +
>>> switch_state->callbacks.pdev = pdev; +    ret =
>>> sensor_hub_register_callback(hsdev,
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH, +
>>> &switch_state->callbacks); +    if (ret < 0) { +       
> dev_err(&pdev->dev,
>>> "callback reg failed\n"); +        goto error_iio_unreg; +    } +
> +    return
>>> ret; + +error_iio_unreg: +    iio_device_unregister(indio_dev);
>>> +error_remove_trigger: +    hid_sensor_remove_trigger(indio_dev);
>>> +error_unreg_buffer_funcs: +
>>> iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: +
>>> kfree(indio_dev->channels); +error_free_dev: +
>>> iio_device_free(indio_dev); +error_ret: +    return ret; +} + +/*
>>> Function to deinitialize the processing for usage id */ +static int
>>> hid_switch_remove(struct platform_device *pdev) +{ +    struct
>>> hid_sensor_hub_device *hsdev = pdev->dev.platform_data; +    struct
>>> iio_dev *indio_dev = platform_get_drvdata(pdev); + +
>>> sensor_hub_remove_callback(hsdev,
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH); +
>>> iio_device_unregister(indio_dev); +
>>> hid_sensor_remove_trigger(indio_dev); +
>>> iio_triggered_buffer_cleanup(indio_dev); +
>>> kfree(indio_dev->channels); +    iio_device_free(indio_dev); + +
>>> return 0; +} + +static struct platform_driver
>>> hid_switch_platform_driver = { +    .driver = { +        .name    =
>>> DRIVER_NAME, +        .owner    = THIS_MODULE, +    }, +    .probe   
>     =
>>> hid_switch_probe, +    .remove        = hid_switch_remove, +};
>>> +module_platform_driver(hid_switch_platform_driver); +
>>> +MODULE_DESCRIPTION("HID Sensor Boolean Switch");
>>> +MODULE_AUTHOR("Alexandre Relange <alexandre@xxxxxxxxxxx>");
>>> +MODULE_LICENSE("GPL"); diff --git a/include/linux/hid-sensor-ids.h
>>> b/include/linux/hid-sensor-ids.h index 6f24446..e469078 100644 ---
>>> a/include/linux/hid-sensor-ids.h +++
>>> b/include/linux/hid-sensor-ids.h @@ -31,6 +31,10 @@ #define
>>> HID_USAGE_SENSOR_ALS                    0x200041 #define
>>> HID_USAGE_SENSOR_LIGHT_ILLUM                0x2004d1
>>>
>>> +/* MECHANICAL: Boolean Switch: (200061) */ +#define
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH            0x200061 +#define
>>> HID_USAGE_SENSOR_MECHA_BOOL_SWITCH_STATE        0x200491 + /* Gyro 3D:
>>> (200076) */ #define HID_USAGE_SENSOR_GYRO_3D                0x200076
> #define
>>> HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS            0x200457
>>>
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux