Commit def7cb8c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging tree update from Greg Kroah-Hartman:
 "Here is the big staging tree update for the 3.7-rc1 merge window.

  There are a few patches in here that are outside of the staging area,
  namely HID and IIO patches, but all of them have been acked by the
  relevant subsystem maintainers.  The IIO stuff is still coming in
  through this tree as it hasn't entirely moved out of the staging tree,
  but is almost there.

  Other than that, there wa a ton of work on the comedi drivers to make
  them more readable and the correct style.  Doing that removed a lot of
  code, but we added a new driver to the staging tree, so we didn't end
  up with a net reduction this time around:

   662 files changed, 51649 insertions(+), 26582 deletions(-)

  All of these patches have been in the linux-next tree already.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1094 commits)
  staging: comedi: jr3_pci: fix iomem dereference
  staging: comedi: drivers: use comedi_fc.h cmdtest helpers
  Staging: winbond: usb_free_urb(NULL) is safe
  Staging: winbond: checkpatch cleanup
  Staging: winbond: Removed undesired spaces, lines and tabs
  Staging: winbond: Typo corrections in comments
  Staging: winbond: Changed c99 comments to c89 comments
  staging: r8712u: Do not queue cloned skb
  staging: comedi: ni_mio_common: always lock in ni_ai_poll()
  staging: comedi: s626: add FIXME comment
  staging: comedi: s626: don't dereference insn->data
  staging: comedi: s526: fix if() check in s526_gpct_winsn()
  staging: comedi: s626: cleanup comments in s626_initialize()
  staging: comedi: s626: remove clear of kzalloc'ed data
  staging: comedi: s626: remove 'WDInterval' from private data
  staging: comedi: s626: remove 'ChargeEnabled' from private data
  staging: comedi: s626: remove 'IsBoardRevA' comment
  staging: comedi: s626: #if 0 out the "SAA7146 BUG WORKAROUND"
  staging: comedi: s626: remove 'allocatedBuf' from private data
  staging: comedi: s626: add final attach message
  ...
