HID: hid-sensor-hub: Add support for application collection
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Thu, 19 Feb 2015 23:31:26 +0000 (15:31 -0800)
committerJiri Kosina <jkosina@suse.cz>
Mon, 23 Feb 2015 14:11:52 +0000 (15:11 +0100)
Section 4.2.5 of HID Sensor hub specification allows two methods
defining sensor devices.
- Each sensor device by its own collection
- A top level application collection object, including multiple
sensors.
In the first method, each sensor can be in its own sensor application
collection without a physical collection.
In the second method there is a usage id for collection type, which
is defined as an application collection, with multiple physical
collections in it. It is possible to define fusion sensor with this
and may have its own handler. If there is a callback registered
for the collection type, then forward all reports for sensors in
its collection to this handler.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-sensor-hub.c
include/linux/hid-sensor-ids.h

index 62fadf8c86fc6c826174035d1022615b7e43cf52..c325f85fa3a69d7f63799aa2da242d44034ba239 100644 (file)
@@ -86,7 +86,8 @@ static int sensor_hub_get_physical_device_count(struct hid_device *hdev)
 
        for (i = 0; i < hdev->maxcollection; ++i) {
                struct hid_collection *collection = &hdev->collection[i];
-               if (collection->type == HID_COLLECTION_PHYSICAL)
+               if (collection->type == HID_COLLECTION_PHYSICAL ||
+                   collection->type == HID_COLLECTION_APPLICATION)
                        ++count;
        }
 
@@ -118,7 +119,8 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
 
        spin_lock(&pdata->dyn_callback_lock);
        list_for_each_entry(callback, &pdata->dyn_callback_list, list)
-               if (callback->usage_id == usage_id &&
+               if ((callback->usage_id == usage_id ||
+                    callback->usage_id == HID_USAGE_SENSOR_COLLECTION) &&
                        (collection_index >=
                                callback->hsdev->start_collection_index) &&
                        (collection_index <
@@ -157,7 +159,18 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
        callback->usage_callback = usage_callback;
        callback->usage_id = usage_id;
        callback->priv = NULL;
-       list_add_tail(&callback->list, &pdata->dyn_callback_list);
+       /*
+        * If there is a handler registered for the collection type, then
+        * it will handle all reports for sensors in this collection. If
+        * there is also an individual sensor handler registration, then
+        * we want to make sure that the reports are directed to collection
+        * handler, as this may be a fusion sensor. So add collection handlers
+        * to the beginning of the list, so that they are matched first.
+        */
+       if (usage_id == HID_USAGE_SENSOR_COLLECTION)
+               list_add(&callback->list, &pdata->dyn_callback_list);
+       else
+               list_add_tail(&callback->list, &pdata->dyn_callback_list);
        spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
 
        return 0;
@@ -555,6 +568,7 @@ static int sensor_hub_probe(struct hid_device *hdev,
        int dev_cnt;
        struct hid_sensor_hub_device *hsdev;
        struct hid_sensor_hub_device *last_hsdev = NULL;
+       struct hid_sensor_hub_device *collection_hsdev = NULL;
 
        sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
        if (!sd) {
@@ -601,7 +615,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
        for (i = 0; i < hdev->maxcollection; ++i) {
                struct hid_collection *collection = &hdev->collection[i];
 
-               if (collection->type == HID_COLLECTION_PHYSICAL) {
+               if (collection->type == HID_COLLECTION_PHYSICAL ||
+                   collection->type == HID_COLLECTION_APPLICATION) {
 
                        hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
                                             GFP_KERNEL);
@@ -638,10 +653,17 @@ static int sensor_hub_probe(struct hid_device *hdev,
                        hid_dbg(hdev, "Adding %s:%d\n", name,
                                        hsdev->start_collection_index);
                        sd->hid_sensor_client_cnt++;
+                       if (collection_hsdev)
+                               collection_hsdev->end_collection_index = i;
+                       if (collection->type == HID_COLLECTION_APPLICATION &&
+                           collection->usage == HID_USAGE_SENSOR_COLLECTION)
+                               collection_hsdev = hsdev;
                }
        }
        if (last_hsdev)
                last_hsdev->end_collection_index = i;
+       if (collection_hsdev)
+               collection_hsdev->end_collection_index = i;
 
        ret = mfd_add_hotplug_devices(&hdev->dev,
                        sd->hid_sensor_hub_client_devs,
index 109f0e633e01f176f4937e3838834cbff2d33b67..f2ee90aed0c2e8f00cdb9d5bbbece61e4b325397 100644 (file)
@@ -21,6 +21,8 @@
 
 #define HID_MAX_PHY_DEVICES                                    0xFF
 
+#define HID_USAGE_SENSOR_COLLECTION                            0x200001
+
 /* Accel 3D (200073) */
 #define HID_USAGE_SENSOR_ACCEL_3D                              0x200073
 #define HID_USAGE_SENSOR_DATA_ACCELERATION                     0x200452