From b94295e0502dbe7f0c0d2b572c8b7334b05c279c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 1 Sep 2014 18:34:28 -0700 Subject: [PATCH] greybus: sysfs attributes for functions and more driver core integration. --- drivers/staging/greybus/core.c | 178 +++++++++++++++++++++++++-------- drivers/staging/greybus/greybus.h | 4 + drivers/staging/greybus/greybus_desc.h | 6 +- 3 files changed, 146 insertions(+), 42 deletions(-) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 9e9ffa0..c05495b 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -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) diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 6d82806..1a0dc4c 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -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. */ diff --git a/drivers/staging/greybus/greybus_desc.h b/drivers/staging/greybus/greybus_desc.h index 37cc99a..0fd7230 100644 --- a/drivers/staging/greybus/greybus_desc.h +++ b/drivers/staging/greybus/greybus_desc.h @@ -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; }; -- 2.7.4