parents 06d2fe15 e1878957
* Freescale i.MX28 LRADC device driver
Required properties:
- compatible: Should be "fsl,imx28-lradc"
- reg: Address and length of the register set for the device
- interrupts: Should contain the LRADC interrupts
Examples:
lradc@80050000 {
compatible = "fsl,imx28-lradc";
reg = <0x80050000 0x2000>;
interrupts = <10 14 15 16 17 18 19
20 21 22 23 24 25>;
};
Freescale i.MX IPUv3
====================
Required properties:
- compatible: Should be "fsl,<chip>-ipu"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain sync interrupt and error interrupt,
in this order.
- #crtc-cells: 1, See below
example:
ipu: ipu@18000000 {
#crtc-cells = <1>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
};
Parallel display support
========================
Required properties:
- compatible: Should be "fsl,imx-parallel-display"
- crtc: the crtc this display is connected to, see below
Optional properties:
- interface_pix_fmt: How this display is connected to the
crtc. Currently supported types: "rgb24", "rgb565"
- edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data
channel
example:
display@di0 {
compatible = "fsl,imx-parallel-display";
edid = [edid-data];
crtc = <&ipu 0>;
interface-pix-fmt = "rgb24";
};
HID Sensors Framework
======================
HID sensor framework provides necessary interfaces to implement sensor drivers,
which are connected to a sensor hub. The sensor hub is a HID device and it provides
a report descriptor conforming to HID 1.12 sensor usage tables.
Description from the HID 1.12 "HID Sensor Usages" specification:
"Standardization of HID usages for sensors would allow (but not require) sensor
hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
thereby enabling some operating systems to incorporate common device drivers that
could be reused between vendors, alleviating any need for the vendors to provide
the drivers themselves."
This specification describes many usage IDs, which describe the type of sensor
and also the individual data fields. Each sensor can have variable number of
data fields. The length and order is specified in the report descriptor. For
example a part of report descriptor can look like:
INPUT(1)[INPUT]
..
Field(2)
Physical(0020.0073)
Usage(1)
0020.045f
Logical Minimum(-32767)
Logical Maximum(32767)
Report Size(8)
Report Count(1)
Report Offset(16)
Flags(Variable Absolute)
..
..
The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
This accelerometer-3D has some fields. Here for example field 2 is motion intensity
(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
order of fields and length of each field is important as the input event raw
data will use this format.
Implementation
=================
This specification defines many different types of sensors with different sets of
data fields. It is difficult to have a common input event to user space applications,
for different sensors. For example an accelerometer can send X,Y and Z data, whereas
an ambient light sensor can send illumination data.
So the implementation has two parts:
- Core hid driver
- Individual sensor processing part (sensor drivers)
Core driver
-----------
The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
report descriptors and identifies all the sensors present. It adds an MFD device
with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
For example
HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
So if any driver with this name is inserted, then the probe routine for that
function will be called. So an accelerometer processing driver can register
with this name and will be probed if there is an accelerometer-3D detected.
The core driver provides a set of APIs which can be used by the processing
drivers to register and get events for that usage id. Also it provides parsing
functions, which get and set each input/feature/output report.
Individual sensor processing part (sensor drivers)
-----------
The processing driver will use an interface provided by the core driver to parse
the report and get the indexes of the fields and also can get events. This driver
can use IIO interface to use the standard ABI defined for a type of sensor.
Core driver Interface
=====================
Callback structure:
Each processing driver can use this structure to set some callbacks.
int (*suspend)(..): Callback when HID suspend is received
int (*resume)(..): Callback when HID resume is received
int (*capture_sample)(..): Capture a sample for one of its data fields
int (*send_event)(..): One complete event is received which can have
multiple data fields.
Registration functions:
int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_hub_callbacks *usage_callback):
Registers callbacks for an usage id. The callback functions are not allowed
to sleep.
int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id):
Removes callbacks for an usage id.
Parsing function:
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
u8 type,
u32 usage_id, u32 attr_usage_id,
struct hid_sensor_hub_attribute_info *info);
A processing driver can look for some field of interest and check if it exists
in a report descriptor. If it exists it will store necessary information
so that fields can be set or get individually.
These indexes avoid searching every time and getting field index to get or set.
Set Feature report
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 value);
This interface is used to set a value for a field in feature report. For example
if there is a field report_interval, which is parsed by a call to
sensor_hub_input_get_attribute_info before, then it can directly set that individual
field.
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 *value);
This interface is used to get a value for a field in input report. For example
if there is a field report_interval, which is parsed by a call to
sensor_hub_input_get_attribute_info before, then it can directly get that individual
field value.
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
u32 attr_usage_id, u32 report_id);
This is used to get a particular field value through input reports. For example
accelerometer wants to poll X axis value, then it can call this function with
the usage id of X axis. HID sensors can provide events, so this is not necessary
to poll for any field. If there is some new sample, the core driver will call
registered callback function to process the sample.
......@@ -708,6 +708,20 @@ config HID_ZYDACRON
---help---
Support for Zydacron remote control.
config HID_SENSOR_HUB
tristate "HID Sensors framework support"
depends on USB_HID
select MFD_CORE
default n
-- help---
Support for HID Sensor framework. This creates a MFD instance
for a sensor hub and identifies all the sensors connected to it.
Each sensor is registered as a MFD cell, so that sensor specific
processing can be done in a separate driver. Each sensor
drivers can use the service provided by this driver to register
for events and handle data streams. Each sensor driver can format
data and present to user mode using input or IIO interface.
endmenu
endif # HID
......
......@@ -112,6 +112,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
......
......@@ -1568,6 +1568,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
......@@ -1665,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
......
......@@ -429,6 +429,11 @@
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
#define USB_VENDOR_ID_INTEL_8086 0x8086
#define USB_VENDOR_ID_INTEL_8087 0x8087
#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
......@@ -706,6 +711,7 @@
#define USB_VENDOR_ID_STANTUM_STM 0x0483
#define USB_DEVICE_ID_MTP_STM 0x3261
#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
......
/*
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*
* 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/hid.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/list.h>
#include <linux/hid-sensor-ids.h>
#include <linux/hid-sensor-hub.h>
#include "hid-ids.h"
/**
* struct sensor_hub_pending - Synchronous read pending information
* @status: Pending status true/false.
* @ready: Completion synchronization data.
* @usage_id: Usage id for physical device, E.g. Gyro usage id.
* @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
* @raw_size: Response size for a read request.
* @raw_data: Place holder for received response.
*/
struct sensor_hub_pending {
bool status;
struct completion ready;
u32 usage_id;
u32 attr_usage_id;
int raw_size;
u8 *raw_data;
};
/**
* struct sensor_hub_data - Hold a instance data for a HID hub device
* @hsdev: Stored hid instance for current hub device.
* @mutex: Mutex to serialize synchronous request.
* @lock: Spin lock to protect pending request structure.
* @pending: Holds information of pending sync read request.
* @dyn_callback_list: Holds callback function
* @dyn_callback_lock: spin lock to protect callback list
* @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance.
* @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached).
*/
struct sensor_hub_data {
struct hid_sensor_hub_device *hsdev;
struct mutex mutex;
spinlock_t lock;
struct sensor_hub_pending pending;
struct list_head dyn_callback_list;
spinlock_t dyn_callback_lock;
struct mfd_cell *hid_sensor_hub_client_devs;
int hid_sensor_client_cnt;
};
/**
* struct hid_sensor_hub_callbacks_list - Stores callback list
* @list: list head.
* @usage_id: usage id for a physical device.
* @usage_callback: Stores registered callback functions.
* @priv: Private data for a physical device.
*/
struct hid_sensor_hub_callbacks_list {
struct list_head list;
u32 usage_id;
struct hid_sensor_hub_callbacks *usage_callback;
void *priv;
};
static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
{
int i;
int ret = -EINVAL;
for (i = 0; i < hdev->maxcollection; i++) {
struct hid_collection *col = &hdev->collection[i];
if (col->type == HID_COLLECTION_PHYSICAL &&
(col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
ret = 0;
break;
}
}
return ret;
}
static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
int dir)
{
struct hid_report *report;
list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) {
if (report->id == id)
return report;
}
hid_warn(hdev, "No report with id 0x%x found\n", id);
return NULL;
}
static int sensor_hub_get_physical_device_count(
struct hid_report_enum *report_enum)
{
struct hid_report *report;
struct hid_field *field;
int cnt = 0;
list_for_each_entry(report, &report_enum->report_list, list) {
field = report->field[0];
if (report->maxfield && field &&
field->physical)
cnt++;
}
return cnt;
}
static void sensor_hub_fill_attr_info(
struct hid_sensor_hub_attribute_info *info,
s32 index, s32 report_id, s32 units, s32 unit_expo, s32 size)
{
info->index = index;
info->report_id = report_id;
info->units = units;
info->unit_expo = unit_expo;
info->size = size/8;
}
static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
struct hid_device *hdev,
u32 usage_id, void **priv)
{
struct hid_sensor_hub_callbacks_list *callback;
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
if (callback->usage_id == usage_id) {
*priv = callback->priv;
spin_unlock(&pdata->dyn_callback_lock);
return callback->usage_callback;
}
spin_unlock(&pdata->dyn_callback_lock);
return NULL;
}
int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_hub_callbacks *usage_callback)
{
struct hid_sensor_hub_callbacks_list *callback;
struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
if (callback->usage_id == usage_id) {
spin_unlock(&pdata->dyn_callback_lock);
return -EINVAL;
}
callback = kzalloc(sizeof(*callback), GFP_ATOMIC);
if (!callback) {
spin_unlock(&pdata->dyn_callback_lock);
return -ENOMEM;
}
callback->usage_callback = usage_callback;
callback->usage_id = usage_id;
callback->priv = NULL;
list_add_tail(&callback->list, &pdata->dyn_callback_list);
spin_unlock(&pdata->dyn_callback_lock);
return 0;
}
EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
u32 usage_id)
{
struct hid_sensor_hub_callbacks_list *callback;
struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
spin_lock(&pdata->dyn_callback_lock);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
if (callback->usage_id == usage_id) {
list_del(&callback->list);
kfree(callback);
break;
}
spin_unlock(&pdata->dyn_callback_lock);
return 0;
}
EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 value)
{
struct hid_report *report;
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
int ret = 0;
mutex_lock(&data->mutex);
report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
if (!report || (field_index >= report->maxfield)) {
ret = -EINVAL;
goto done_proc;
}
hid_set_field(report->field[field_index], 0, value);
usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
usbhid_wait_io(hsdev->hdev);
done_proc:
mutex_unlock(&data->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 *value)
{
struct hid_report *report;
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
int ret = 0;
mutex_lock(&data->mutex);
report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
if (!report || (field_index >= report->maxfield)) {
ret = -EINVAL;
goto done_proc;
}
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
usbhid_wait_io(hsdev->hdev);
*value = report->field[field_index]->value[0];
done_proc:
mutex_unlock(&data->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
u32 attr_usage_id, u32 report_id)
{
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
unsigned long flags;
struct hid_report *report;
int ret_val = 0;
mutex_lock(&data->mutex);
memset(&data->pending, 0, sizeof(data->pending));
init_completion(&data->pending.ready);
data->pending.usage_id = usage_id;
data->pending.attr_usage_id = attr_usage_id;
data->pending.raw_size = 0;
spin_lock_irqsave(&data->lock, flags);
data->pending.status = true;
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
if (!report) {
spin_unlock_irqrestore(&data->lock, flags);
goto err_free;
}
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) {
case 1:
ret_val = *(u8 *)data->pending.raw_data;
break;
case 2:
ret_val = *(u16 *)data->pending.raw_data;
break;
case 4:
ret_val = *(u32 *)data->pending.raw_data;
break;
default:
ret_val = 0;
}
kfree(data->pending.raw_data);
err_free:
data->pending.status = false;
mutex_unlock(&data->mutex);
return ret_val;
}
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
u8 type,
u32 usage_id,
u32 attr_usage_id,
struct hid_sensor_hub_attribute_info *info)
{
int ret = -1;
int i, j;
int collection_index = -1;
struct hid_report *report;
struct hid_field *field;
struct hid_report_enum *report_enum;
struct hid_device *hdev = hsdev->hdev;
/* Initialize with defaults */
info->usage_id = usage_id;
info->attrib_id = attr_usage_id;
info->report_id = -1;
info->index = -1;
info->units = -1;
info->unit_expo = -1;
for (i = 0; i < hdev->maxcollection; ++i) {
struct hid_collection *collection = &hdev->collection[i];
if (usage_id == collection->usage) {
collection_index = i;
break;
}
}
if (collection_index == -1)
goto err_ret;
report_enum = &hdev->report_enum[type];
list_for_each_entry(report, &report_enum->report_list, list) {
for (i = 0; i < report->maxfield; ++i) {
field = report->field[i];
if (field->physical == usage_id &&
field->logical == attr_usage_id) {
sensor_hub_fill_attr_info(info, i, report->id,
field->unit, field->unit_exponent,
field->report_size);