diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index f6ad19a1329b..9945cb804d10 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -2,6 +2,7 @@ greybus-y := core.o \ debugfs.o \ ap.o \ manifest.o \ + endo.o \ module.o \ interface.o \ bundle.o \ diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index da62c5496e50..7c701f398a4d 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -51,6 +51,14 @@ static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env) struct gb_bundle *bundle = NULL; struct gb_connection *connection = NULL; + if (is_gb_endo(dev)) { + /* + * Not much to do for an endo, just fall through, as the + * "default" attributes are good enough for us. + */ + return 0; + } + if (is_gb_module(dev)) { module = to_gb_module(dev); } else if (is_gb_interface(dev)) { diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c new file mode 100644 index 000000000000..e3bb25f7ec2b --- /dev/null +++ b/drivers/staging/greybus/endo.c @@ -0,0 +1,164 @@ +/* + * Greybus endo code + * + * Copyright 2015 Google Inc. + * Copyright 2014 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#include "greybus.h" + +/* endo sysfs attributes */ +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gb_endo *endo = to_gb_endo(dev); + + return sprintf(buf, "%s", &endo->svc.serial_number[0]); +} +static DEVICE_ATTR_RO(serial_number); + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct gb_endo *endo = to_gb_endo(dev); + + return sprintf(buf, "%s", &endo->svc.version[0]); +} +static DEVICE_ATTR_RO(version); + +static struct attribute *endo_attrs[] = { + &dev_attr_serial_number.attr, + &dev_attr_version.attr, + NULL, +}; +static const struct attribute_group endo_group = { + .attrs = endo_attrs, + .name = "SVC", +}; +static const struct attribute_group *endo_groups[] = { + &endo_group, + NULL, +}; + +static void greybus_endo_release(struct device *dev) +{ + struct gb_endo *endo = to_gb_endo(dev); + + kfree(endo); +} + +struct device_type greybus_endo_type = { + .name = "greybus_endo", + .release = greybus_endo_release, +}; + + +/* + * Endo "types" have different module locations, these are tables based on those + * types that list the module ids for the different locations. + * + * List must end with 0x00 in order to properly terminate the list. + */ +static u8 endo_0555[] = { + 0x01, + 0x03, + 0x05, + 0x07, + 0x08, + 0x0a, + 0x0c, + 0x00, +}; + + +static int create_modules(struct gb_endo *endo) +{ + struct gb_module *module; + u8 *endo_modules; + int i; + + /* Depending on the endo type, create a bunch of different modules */ + switch (endo->type) { + case 0x0555: + endo_modules = &endo_0555[0]; + break; + default: + dev_err(&endo->dev, "Unknown endo type 0x%04x, aborting!", + endo->type); + return -EINVAL; + } + + for (i = 0; endo_modules[i] != 0x00; ++i) { +// module = gb_module_create(&endo->dev, endo_modules[i]); + if (!module) + return -EINVAL; + } + + return 0; +} + +static void remove_modules(struct gb_endo *endo) +{ + /* + * We really don't care how many modules have been created, or what the + * configuration of them are, let's just enumerate over everything in + * the system and delete all found modules. + */ + +} + +struct gb_endo *gb_endo_create(struct greybus_host_device *hd) +{ + struct gb_endo *endo; + int retval; + + endo = kzalloc(sizeof(*endo), GFP_KERNEL); + if (!endo) + return NULL; + + endo->dev.parent = hd->parent; + endo->dev.bus = &greybus_bus_type; + endo->dev.type = &greybus_endo_type; + endo->dev.groups = endo_groups; + endo->dev.dma_mask = hd->parent->dma_mask; + device_initialize(&endo->dev); + + // FIXME - determine endo "type" from the SVC + // Also get the version and serial number from the SVC, right now we are + // using "fake" numbers. + strcpy(&endo->svc.serial_number[0], "042"); + strcpy(&endo->svc.version[0], "0.0"); + endo->type = 0x0555; + + dev_set_name(&endo->dev, "endo-0x%04x", endo->type); + retval = device_add(&endo->dev); + if (retval) { + dev_err(hd->parent, "failed to add endo device of type 0x%04x\n", + endo->type); + put_device(&endo->dev); + kfree(endo); + return NULL; + } + + retval = create_modules(endo); + if (retval) { + gb_endo_remove(endo); + return NULL; + } + + return endo; +} + +void gb_endo_remove(struct gb_endo *endo) +{ + if (!endo) + return; + + /* remove all modules first */ + remove_modules(endo); + + device_unregister(&endo->dev); +} + diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h new file mode 100644 index 000000000000..649093e4025d --- /dev/null +++ b/drivers/staging/greybus/endo.h @@ -0,0 +1,32 @@ +/* + * Greybus endo code + * + * Copyright 2015 Google Inc. + * + * Released under the GPLv2 only. + */ + +#ifndef __ENDO_H +#define __ENDO_H + +/* Greybus "public" definitions" */ +struct gb_svc { + u8 serial_number[10]; + u8 version[10]; +}; + +struct gb_endo { + struct device dev; + struct gb_svc svc; + u16 type; +}; +#define to_gb_endo(d) container_of(d, struct gb_endo, dev) + + +/* Greybus "private" definitions */ +struct greybus_host_device; + +struct gb_endo *gb_endo_create(struct greybus_host_device *hd); +void gb_endo_remove(struct gb_endo *endo); + +#endif /* __ENDO_H */ diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 8d4bde3815d6..e0aae42fc4ce 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -24,6 +24,7 @@ #include "greybus_id.h" #include "greybus_manifest.h" #include "manifest.h" +#include "endo.h" #include "module.h" #include "interface.h" #include "bundle.h" @@ -158,11 +159,17 @@ void gb_uart_device_exit(struct gb_connection *connection); int svc_set_route_send(struct gb_bundle *bundle, struct greybus_host_device *hd); +extern struct device_type greybus_endo_type; extern struct device_type greybus_module_type; extern struct device_type greybus_interface_type; extern struct device_type greybus_bundle_type; extern struct device_type greybus_connection_type; +static inline int is_gb_endo(const struct device *dev) +{ + return dev->type == &greybus_endo_type; +} + static inline int is_gb_module(const struct device *dev) { return dev->type == &greybus_module_type;