sysfs.o \
debugfs.o \
ap.o \
+ module.o \
i2c-gb.o \
gpio-gb.o \
sdio-gb.o \
// we will want to keep the battery stats in here as we will be getting
// updates from the SVC "on the fly" so we don't have to always go ask
// the battery for some information. Hopefully...
- struct greybus_module *gmod;
+ struct gb_module *gmod;
};
#define to_gb_battery(x) container_of(x, struct gb_battery, bat)
POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
-int gb_battery_probe(struct greybus_module *gmod,
+int gb_battery_probe(struct gb_module *gmod,
const struct greybus_module_id *id)
{
struct gb_battery *gb;
return 0;
}
-void gb_battery_disconnect(struct greybus_module *gmod)
+void gb_battery_disconnect(struct gb_module *gmod)
{
struct gb_battery *gb;
}
EXPORT_SYMBOL_GPL(greybus_disabled);
-static int greybus_match_one_id(struct greybus_module *gmod,
- const struct greybus_module_id *id)
-{
- struct greybus_descriptor_module *module;
-
- module = &gmod->module;
-
- if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
- (id->vendor != le16_to_cpu(module->vendor)))
- return 0;
-
- if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
- (id->product != le16_to_cpu(module->product)))
- return 0;
-
- if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
- (id->serial_number != le64_to_cpu(module->serial_number)))
- return 0;
-
- return 1;
-}
-
-static const struct greybus_module_id *greybus_match_id(
- struct greybus_module *gmod,
- const struct greybus_module_id *id)
-{
- if (id == NULL)
- return NULL;
-
- for (; id->vendor || id->product || id->serial_number ||
- id->driver_info ; id++) {
- if (greybus_match_one_id(gmod, id))
- return id;
- }
-
- return NULL;
-}
-
static int greybus_module_match(struct device *dev, struct device_driver *drv)
{
struct greybus_driver *driver = to_greybus_driver(dev->driver);
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
const struct greybus_module_id *id;
- id = greybus_match_id(gmod, driver->id_table);
+ id = gb_module_match_id(gmod, driver->id_table);
if (id)
return 1;
/* FIXME - Dyanmic ids? */
static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- /* struct greybus_module *gmod = to_greybus_module(dev); */
+ /* struct gb_module *gmod = to_gb_module(dev); */
/* FIXME - add some uevents here... */
return 0;
static int greybus_probe(struct device *dev)
{
struct greybus_driver *driver = to_greybus_driver(dev->driver);
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
const struct greybus_module_id *id;
int retval;
/* match id */
- id = greybus_match_id(gmod, driver->id_table);
+ id = gb_module_match_id(gmod, driver->id_table);
if (!id)
return -ENODEV;
static int greybus_remove(struct device *dev)
{
struct greybus_driver *driver = to_greybus_driver(dev->driver);
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
driver->disconnect(gmod);
return 0;
static void greybus_module_release(struct device *dev)
{
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
int i;
for (i = 0; i < gmod->num_strings; ++i)
}
-const u8 *greybus_string(struct greybus_module *gmod, int id)
+const u8 *greybus_string(struct gb_module *gmod, int id)
{
int i;
struct gmod_string *string;
.release = greybus_module_release,
};
-static int gb_init_subdevs(struct greybus_module *gmod,
+static int gb_init_subdevs(struct gb_module *gmod,
const struct greybus_module_id *id)
{
int retval;
return retval;
}
-static const struct greybus_module_id fake_gb_id = {
+static const struct greybus_module_id fake_greybus_module_id = {
GREYBUS_DEVICE(0x42, 0x42)
};
-static int create_module(struct greybus_module *gmod,
+static int create_module(struct gb_module *gmod,
struct greybus_descriptor_module *module,
size_t desc_size)
{
return 0;
}
-static int create_string(struct greybus_module *gmod,
+static int create_string(struct gb_module *gmod,
struct greybus_descriptor_string *string,
size_t desc_size)
{
return 0;
}
-static int create_cport(struct greybus_module *gmod,
+static int create_cport(struct gb_module *gmod,
struct greybus_descriptor_cport *cport,
size_t desc_size)
{
void gb_add_module(struct greybus_host_device *hd, u8 module_id,
u8 *data, int size)
{
- struct greybus_module *gmod;
+ struct gb_module *gmod;
struct greybus_manifest *manifest;
int retval;
int overall_size;
if (size <= sizeof(manifest->header))
return;
- gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
+ gmod = gb_module_create(hd, module_id);
if (!gmod)
return;
- gmod->module_number = module_id;
gmod->dev.parent = hd->parent;
gmod->dev.driver = NULL;
gmod->dev.bus = &greybus_bus_type;
data += desc_size;
}
- retval = gb_init_subdevs(gmod, &fake_gb_id);
+ retval = gb_init_subdevs(gmod, &fake_greybus_module_id);
if (retval)
goto error;
// FIXME should be the remove_device call...
}
-void greybus_remove_device(struct greybus_module *gmod)
+void greybus_remove_device(struct gb_module *gmod)
{
/* tear down all of the "sub device types" for this device */
gb_i2c_disconnect(gmod);
kref_init(&hd->kref);
hd->parent = parent;
hd->driver = driver;
+ INIT_LIST_HEAD(&hd->modules);
return hd;
}
/* Workqueue to handle Greybus buffer completions. */
static struct workqueue_struct *gbuf_workqueue;
-static struct gbuf *__alloc_gbuf(struct greybus_module *gmod,
+static struct gbuf *__alloc_gbuf(struct gb_module *gmod,
u16 cport_id,
gbuf_complete_t complete,
gfp_t gfp_mask,
* that the driver can then fill up with the data to be sent out. Curse
* hardware designers for this issue...
*/
-struct gbuf *greybus_alloc_gbuf(struct greybus_module *gmod,
+struct gbuf *greybus_alloc_gbuf(struct gb_module *gmod,
u16 cport_id,
gbuf_complete_t complete,
unsigned int size,
gbuf->direction = GBUF_DIRECTION_OUT;
/* Host controller specific allocation for the actual buffer */
- retval = gbuf->gmod->hd->driver->alloc_gbuf_data(gbuf, size, gfp_mask);
+ retval = gmod->hd->driver->alloc_gbuf_data(gbuf, size, gfp_mask);
if (retval) {
greybus_free_gbuf(gbuf);
return NULL;
struct gb_cport_handler {
gbuf_complete_t handler;
u16 cport_id;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
void *context;
};
// FIXME - use a lock for this list of handlers, but really, for now we don't
// need it, we don't have a dynamic system...
-int gb_register_cport_complete(struct greybus_module *gmod,
- gbuf_complete_t handler, u16 cport_id,
+int gb_register_cport_complete(struct gb_module *gmod,
+ gbuf_complete_t handler,
+ u16 cport_id,
void *context)
{
if (cport_handler[cport_id].handler)
struct gb_gpio_device {
struct gpio_chip chip;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
struct gpio_chip *gpio;
// FIXME - some lock?
};
// FIXME - do something there
}
-int gb_gpio_probe(struct greybus_module *gmod,
+int gb_gpio_probe(struct gb_module *gmod,
const struct greybus_module_id *id)
{
struct gb_gpio_device *gb_gpio;
return 0;
}
-void gb_gpio_disconnect(struct greybus_module *gmod)
+void gb_gpio_disconnect(struct gb_module *gmod)
{
struct gb_gpio_device *gb_gpio_dev;
int retval;
#ifdef __KERNEL__
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/slab.h>
#include <linux/device.h>
#include <linux/module.h>
+
#include "greybus_id.h"
#include "greybus_manifest.h"
+#include "module.h"
/* Matches up with the Greybus Protocol specification document */
struct kref kref;
void *hdpriv;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
u16 cport_id;
int status;
void *transfer_buffer;
* same module as the gpio pins, etc.)
*
* So, put the "private" data structures here in greybus.h and link to them off
- * of the "main" greybus_module structure.
+ * of the "main" gb_module structure.
*/
struct gb_i2c_device;
struct device *parent;
const struct greybus_host_driver *driver;
+ struct list_head modules;
+
/* Private data for the host driver */
unsigned long hd_priv[0] __attribute__ ((aligned(sizeof(s64))));
};
u8 *data, size_t length);
void greybus_gbuf_finished(struct gbuf *gbuf);
-
-/* Increase these values if needed */
-#define MAX_CPORTS_PER_MODULE 10
-#define MAX_STRINGS_PER_MODULE 10
-
-struct greybus_module {
- struct device dev;
- u16 module_number;
- struct greybus_descriptor_module module;
- int num_cports;
- int num_strings;
- u16 cport_ids[MAX_CPORTS_PER_MODULE];
- struct gmod_string *string[MAX_STRINGS_PER_MODULE];
-
- struct greybus_host_device *hd;
-
- struct gb_i2c_device *gb_i2c_dev;
- struct gb_gpio_device *gb_gpio_dev;
- struct gb_sdio_host *gb_sdio_host;
- struct gb_tty *gb_tty;
- struct gb_usb_device *gb_usb_dev;
- struct gb_battery *gb_battery;
-};
-#define to_greybus_module(d) container_of(d, struct greybus_module, dev)
-
-struct gbuf *greybus_alloc_gbuf(struct greybus_module *gmod, u16 cport_id,
+struct gbuf *greybus_alloc_gbuf(struct gb_module *gmod, u16 cport_id,
gbuf_complete_t complete, unsigned int size,
gfp_t gfp_mask, void *context);
void greybus_free_gbuf(struct gbuf *gbuf);
struct greybus_driver {
const char *name;
- int (*probe)(struct greybus_module *gmod,
+ int (*probe)(struct gb_module *gmod,
const struct greybus_module_id *id);
- void (*disconnect)(struct greybus_module *gmod);
+ void (*disconnect)(struct gb_module *gmod);
- int (*suspend)(struct greybus_module *gmod, pm_message_t message);
- int (*resume)(struct greybus_module *gmod);
+ int (*suspend)(struct gb_module *gmod, pm_message_t message);
+ int (*resume)(struct gb_module *gmod);
const struct greybus_module_id *id_table;
};
#define to_greybus_driver(d) container_of(d, struct greybus_driver, driver)
-static inline void greybus_set_drvdata(struct greybus_module *gmod, void *data)
-{
- dev_set_drvdata(&gmod->dev, data);
-}
-
-static inline void *greybus_get_drvdata(struct greybus_module *gmod)
-{
- return dev_get_drvdata(&gmod->dev);
-}
-
/* Don't call these directly, use the module_greybus_driver() macro instead */
int greybus_register_driver(struct greybus_driver *driver,
struct module *module, const char *mod_name);
int greybus_disabled(void);
-void greybus_remove_device(struct greybus_module *gmod);
+void greybus_remove_device(struct gb_module *gmod);
-const u8 *greybus_string(struct greybus_module *gmod, int id);
+const u8 *greybus_string(struct gb_module *gmod, int id);
/* Internal functions to gb module, move to internal .h file eventually. */
int gb_gbuf_init(void);
void gb_gbuf_exit(void);
-int gb_register_cport_complete(struct greybus_module *gmod,
+int gb_register_cport_complete(struct gb_module *gmod,
gbuf_complete_t handler, u16 cport_id,
void *context);
void gb_deregister_cport_complete(u16 cport_id);
* we have static functions for this, not "dynamic" drivers like we really
* should in the end.
*/
-int gb_i2c_probe(struct greybus_module *gmod, const struct greybus_module_id *id);
-void gb_i2c_disconnect(struct greybus_module *gmod);
-int gb_gpio_probe(struct greybus_module *gmod, const struct greybus_module_id *id);
-void gb_gpio_disconnect(struct greybus_module *gmod);
-int gb_sdio_probe(struct greybus_module *gmod, const struct greybus_module_id *id);
-void gb_sdio_disconnect(struct greybus_module *gmod);
-int gb_tty_probe(struct greybus_module *gmod, const struct greybus_module_id *id);
-void gb_tty_disconnect(struct greybus_module *gmod);
-int gb_battery_probe(struct greybus_module *gmod, const struct greybus_module_id *id);
-void gb_battery_disconnect(struct greybus_module *gmod);
+int gb_i2c_probe(struct gb_module *gmod, const struct greybus_module_id *id);
+void gb_i2c_disconnect(struct gb_module *gmod);
+int gb_gpio_probe(struct gb_module *gmod, const struct greybus_module_id *id);
+void gb_gpio_disconnect(struct gb_module *gmod);
+int gb_sdio_probe(struct gb_module *gmod, const struct greybus_module_id *id);
+void gb_sdio_disconnect(struct gb_module *gmod);
+int gb_tty_probe(struct gb_module *gmod, const struct greybus_module_id *id);
+void gb_tty_disconnect(struct gb_module *gmod);
+int gb_battery_probe(struct gb_module *gmod,
+ const struct greybus_module_id *id);
+void gb_battery_disconnect(struct gb_module *gmod);
int gb_tty_init(void);
void gb_tty_exit(void);
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+
#include "greybus.h"
struct gb_i2c_device {
struct i2c_adapter *adapter;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
};
static const struct greybus_module_id id_table[] = {
int size, union i2c_smbus_data *data)
{
struct gb_i2c_device *gb_i2c_dev;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
gb_i2c_dev = i2c_get_adapdata(adap);
gmod = gb_i2c_dev->gmod;
.functionality = i2c_gb_func,
};
-int gb_i2c_probe(struct greybus_module *gmod,
+int gb_i2c_probe(struct gb_module *gmod,
const struct greybus_module_id *id)
{
struct gb_i2c_device *gb_i2c_dev;
return retval;
}
-void gb_i2c_disconnect(struct greybus_module *gmod)
+void gb_i2c_disconnect(struct gb_module *gmod)
{
struct gb_i2c_device *gb_i2c_dev;
--- /dev/null
+/*
+ * Greybus modules
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+
+/* XXX This could be per-host device */
+static DEFINE_SPINLOCK(gb_modules_lock);
+
+static int gb_module_match_one_id(struct gb_module *gmod,
+ const struct greybus_module_id *id)
+{
+ struct greybus_descriptor_module *module;
+
+ module = &gmod->module;
+
+ if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
+ (id->vendor != le16_to_cpu(module->vendor)))
+ return 0;
+
+ if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
+ (id->product != le16_to_cpu(module->product)))
+ return 0;
+
+ if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
+ (id->serial_number != le64_to_cpu(module->serial_number)))
+ return 0;
+
+ return 1;
+}
+
+const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
+ const struct greybus_module_id *id)
+{
+ if (id == NULL)
+ return NULL;
+
+ for (; id->vendor || id->product || id->serial_number ||
+ id->driver_info; id++) {
+ if (gb_module_match_one_id(gmod, id))
+ return id;
+ }
+
+ return NULL;
+}
+
+/*
+ * A Greybus module represents a user-replacable component on an Ara
+ * phone.
+ *
+ * Create a gb_module structure to represent a discovered module.
+ * The position within the Endo is encoded in the "module_id" argument.
+ * Returns a pointer to the new module or a null pointer if a
+ * failure occurs due to memory exhaustion.
+ */
+struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
+{
+ struct gb_module *module;
+
+ module = kzalloc(sizeof(*module), GFP_KERNEL);
+ if (!module)
+ return NULL;
+
+ module->hd = hd; /* XXX refcount? */
+ module->module_id = module_id;
+
+ spin_lock_irq(&gb_modules_lock);
+ list_add_tail(&module->links, &hd->modules);
+ spin_unlock_irq(&gb_modules_lock);
+
+ return module;
+}
+
+/*
+ * Tear down a previously set up module.
+ */
+void gb_module_destroy(struct gb_module *module)
+{
+ if (WARN_ON(!module))
+ return;
+
+ spin_lock_irq(&gb_modules_lock);
+ list_del(&module->links);
+ spin_unlock_irq(&gb_modules_lock);
+
+ /* kref_put(module->hd); */
+
+ kfree(module);
+}
--- /dev/null
+/*
+ * Greybus modules
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#ifndef __MODULE_H
+#define __MODULE_H
+
+/* Increase these values if needed */
+#define MAX_CPORTS_PER_MODULE 10
+#define MAX_STRINGS_PER_MODULE 10
+
+struct gb_module {
+ struct device dev;
+
+ struct list_head links; /* greybus_host_device->modules */
+ u8 module_id; /* Physical location within the Endo */
+
+ struct greybus_descriptor_module module;
+ int num_cports;
+ int num_strings;
+ u16 cport_ids[MAX_CPORTS_PER_MODULE];
+ struct gmod_string *string[MAX_STRINGS_PER_MODULE];
+
+ struct greybus_host_device *hd;
+
+ struct gb_i2c_device *gb_i2c_dev;
+ struct gb_gpio_device *gb_gpio_dev;
+ struct gb_sdio_host *gb_sdio_host;
+ struct gb_tty *gb_tty;
+ struct gb_usb_device *gb_usb_dev;
+ struct gb_battery *gb_battery;
+};
+#define to_gb_module(d) container_of(d, struct gb_module, dev)
+
+static inline void
+gb_module_set_drvdata(struct gb_module *gmod, void *data)
+{
+ dev_set_drvdata(&gmod->dev, data);
+}
+
+static inline void *gb_module_get_drvdata(struct gb_module *gmod)
+{
+ return dev_get_drvdata(&gmod->dev);
+}
+
+const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
+ const struct greybus_module_id *id);
+
+struct gb_module *gb_module_create(struct greybus_host_device *hd,
+ u8 module_id);
+void gb_module_destroy(struct gb_module *module);
+
+#endif /* __MODULE_H */
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
+
#include "greybus.h"
struct gb_sdio_host {
.get_ro = gb_sd_get_ro,
};
-int gb_sdio_probe(struct greybus_module *gmod,
+int gb_sdio_probe(struct gb_module *gmod,
const struct greybus_module_id *id)
{
struct mmc_host *mmc;
return 0;
}
-void gb_sdio_disconnect(struct greybus_module *gmod)
+void gb_sdio_disconnect(struct gb_module *gmod)
{
struct mmc_host *mmc;
struct gb_sdio_host *host;
#include <linux/device.h>
#include "greybus.h"
-
#include "kernel_ver.h"
/* Module fields */
-#define greybus_module_attr(field) \
+#define gb_module_attr(field) \
static ssize_t module_##field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
- struct greybus_module *gmod = to_greybus_module(dev); \
+ struct gb_module *gmod = to_gb_module(dev); \
return sprintf(buf, "%x\n", gmod->module.field); \
} \
static DEVICE_ATTR_RO(module_##field)
-greybus_module_attr(vendor);
-greybus_module_attr(product);
-greybus_module_attr(version);
+gb_module_attr(vendor);
+gb_module_attr(product);
+gb_module_attr(version);
static ssize_t module_serial_number_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
return sprintf(buf, "%llX\n",
(unsigned long long)le64_to_cpu(gmod->module.serial_number));
struct device_attribute *attr,
char *buf)
{
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
return sprintf(buf, "%s",
greybus_string(gmod, gmod->module.vendor_stringid));
struct device_attribute *attr,
char *buf)
{
- struct greybus_module *gmod = to_greybus_module(dev);
+ struct gb_module *gmod = to_gb_module(dev);
return sprintf(buf, "%s",
greybus_string(gmod, gmod->module.product_stringid));
static umode_t module_attrs_are_visible(struct kobject *kobj,
struct attribute *a, int n)
{
- struct greybus_module *gmod = to_greybus_module(kobj_to_dev(kobj));
+ struct gb_module *gmod = to_gb_module(kobj_to_dev(kobj));
if ((a == &dev_attr_module_vendor_string.attr) &&
(gmod->module.vendor_stringid))
#include "greybus.h"
struct test_device {
- struct greybus_module *gmod;
+ struct gb_module *gmod;
};
-int gb_register_cport_complete(struct greybus_module *gmod,
+int gb_register_cport_complete(struct gb_module *gmod,
gbuf_complete_t handler, u16 cport_id,
void *context);
void gb_deregister_cport_complete(u16 cport_id);
#include <linux/idr.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
+
#include "greybus.h"
+#include "module.h"
#define GB_NUM_MINORS 255 /* 255 is enough for anyone... */
#define GB_NAME "ttyGB"
struct gb_tty {
struct tty_port port;
- struct greybus_module *gmod;
+ struct gb_module *gmod;
u16 cport_id;
unsigned int minor;
unsigned char clocal;
};
-int gb_tty_probe(struct greybus_module *gmod,
+int gb_tty_probe(struct gb_module *gmod,
const struct greybus_module_id *id)
{
struct gb_tty *gb_tty;
return retval;
}
-void gb_tty_disconnect(struct greybus_module *gmod)
+void gb_tty_disconnect(struct gb_module *gmod)
{
struct gb_tty *gb_tty = gmod->gb_tty;
struct tty_struct *tty;