From: Simon Wood <simon-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> To: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Cc: Frank Praznik <frank.praznik-oKii7tqusJgAvxtiuMwx3w@public.gmane.org>, linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Simon Wood <simon-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> Subject: [RFC] HID: hid-sony: Add basic iio-subsystem reading of SixAxis Accelerometers Date: Thu, 11 Jun 2015 08:54:18 -0600 [thread overview] Message-ID: <1434034458-1968-1-git-send-email-simon@mungewell.org> (raw) In-Reply-To: <195dff9bd065db7e618280cb7c6eb5a9.squirrel-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> [resent as I screwed up addressing... sorry] This patch is a RFC/POC for the idea of using the iio-subsystem as the 'proper' way to communicate the state of motion enabled controllers to the Linux internals. I have started with the hid-sony driver, with support for the SixAxis's 3 Accelerometers. Proper trigger/buffer support will follow shortly, along with support for the DS4 and PSMove controllers (which have a much more extensive set of motion hardware). Once the sensor data is available (over iio) I envision that it will be considerably easier to write motion tracking, flight control and AHRS software in a consistant manner. Hopefully this will become the standard way of connecting controllers, motion controls and head mounted displays. --- drivers/hid/hid-sony.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6ca96ce..79afae6 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -36,6 +36,7 @@ #include <linux/list.h> #include <linux/idr.h> #include <linux/input/mt.h> +#include <linux/iio/iio.h> #include "hid-ids.h" @@ -54,6 +55,7 @@ DUALSHOCK4_CONTROLLER) #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) +#define SONY_IIO_SUPPORT SIXAXIS_CONTROLLER #define MAX_LEDS 4 @@ -835,6 +837,23 @@ struct sony_sc { __u8 led_delay_on[MAX_LEDS]; __u8 led_delay_off[MAX_LEDS]; __u8 led_count; + +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + struct iio_dev *indio_dev; + __u16 last_acc[3]; + __u16 last_gyro[3]; +}; + +enum sony_iio_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +struct sony_iio { + struct sony_sc *sc; +#endif }; static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -1047,6 +1066,12 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, swap(rd[45], rd[46]); swap(rd[47], rd[48]); +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + sc->last_acc[0] = (rd[42] << 8) + rd[41]; + sc->last_acc[1] = (rd[44] << 8) + rd[43]; + sc->last_acc[2] = (rd[46] << 8) + rd[45]; +#endif sixaxis_parse_report(sc, rd, size); } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) @@ -1769,6 +1794,136 @@ static void sony_battery_remove(struct sony_sc *sc) sc->battery_desc.name = NULL; } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + +static int sony_iio_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct sony_iio *data = iio_priv(indio_dev); + int ret; + u32 temp; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_ACCEL: + *val = data->sc->last_acc[chan->scan_index]; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = data->sc->last_gyro[chan->scan_index]; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ACCEL: + *val = 1; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = 1; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_ACCEL: + *val = 512; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = 512; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +#define SONY_ACC_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = AXIS_##_axis, \ +} + +#define SONY_GYRO_CHANNEL(_axis) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = AXIS_##_axis, \ +} + +static const struct iio_chan_spec sony_sixaxis_channels[] = { + SONY_ACC_CHANNEL(X), + SONY_ACC_CHANNEL(Y), + SONY_ACC_CHANNEL(Z), +}; + +static const struct iio_info sony_iio_info = { + .read_raw = &sony_iio_read_raw, + .driver_module = THIS_MODULE, +}; + +static int sony_iio_probe(struct sony_sc *sc) +{ + struct hid_device *hdev = sc->hdev; + struct iio_dev *indio_dev; + struct sony_iio *data; + int ret; + + indio_dev = iio_device_alloc(sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + sc->indio_dev = indio_dev; + data = iio_priv(indio_dev); + data->sc = sc; + + indio_dev->dev.parent = &hdev->dev; + indio_dev->name = dev_name(&hdev->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &sony_iio_info; + indio_dev->channels = sony_sixaxis_channels; + indio_dev->num_channels = 3; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + hid_err(hdev, "Unable to register iio device\n"); + goto error_iio_probe; + } + return 0; + +error_iio_probe: + kfree(indio_dev); + sc->indio_dev = NULL; + return ret; +} + +static void sony_iio_remove(struct sony_sc *sc) +{ + if (!sc->indio_dev) + return; + + iio_device_unregister(sc->indio_dev); + kfree(sc->indio_dev); + sc->indio_dev = NULL; +} +#endif + /* * If a controller is plugged in via USB while already connected via Bluetooth * it will show up as two devices. A global list of connected controllers and @@ -2073,6 +2228,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) { + ret = sony_iio_probe(sc); + if (ret < 0) + goto err_stop; + } +#endif + if (sc->quirks & SONY_FF_SUPPORT) { ret = sony_init_ff(sc); if (ret < 0) @@ -2087,6 +2251,11 @@ err_stop: sony_leds_remove(sc); if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) + sony_iio_remove(sc); +#endif sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); sony_remove_dev_list(sc); @@ -2107,6 +2276,12 @@ static void sony_remove(struct hid_device *hdev) sony_battery_remove(sc); } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) + sony_iio_remove(sc); +#endif + sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); -- 2.1.4
WARNING: multiple messages have this Message-ID (diff)
From: Simon Wood <simon@mungewell.org> To: linux-input@vger.kernel.org Cc: Frank Praznik <frank.praznik@oh.rr.com>, linux-iio@vger.kernel.org, Simon Wood <simon@mungewell.org> Subject: [RFC] HID: hid-sony: Add basic iio-subsystem reading of SixAxis Accelerometers Date: Thu, 11 Jun 2015 08:54:18 -0600 [thread overview] Message-ID: <1434034458-1968-1-git-send-email-simon@mungewell.org> (raw) In-Reply-To: <195dff9bd065db7e618280cb7c6eb5a9.squirrel@mungewell.org> [resent as I screwed up addressing... sorry] This patch is a RFC/POC for the idea of using the iio-subsystem as the 'proper' way to communicate the state of motion enabled controllers to the Linux internals. I have started with the hid-sony driver, with support for the SixAxis's 3 Accelerometers. Proper trigger/buffer support will follow shortly, along with support for the DS4 and PSMove controllers (which have a much more extensive set of motion hardware). Once the sensor data is available (over iio) I envision that it will be considerably easier to write motion tracking, flight control and AHRS software in a consistant manner. Hopefully this will become the standard way of connecting controllers, motion controls and head mounted displays. --- drivers/hid/hid-sony.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6ca96ce..79afae6 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -36,6 +36,7 @@ #include <linux/list.h> #include <linux/idr.h> #include <linux/input/mt.h> +#include <linux/iio/iio.h> #include "hid-ids.h" @@ -54,6 +55,7 @@ DUALSHOCK4_CONTROLLER) #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) +#define SONY_IIO_SUPPORT SIXAXIS_CONTROLLER #define MAX_LEDS 4 @@ -835,6 +837,23 @@ struct sony_sc { __u8 led_delay_on[MAX_LEDS]; __u8 led_delay_off[MAX_LEDS]; __u8 led_count; + +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + struct iio_dev *indio_dev; + __u16 last_acc[3]; + __u16 last_gyro[3]; +}; + +enum sony_iio_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +struct sony_iio { + struct sony_sc *sc; +#endif }; static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -1047,6 +1066,12 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, swap(rd[45], rd[46]); swap(rd[47], rd[48]); +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + sc->last_acc[0] = (rd[42] << 8) + rd[41]; + sc->last_acc[1] = (rd[44] << 8) + rd[43]; + sc->last_acc[2] = (rd[46] << 8) + rd[45]; +#endif sixaxis_parse_report(sc, rd, size); } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) @@ -1769,6 +1794,136 @@ static void sony_battery_remove(struct sony_sc *sc) sc->battery_desc.name = NULL; } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + +static int sony_iio_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct sony_iio *data = iio_priv(indio_dev); + int ret; + u32 temp; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_ACCEL: + *val = data->sc->last_acc[chan->scan_index]; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = data->sc->last_gyro[chan->scan_index]; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ACCEL: + *val = 1; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = 1; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_ACCEL: + *val = 512; + return IIO_VAL_INT; + case IIO_ANGL_VEL: + *val = 512; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +#define SONY_ACC_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = AXIS_##_axis, \ +} + +#define SONY_GYRO_CHANNEL(_axis) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = AXIS_##_axis, \ +} + +static const struct iio_chan_spec sony_sixaxis_channels[] = { + SONY_ACC_CHANNEL(X), + SONY_ACC_CHANNEL(Y), + SONY_ACC_CHANNEL(Z), +}; + +static const struct iio_info sony_iio_info = { + .read_raw = &sony_iio_read_raw, + .driver_module = THIS_MODULE, +}; + +static int sony_iio_probe(struct sony_sc *sc) +{ + struct hid_device *hdev = sc->hdev; + struct iio_dev *indio_dev; + struct sony_iio *data; + int ret; + + indio_dev = iio_device_alloc(sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + sc->indio_dev = indio_dev; + data = iio_priv(indio_dev); + data->sc = sc; + + indio_dev->dev.parent = &hdev->dev; + indio_dev->name = dev_name(&hdev->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &sony_iio_info; + indio_dev->channels = sony_sixaxis_channels; + indio_dev->num_channels = 3; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + hid_err(hdev, "Unable to register iio device\n"); + goto error_iio_probe; + } + return 0; + +error_iio_probe: + kfree(indio_dev); + sc->indio_dev = NULL; + return ret; +} + +static void sony_iio_remove(struct sony_sc *sc) +{ + if (!sc->indio_dev) + return; + + iio_device_unregister(sc->indio_dev); + kfree(sc->indio_dev); + sc->indio_dev = NULL; +} +#endif + /* * If a controller is plugged in via USB while already connected via Bluetooth * it will show up as two devices. A global list of connected controllers and @@ -2073,6 +2228,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) { + ret = sony_iio_probe(sc); + if (ret < 0) + goto err_stop; + } +#endif + if (sc->quirks & SONY_FF_SUPPORT) { ret = sony_init_ff(sc); if (ret < 0) @@ -2087,6 +2251,11 @@ err_stop: sony_leds_remove(sc); if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) + sony_iio_remove(sc); +#endif sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); sony_remove_dev_list(sc); @@ -2107,6 +2276,12 @@ static void sony_remove(struct hid_device *hdev) sony_battery_remove(sc); } +#if IS_BUILTIN(CONFIG_IIO) || \ + (IS_MODULE(CONFIG_IIO) && IS_MODULE(CONFIG_HID_SONY)) + if (sc->quirks & SONY_IIO_SUPPORT) + sony_iio_remove(sc); +#endif + sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); -- 2.1.4
next prev parent reply other threads:[~2015-06-11 14:54 UTC|newest] Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top 2015-06-08 15:41 Handling Controllers with Acc/Gyro/Mag via HID system simon 2015-06-08 22:43 ` Frank Praznik 2015-06-11 14:48 ` [RFC] HID: hid-sony: Add basic iio-subsystem reading of SixAxis Accelerometers Simon Wood [not found] ` <195dff9bd065db7e618280cb7c6eb5a9.squirrel-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> 2015-06-11 14:54 ` Simon Wood [this message] 2015-06-11 14:54 ` Simon Wood 2015-06-11 15:07 ` Bastien Nocera 2015-06-14 14:53 ` Jonathan Cameron 2015-06-14 17:25 ` simon [not found] ` <d6702f5d19d2baea80132666fcf7654a.squirrel-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> 2015-06-14 17:57 ` Jonathan Cameron 2015-06-14 17:57 ` Jonathan Cameron 2015-06-15 18:14 ` Srinivas Pandruvada [not found] ` <1434392064.2353.77.camel-hINH/TbAiWqaJgj69oe+EDMJUdESFZ8XQQ4Iyu8u01E@public.gmane.org> 2015-06-21 13:16 ` Jonathan Cameron 2015-06-21 13:16 ` Jonathan Cameron 2015-06-18 6:15 ` simon [not found] ` <a740eca098128c7a830db825d7c0288c.squirrel-wM4F9T/ekXmXDw4h08c5KA@public.gmane.org> 2015-06-21 13:12 ` Jonathan Cameron 2015-06-21 13:12 ` Jonathan Cameron
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1434034458-1968-1-git-send-email-simon@mungewell.org \ --to=simon-wm4f9t/ekxmxdw4h08c5ka@public.gmane.org \ --cc=frank.praznik-oKii7tqusJgAvxtiuMwx3w@public.gmane.org \ --cc=linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.