greybus: interface: Fetch and expose version of interface's firmware
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 28 Dec 2015 06:29:01 +0000 (11:59 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 30 Dec 2015 21:13:04 +0000 (13:13 -0800)
The version of the currently running firmware on the module is useful
for userspace as it can be used to find if an update is available or
not. This patch fetches interface's version with a new control operation
and exposes the same in userspace.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Documentation/sysfs-bus-greybus
drivers/staging/greybus/control.c
drivers/staging/greybus/control.h
drivers/staging/greybus/greybus_protocols.h
drivers/staging/greybus/interface.c
drivers/staging/greybus/interface.h

index 0d16d76..9ce36dd 100644 (file)
@@ -73,6 +73,14 @@ Contact:     Greg Kroah-Hartman <greg@kroah.com>
 Description:
                Vendor ID string of a Greybus interface block.
 
+What:          /sys/bus/greybus/device/N-I/version
+Date:          October 2015
+KernelVersion: 4.XX
+Contact:       Greg Kroah-Hartman <greg@kroah.com>
+Description:
+               Interface version represented as <16 bit major number>.<16 bit
+               minor number>.
+
 What:          /sys/bus/greybus/device/N-I.B
 Date:          October 2015
 KernelVersion: 4.XX
index 09ff797..4d65dbf 100644 (file)
@@ -59,6 +59,35 @@ int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id)
                                 sizeof(request), NULL, 0);
 }
 
+int gb_control_get_interface_version_operation(struct gb_interface *intf)
+{
+       struct gb_control_interface_version_response response;
+       struct gb_connection *connection = intf->control->connection;
+       int ret;
+
+       /* The ES3 bootrom fails to boot if this request it sent to it */
+       if (intf->boot_over_unipro)
+               return 0;
+
+       ret = gb_operation_sync(connection, GB_CONTROL_TYPE_INTERFACE_VERSION,
+                               NULL, 0, &response, sizeof(response));
+       if (ret) {
+               dev_err(&connection->intf->dev,
+                       "failed to get interface version: %d\n", ret);
+               /*
+                * FIXME: Return success until the time we bump version of
+                * control protocol. The interface-version is already set to
+                * 0.0, so no need to update that.
+                */
+               return 0;
+       }
+
+       intf->version_major = le16_to_cpu(response.major);
+       intf->version_minor = le16_to_cpu(response.minor);
+
+       return 0;
+}
+
 struct gb_control *gb_control_create(struct gb_interface *intf)
 {
        struct gb_control *control;
index da0fa66..7cb3dd2 100644 (file)
@@ -24,6 +24,7 @@ int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id);
 int gb_control_get_manifest_size_operation(struct gb_interface *intf);
 int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
                                      size_t size);
+int gb_control_get_interface_version_operation(struct gb_interface *intf);
 
 int gb_control_protocol_init(void);
 void gb_control_protocol_exit(void);
index f66f4d7..a0bddaa 100644 (file)
@@ -125,6 +125,7 @@ struct gb_protocol_version_response {
 #define GB_CONTROL_TYPE_GET_MANIFEST           0x04
 #define GB_CONTROL_TYPE_CONNECTED              0x05
 #define GB_CONTROL_TYPE_DISCONNECTED           0x06
+#define GB_CONTROL_TYPE_INTERFACE_VERSION      0x0a
 
 /* Control protocol manifest get size request has no payload*/
 struct gb_control_get_manifest_size_response {
@@ -146,6 +147,12 @@ struct gb_control_disconnected_request {
 } __packed;
 /* Control protocol [dis]connected response has no payload */
 
+/* Control protocol interface version request has no payload */
+struct gb_control_interface_version_response {
+       __le16                  major;
+       __le16                  minor;
+} __packed;
+
 
 /* Firmware Protocol */
 
index 69eb788..edac238 100644 (file)
@@ -29,6 +29,16 @@ gb_interface_attr(vendor_string, "%s");
 gb_interface_attr(product_string, "%s");
 gb_interface_attr(serial_number, "0x%016llx");
 
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u.%u\n", intf->version_major,
+                        intf->version_minor);
+}
+static DEVICE_ATTR_RO(version);
+
 static struct attribute *interface_attrs[] = {
        &dev_attr_ddbl1_manufacturer_id.attr,
        &dev_attr_ddbl1_product_id.attr,
@@ -38,6 +48,7 @@ static struct attribute *interface_attrs[] = {
        &dev_attr_vendor_string.attr,
        &dev_attr_product_string.attr,
        &dev_attr_serial_number.attr,
+       &dev_attr_version.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(interface);
@@ -214,6 +225,10 @@ int gb_interface_init(struct gb_interface *intf, u8 device_id)
                goto free_manifest;
        }
 
+       ret = gb_control_get_interface_version_operation(intf);
+       if (ret)
+               goto free_manifest;
+
        /* Register the interface and its bundles. */
        ret = device_add(&intf->dev);
        if (ret) {
index a1a1f9f..4168a57 100644 (file)
@@ -32,6 +32,9 @@ struct gb_interface {
        u32 product_id;
        u64 serial_number;
 
+       u16 version_major;
+       u16 version_minor;
+
        struct gb_host_device *hd;
 
        /* The interface needs to boot over unipro */