greybus: sysfs attributes for functions and more driver core integration.
authorGreg Kroah-Hartman <greg@kroah.com>
Tue, 2 Sep 2014 01:34:28 +0000 (18:34 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Tue, 2 Sep 2014 01:34:28 +0000 (18:34 -0700)
drivers/staging/greybus/core.c
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus_desc.h

index 9e9ffa0..c05495b 100644 (file)
@@ -156,6 +156,78 @@ void greybus_deregister(struct greybus_driver *driver)
 EXPORT_SYMBOL_GPL(greybus_deregister);
 
 
+static void greybus_module_release(struct device *dev)
+{
+       struct greybus_device *gdev = to_greybus_device(dev);
+       int i;
+
+       for (i = 0; i < gdev->num_strings; ++i)
+               kfree(gdev->string[i]);
+       for (i = 0; i < gdev->num_cports; ++i)
+               kfree(gdev->cport[i]);
+       kfree(gdev);
+}
+
+
+
+static struct device_type greybus_module_type = {
+       .name =         "greybus_module",
+       .release =      greybus_module_release,
+};
+
+/* Function fields */
+#define greybus_function_attr(field)                                   \
+static ssize_t function_##field##_show(struct device *dev,             \
+                                      struct device_attribute *attr,   \
+                                      char *buf)                       \
+{                                                                      \
+       struct greybus_device *gdev = to_greybus_device(dev);           \
+       return sprintf(buf, "%d\n", gdev->function.field);              \
+}                                                                      \
+static DEVICE_ATTR_RO(function_##field)
+
+greybus_function_attr(number);
+greybus_function_attr(cport);
+greybus_function_attr(class);
+greybus_function_attr(subclass);
+greybus_function_attr(protocol);
+
+static struct attribute *function_attrs[] = {
+       &dev_attr_function_number.attr,
+       &dev_attr_function_cport.attr,
+       &dev_attr_function_class.attr,
+       &dev_attr_function_subclass.attr,
+       &dev_attr_function_protocol.attr,
+       NULL,
+};
+
+static umode_t function_attrs_are_visible(struct kobject *kobj,
+                                         struct attribute *a, int n)
+{
+       struct greybus_device *gdev = to_greybus_device(kobj_to_dev(kobj));
+
+       // FIXME - make this a dynamic structure to "know" if it really is here
+       // or not easier?
+       if (gdev->function.number ||
+           gdev->function.cport ||
+           gdev->function.class ||
+           gdev->function.subclass ||
+           gdev->function.protocol)
+               return a->mode;
+       return 0;
+}
+
+static struct attribute_group function_addr_grp = {
+       .attrs =        function_attrs,
+       .is_visible =   function_attrs_are_visible,
+};
+
+static const struct attribute_group *greybus_module_groups[] = {
+       &function_addr_grp,
+       NULL,
+};
+
+
 static int gb_init_subdevs(struct greybus_device *gdev,
                           const struct greybus_module_id *id)
 {
@@ -201,7 +273,8 @@ static int create_function(struct greybus_device *gdev,
        int header_size = sizeof(struct greybus_descriptor_function);
 
        if (desc_size != header_size) {
-               pr_err("invalid function header size %d\n", desc_size);
+               dev_err(gdev->dev.parent, "invalid function header size %d\n",
+                       desc_size);
                return -EINVAL;
        }
        memcpy(&gdev->function, &desc->function, header_size);
@@ -214,7 +287,8 @@ static int create_module_id(struct greybus_device *gdev,
        int header_size = sizeof(struct greybus_descriptor_module_id);
 
        if (desc_size != header_size) {
-               pr_err("invalid module header size %d\n", desc_size);
+               dev_err(gdev->dev.parent, "invalid module header size %d\n",
+                       desc_size);
                return -EINVAL;
        }
        memcpy(&gdev->module_id, &desc->module_id, header_size);
@@ -227,7 +301,8 @@ static int create_serial_number(struct greybus_device *gdev,
        int header_size = sizeof(struct greybus_descriptor_serial_number);
 
        if (desc_size != header_size) {
-               pr_err("invalid serial number header size %d\n", desc_size);
+               dev_err(gdev->dev.parent, "invalid serial number header size %d\n",
+                       desc_size);
                return -EINVAL;
        }
        memcpy(&gdev->serial_number, &desc->serial_number, header_size);
@@ -242,12 +317,14 @@ static int create_string(struct greybus_device *gdev,
        int header_size  = sizeof(struct greybus_descriptor_string);
 
        if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
-               pr_err("too many strings for this module!\n");
+               dev_err(gdev->dev.parent,
+                       "too many strings for this module!\n");
                return -EINVAL;
        }
 
        if (desc_size < header_size) {
-               pr_err("invalid string header size %d\n", desc_size);
+               dev_err(gdev->dev.parent, "invalid string header size %d\n",
+                       desc_size);
                return -EINVAL;
        }
 
@@ -259,28 +336,59 @@ static int create_string(struct greybus_device *gdev,
        string->length = string_size;
        string->id = desc->string.id;
        memcpy(&string->string, &desc->string.string, string_size);
+
        gdev->string[gdev->num_strings] = string;
        gdev->num_strings++;
 
        return 0;
 }
 
+static int create_cport(struct greybus_device *gdev,
+                       struct greybus_descriptor *desc, int desc_size)
+{
+       struct gdev_cport *cport;
+       int header_size = sizeof(struct greybus_descriptor_cport);
+
+       if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
+               dev_err(gdev->dev.parent, "too many cports for this module!\n");
+               return -EINVAL;
+       }
+
+       if (desc_size != header_size) {
+               dev_err(gdev->dev.parent,
+                       "invalid serial number header size %d\n", desc_size);
+               return -EINVAL;
+       }
+
+       cport = kzalloc(sizeof(*cport), GFP_KERNEL);
+       if (!cport)
+               return -ENOMEM;
+
+       cport->number = le16_to_cpu(desc->cport.number);
+       cport->size = le16_to_cpu(desc->cport.size);
+       cport->speed = desc->cport.speed;
+
+       gdev->cport[gdev->num_cports] = cport;
+       gdev->num_cports++;
+
+       return 0;
+}
+
 /**
  * greybus_new_device:
  *
  * Pass in a buffer that _should_ be a set of greybus descriptor fields and spit
  * out a greybus device structure.
  */
-struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
+struct greybus_device *greybus_new_device(struct device *parent,
+                                         int module_number, u8 *data, int size)
 {
        struct greybus_device *gdev;
        struct greybus_descriptor_block_header *block;
        struct greybus_descriptor *desc;
        int retval;
        int overall_size;
-       int header_size;
        int desc_size;
-       int i;
        u8 version_major;
        u8 version_minor;
 
@@ -293,12 +401,20 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
                return NULL;
 
        gdev->module_number = module_number;
+       gdev->dev.parent = parent;
+       gdev->dev.driver = NULL;
+       gdev->dev.bus = &greybus_bus_type;
+       gdev->dev.type = &greybus_module_type;
+       gdev->dev.groups = greybus_module_groups;
+       gdev->dev.dma_mask = parent->dma_mask;
+       device_initialize(&gdev->dev);
+       dev_set_name(&gdev->dev, "%d", module_number);
 
        block = (struct greybus_descriptor_block_header *)data;
        overall_size = le16_to_cpu(block->size);
        if (overall_size != size) {
-               pr_err("size != block header size, %d != %d\n", size,
-                               overall_size);
+               dev_err(parent, "size != block header size, %d != %d\n", size,
+                       overall_size);
                goto error;
        }
 
@@ -330,32 +446,14 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
                        retval = create_string(gdev, desc, desc_size);
                        break;
 
-               case GREYBUS_TYPE_CPORT: {
-                       struct gdev_cport *cport;
-
-                       header_size = sizeof(struct greybus_descriptor_cport);
-                       if (desc_size != header_size) {
-                               pr_err("invalid serial number header size %d\n",
-                                      desc_size);
-                               goto error;
-                       }
-                       cport = kzalloc(sizeof(*cport), GFP_KERNEL);
-                       if (!cport)
-                               goto error;
-                       cport->number = le16_to_cpu(desc->cport.number);
-                       cport->size = le16_to_cpu(desc->cport.size);
-                       cport->speed = desc->cport.speed;
-                       gdev->cport[gdev->num_cports] = cport;
-                       gdev->num_cports++;
-                       // FIXME - check for too many cports...
-
-                       size -= desc_size;
-                       data += desc_size;
+               case GREYBUS_TYPE_CPORT:
+                       retval = create_cport(gdev, desc, desc_size);
                        break;
-                       }
+
                case GREYBUS_TYPE_INVALID:
                default:
-                       pr_err("invalid descriptor type %d\n", desc->header.type);
+                       dev_err(parent, "invalid descriptor type %d\n",
+                               desc->header.type);
                        goto error;
                }
                if (retval)
@@ -367,23 +465,25 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
        retval = gb_init_subdevs(gdev, &fake_gb_id);
        if (retval)
                goto error;
+
+       // FIXME device_add(&gdev->dev);
+
+
        return gdev;
 error:
-       for (i = 0; i < gdev->num_strings; ++i)
-               kfree(gdev->string[i]);
-       for (i = 0; i < gdev->num_cports; ++i)
-               kfree(gdev->cport[i]);
-       kfree(gdev);
+       greybus_module_release(&gdev->dev);
        return NULL;
 }
 
-void remove_device(struct greybus_device *gdev)
+void greybus_remove_device(struct greybus_device *gdev)
 {
        /* tear down all of the "sub device types" for this device */
        gb_i2c_disconnect(gdev);
        gb_gpio_disconnect(gdev);
        gb_sdio_disconnect(gdev);
        gb_tty_disconnect(gdev);
+
+       // FIXME - device_remove(&gdev->dev);
 }
 
 static int __init gb_init(void)
index 6d82806..1a0dc4c 100644 (file)
@@ -173,6 +173,10 @@ void greybus_deregister(struct greybus_driver *driver);
 
 int greybus_disabled(void);
 
+struct greybus_device *greybus_new_device(struct device *parent,
+                                         int module_number, u8 *data,
+                                         int size);
+void greybus_remove_device(struct greybus_device *gdev);
 
 /* Internal functions to gb module, move to internal .h file eventually. */
 
index 37cc99a..0fd7230 100644 (file)
@@ -50,9 +50,9 @@ enum greybus_function_class {
 struct greybus_descriptor_function {
        __le16  number;
        __le16  cport;
-       __u8    function_class;         /* enum greybus_function_class */
-       __u8    function_subclass;
-       __u8    function_protocol;
+       __u8    class;          /* enum greybus_function_class */
+       __u8    subclass;
+       __u8    protocol;
        __u8    reserved;
 };