| /* |
| * Greybus module code |
| * |
| * Copyright 2014 Google Inc. |
| * Copyright 2014 Linaro Ltd. |
| * |
| * Released under the GPLv2 only. |
| */ |
| |
| #include "greybus.h" |
| |
| |
| /* module sysfs attributes */ |
| static ssize_t epm_show(struct device *dev, struct device_attribute *attr, |
| char *buf) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return sprintf(buf, "1\n"); |
| } |
| |
| static ssize_t epm_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t size) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return 0; |
| } |
| static DEVICE_ATTR_RW(epm); |
| |
| static ssize_t power_control_show(struct device *dev, |
| struct device_attribute *addr, char *buf) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return sprintf(buf, "1\n"); |
| } |
| |
| static ssize_t power_control_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t size) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return 0; |
| } |
| static DEVICE_ATTR_RW(power_control); |
| |
| static ssize_t present_show(struct device *dev, |
| struct device_attribute *addr, char *buf) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return sprintf(buf, "1\n"); |
| } |
| |
| static ssize_t present_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t size) |
| { |
| // FIXME |
| // Implement something here when we have a working control protocol |
| return 0; |
| } |
| static DEVICE_ATTR_RW(present); |
| |
| static struct attribute *module_attrs[] = { |
| &dev_attr_epm.attr, |
| &dev_attr_power_control.attr, |
| &dev_attr_present.attr, |
| NULL, |
| }; |
| ATTRIBUTE_GROUPS(module); |
| |
| static void gb_module_release(struct device *dev) |
| { |
| struct gb_module *module = to_gb_module(dev); |
| |
| kfree(module); |
| } |
| |
| struct device_type greybus_module_type = { |
| .name = "greybus_module", |
| .release = gb_module_release, |
| }; |
| |
| struct module_find { |
| struct gb_endo *endo; |
| u8 module_id; |
| }; |
| |
| static int module_find(struct device *dev, void *data) |
| { |
| struct gb_module *module; |
| struct module_find *find = data; |
| |
| if (!is_gb_module(dev)) |
| return 0; |
| |
| module = to_gb_module(dev); |
| if ((module->module_id == find->module_id) && |
| (module->dev.parent == &find->endo->dev)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /* |
| * Search the list of modules in the system. If one is found, return it, with |
| * the reference count incremented. |
| */ |
| struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id) |
| { |
| struct device *dev; |
| struct gb_module *module = NULL; |
| struct module_find find; |
| |
| if (!module_id) |
| return NULL; |
| |
| find.module_id = module_id; |
| find.endo = hd->endo; |
| |
| dev = bus_find_device(&greybus_bus_type, NULL, |
| &find, module_find); |
| if (dev) |
| module = to_gb_module(dev); |
| |
| return module; |
| } |
| |
| struct gb_module *gb_module_create(struct device *parent, u8 module_id) |
| { |
| struct gb_module *module; |
| int retval; |
| |
| module = kzalloc(sizeof(*module), GFP_KERNEL); |
| if (!module) |
| return NULL; |
| |
| module->module_id = module_id; |
| module->dev.parent = parent; |
| module->dev.bus = &greybus_bus_type; |
| module->dev.type = &greybus_module_type; |
| module->dev.groups = module_groups; |
| module->dev.dma_mask = parent->dma_mask; |
| device_initialize(&module->dev); |
| dev_set_name(&module->dev, "%s:%hhu", dev_name(parent), module_id); |
| |
| retval = device_add(&module->dev); |
| if (retval) { |
| pr_err("failed to add module device for id 0x%02hhx\n", |
| module_id); |
| put_device(&module->dev); |
| kfree(module); |
| return NULL; |
| } |
| |
| return module; |
| } |
| |
| static int module_remove(struct device *dev, void *data) |
| { |
| struct gb_module *module; |
| struct gb_endo *endo = data; |
| |
| if (!is_gb_module(dev)) |
| return 0; |
| |
| module = to_gb_module(dev); |
| if (module->dev.parent == &endo->dev) |
| device_unregister(&module->dev); |
| |
| return 0; |
| } |
| |
| void gb_module_remove_all(struct gb_endo *endo) |
| { |
| bus_for_each_dev(&greybus_bus_type, NULL, endo, module_remove); |
| } |