diff --git a/drivers/staging/greybus/battery-gb.c b/drivers/staging/greybus/battery-gb.c index 592b68d5115a..b7d8e2c8fb85 100644 --- a/drivers/staging/greybus/battery-gb.c +++ b/drivers/staging/greybus/battery-gb.c @@ -359,7 +359,7 @@ static enum power_supply_property battery_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; -int gb_battery_device_init(struct gb_connection *connection) +static int gb_battery_connection_init(struct gb_connection *connection) { struct gb_battery *gb; struct power_supply *b; @@ -369,7 +369,7 @@ int gb_battery_device_init(struct gb_connection *connection) if (!gb) return -ENOMEM; - gb->connection = connection; // FIXME refcount! + gb->connection = connection; connection->private = gb; /* Check the version */ @@ -397,7 +397,7 @@ int gb_battery_device_init(struct gb_connection *connection) return 0; } -void gb_battery_device_exit(struct gb_connection *connection) +static void gb_battery_connection_exit(struct gb_connection *connection) { struct gb_battery *gb = connection->private; @@ -405,29 +405,7 @@ void gb_battery_device_exit(struct gb_connection *connection) kfree(gb); } -void gb_battery_disconnect(struct gb_module *gmod) -{ -#if 0 - struct gb_battery *gb; - - gb = gmod->gb_battery; - if (!gb) - return; - - power_supply_unregister(&gb->bat); - - kfree(gb); -#endif -} - -#if 0 -static struct greybus_driver battery_gb_driver = { - .probe = gb_battery_probe, - .disconnect = gb_battery_disconnect, - .id_table = id_table, +struct gb_connection_handler gb_battery_connection_handler = { + .connection_init = gb_battery_connection_init, + .connection_exit = gb_battery_connection_exit, }; - -module_greybus_driver(battery_gb_driver); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Greg Kroah-Hartman "); -#endif diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index bbae16346050..f76855c609c3 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -170,7 +170,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, return NULL; } - connection->interface = interface; /* XXX refcount? */ + connection->interface = interface; connection->interface_cport_id = cport_id; connection->protocol = protocol; connection->state = GB_CONNECTION_STATE_DISABLED; @@ -267,17 +267,19 @@ int gb_connection_init(struct gb_connection *connection) connection->state = GB_CONNECTION_STATE_ENABLED; switch (connection->protocol) { case GREYBUS_PROTOCOL_I2C: - ret = gb_i2c_device_init(connection); + connection->handler = &gb_i2c_connection_handler; break; case GREYBUS_PROTOCOL_GPIO: - ret = gb_gpio_controller_init(connection); + connection->handler = &gb_gpio_connection_handler; break; case GREYBUS_PROTOCOL_BATTERY: - ret = gb_battery_device_init(connection); + connection->handler = &gb_battery_connection_handler; + break; + case GREYBUS_PROTOCOL_UART: + connection->handler = &gb_uart_connection_handler; break; case GREYBUS_PROTOCOL_CONTROL: case GREYBUS_PROTOCOL_AP: - case GREYBUS_PROTOCOL_UART: case GREYBUS_PROTOCOL_HID: case GREYBUS_PROTOCOL_LED: case GREYBUS_PROTOCOL_VENDOR: @@ -296,26 +298,10 @@ int gb_connection_init(struct gb_connection *connection) void gb_connection_exit(struct gb_connection *connection) { - connection->state = GB_CONNECTION_STATE_DESTROYING; - - switch (connection->protocol) { - case GREYBUS_PROTOCOL_I2C: - gb_i2c_device_exit(connection); - break; - case GREYBUS_PROTOCOL_GPIO: - gb_gpio_controller_exit(connection); - break; - case GREYBUS_PROTOCOL_BATTERY: - gb_battery_device_exit(connection); - break; - case GREYBUS_PROTOCOL_CONTROL: - case GREYBUS_PROTOCOL_AP: - case GREYBUS_PROTOCOL_UART: - case GREYBUS_PROTOCOL_HID: - case GREYBUS_PROTOCOL_VENDOR: - default: - gb_connection_err(connection, "unimplemented protocol %u", - (u32)connection->protocol); - break; + if (!connection->handler) { + gb_connection_err(connection, "uninitialized connection"); + return; } + connection->state = GB_CONNECTION_STATE_DESTROYING; + connection->handler->connection_exit(connection); } diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index 17fde8fa285d..88a9398c79d6 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -21,6 +21,15 @@ enum gb_connection_state { GB_CONNECTION_STATE_DESTROYING = 4, }; +struct gb_connection; +typedef int (*gb_connection_init_t)(struct gb_connection *); +typedef void (*gb_connection_exit_t)(struct gb_connection *); + +struct gb_connection_handler { + gb_connection_init_t connection_init; + gb_connection_exit_t connection_exit; +}; + struct gb_connection { struct greybus_host_device *hd; struct gb_interface *interface; @@ -37,6 +46,8 @@ struct gb_connection { struct rb_root pending; /* awaiting reponse */ atomic_t op_cycle; + struct gb_connection_handler *handler; + void *private; }; #define to_gb_connection(d) container_of(d, struct gb_connection, dev) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 61fd6906541d..7c0cb6227b1f 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -282,17 +282,8 @@ static int __init gb_init(void) goto error_operation; } - retval = gb_tty_init(); - if (retval) { - pr_err("gb_tty_init failed\n"); - goto error_tty; - } - return 0; -error_tty: - gb_operation_exit(); - error_operation: gb_gbuf_exit(); @@ -310,7 +301,6 @@ error_bus: static void __exit gb_exit(void) { - gb_tty_exit(); gb_operation_exit(); gb_gbuf_exit(); gb_ap_exit(); diff --git a/drivers/staging/greybus/gpio-gb.c b/drivers/staging/greybus/gpio-gb.c index 069ee69dc0e7..6ba1f633a436 100644 --- a/drivers/staging/greybus/gpio-gb.c +++ b/drivers/staging/greybus/gpio-gb.c @@ -29,7 +29,6 @@ struct gb_gpio_controller { struct gb_gpio_line *lines; struct gpio_chip chip; - struct gpio_chip *gpio; }; #define gpio_chip_to_gb_gpio_controller(chip) \ container_of(chip, struct gb_gpio_controller, chip) @@ -733,7 +732,7 @@ static int gb_gpio_controller_setup(struct gb_gpio_controller *gb_gpio_controlle return ret; } -int gb_gpio_controller_init(struct gb_connection *connection) +static int gb_gpio_connection_init(struct gb_connection *connection) { struct gb_gpio_controller *gb_gpio_controller; struct gpio_chip *gpio; @@ -781,7 +780,7 @@ out_err: return ret; } -void gb_gpio_controller_exit(struct gb_connection *connection) +static void gb_gpio_connection_exit(struct gb_connection *connection) { struct gb_gpio_controller *gb_gpio_controller = connection->private; @@ -793,6 +792,11 @@ void gb_gpio_controller_exit(struct gb_connection *connection) kfree(gb_gpio_controller); } +struct gb_connection_handler gb_gpio_connection_handler = { + .connection_init = gb_gpio_connection_init, + .connection_exit = gb_gpio_connection_exit, +}; + #if 0 MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Greybus GPIO driver"); diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 1e3f31d4a058..3a8d8f1c077c 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -151,7 +151,6 @@ struct gbuf { struct gb_i2c_device; struct gb_gpio_device; -struct gb_sdio_host; struct gb_tty; struct gb_usb_device; struct gb_battery; @@ -266,17 +265,14 @@ void gb_deregister_cport_complete(u16 cport_id); extern struct bus_type greybus_bus_type; extern const struct attribute_group *greybus_module_groups[]; -int gb_i2c_device_init(struct gb_connection *connection); -void gb_i2c_device_exit(struct gb_connection *connection); +extern struct gb_connection_handler gb_i2c_connection_handler; +extern struct gb_connection_handler gb_gpio_connection_handler; +extern struct gb_connection_handler gb_battery_connection_handler; +extern struct gb_connection_handler gb_uart_connection_handler; +extern struct gb_connection_handler gb_sdio_connection_handler; -int gb_battery_device_init(struct gb_connection *connection); -void gb_battery_device_exit(struct gb_connection *connection); - -int gb_gpio_controller_init(struct gb_connection *connection); -void gb_gpio_controller_exit(struct gb_connection *connection); - -int gb_tty_init(void); -void gb_tty_exit(void); +int gb_uart_device_init(struct gb_connection *connection); +void gb_uart_device_exit(struct gb_connection *connection); int svc_set_route_send(struct gb_interface *interface, struct greybus_host_device *hd); diff --git a/drivers/staging/greybus/i2c-gb.c b/drivers/staging/greybus/i2c-gb.c index 9ecfd795ea84..5d3e2f2061b0 100644 --- a/drivers/staging/greybus/i2c-gb.c +++ b/drivers/staging/greybus/i2c-gb.c @@ -22,7 +22,7 @@ struct gb_i2c_device { u16 timeout_msec; u8 retries; - struct i2c_adapter *adapter; + struct i2c_adapter adapter; }; /* Version of the Greybus i2c protocol we support */ @@ -466,10 +466,10 @@ static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev) return gb_i2c_timeout_operation(gb_i2c_dev, GB_I2C_TIMEOUT_DEFAULT); } -int gb_i2c_device_init(struct gb_connection *connection) +static int gb_i2c_connection_init(struct gb_connection *connection) { struct gb_i2c_device *gb_i2c_dev; - struct i2c_adapter *adapter = NULL; + struct i2c_adapter *adapter; int ret; gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL); @@ -482,13 +482,8 @@ int gb_i2c_device_init(struct gb_connection *connection) if (ret) goto out_err; - /* Looks good; allocate and set up our i2c adapter */ - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); - if (!adapter) { - ret = -ENOMEM; - goto out_err; - } - + /* Looks good; up our i2c adapter */ + adapter = &gb_i2c_dev->adapter; adapter->owner = THIS_MODULE; adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adapter->algo = &gb_i2c_algorithm; @@ -504,28 +499,30 @@ int gb_i2c_device_init(struct gb_connection *connection) if (ret) goto out_err; - gb_i2c_dev->adapter = adapter; connection->private = gb_i2c_dev; return 0; out_err: - kfree(adapter); /* kref_put(gb_i2c_dev->connection) */ kfree(gb_i2c_dev); return ret; } -void gb_i2c_device_exit(struct gb_connection *connection) +static void gb_i2c_connection_exit(struct gb_connection *connection) { struct gb_i2c_device *gb_i2c_dev = connection->private; - i2c_del_adapter(gb_i2c_dev->adapter); - kfree(gb_i2c_dev->adapter); + i2c_del_adapter(&gb_i2c_dev->adapter); /* kref_put(gb_i2c_dev->connection) */ kfree(gb_i2c_dev); } +struct gb_connection_handler gb_i2c_connection_handler = { + .connection_init = gb_i2c_connection_init, + .connection_exit = gb_i2c_connection_exit, +}; + #if 0 module_greybus_driver(i2c_gb_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index a7375a2809d5..163cdc439e0c 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -61,7 +61,7 @@ gb_interface_create(struct gb_module *gmod, u8 interface_id) if (!interface) return NULL; - interface->gmod = gmod; /* XXX refcount? */ + interface->gmod = gmod; interface->id = interface_id; interface->device_id = 0xff; /* Invalid device id to start with */ INIT_LIST_HEAD(&interface->connections); diff --git a/drivers/staging/greybus/kernel_ver.h b/drivers/staging/greybus/kernel_ver.h index e0fea182c3b5..e4cda5ce65fa 100644 --- a/drivers/staging/greybus/kernel_ver.h +++ b/drivers/staging/greybus/kernel_ver.h @@ -48,4 +48,19 @@ static inline void gb_gpiochip_remove(struct gpio_chip *chip) } #endif +/* + * ATTRIBUTE_GROUPS showed up in 3.11-rc2, but we need to build on 3.10, so add + * it here. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) +#define ATTRIBUTE_GROUPS(name) \ +static const struct attribute_group name##_group = { \ + .attrs = name##_attrs, \ +}; \ +static const struct attribute_group *name##_groups[] = { \ + &name##_group, \ + NULL, \ +} +#endif + #endif /* __GREYBUS_KERNEL_VER_H */ diff --git a/drivers/staging/greybus/module.c b/drivers/staging/greybus/module.c index 54e8f9e68d25..f65aea680be7 100644 --- a/drivers/staging/greybus/module.c +++ b/drivers/staging/greybus/module.c @@ -82,7 +82,7 @@ struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id) return NULL; gmod->hd = hd; /* XXX refcount? */ - gmod->module_id = module_id; /* XXX check for dups */ + gmod->module_id = module_id; INIT_LIST_HEAD(&gmod->interfaces); spin_lock_irq(&gb_modules_lock); diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index 736c2c167f85..dc354252bef5 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -363,7 +363,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, operation = kmem_cache_zalloc(gb_operation_cache, gfp_flags); if (!operation) return NULL; - operation->connection = connection; /* XXX refcount? */ + operation->connection = connection; operation->request = gb_operation_gbuf_create(operation, type, request_size, diff --git a/drivers/staging/greybus/sdio-gb.c b/drivers/staging/greybus/sdio-gb.c index 19c7c4ac81eb..e9c311780556 100644 --- a/drivers/staging/greybus/sdio-gb.c +++ b/drivers/staging/greybus/sdio-gb.c @@ -13,6 +13,7 @@ #include "greybus.h" struct gb_sdio_host { + struct gb_connection *connection; struct mmc_host *mmc; struct mmc_request *mrq; // FIXME - some lock? @@ -45,13 +46,12 @@ static const struct mmc_host_ops gb_sd_ops = { .get_ro = gb_sd_get_ro, }; -int gb_sdio_probe(struct gb_module *gmod, - const struct greybus_module_id *id) +static int gb_sdio_connection_init(struct gb_connection *connection) { struct mmc_host *mmc; struct gb_sdio_host *host; - mmc = mmc_alloc_host(sizeof(struct gb_sdio_host), &gmod->dev); + mmc = mmc_alloc_host(sizeof(struct gb_sdio_host), &connection->dev); if (!mmc) return -ENOMEM; @@ -60,36 +60,29 @@ int gb_sdio_probe(struct gb_module *gmod, mmc->ops = &gb_sd_ops; // FIXME - set up size limits we can handle. + // FIXME - register the host controller. - // gmod->gb_sdio_host = host; + host->connection = connection; + connection->private = host; return 0; } -void gb_sdio_disconnect(struct gb_module *gmod) +static void gb_sdio_connection_exit(struct gb_connection *connection) { -#if 0 struct mmc_host *mmc; struct gb_sdio_host *host; - host = gmod->gb_sdio_host; + host = connection->private; if (!host) return; mmc = host->mmc; mmc_remove_host(mmc); mmc_free_host(mmc); -#endif + connection->private = NULL; } -#if 0 -static struct greybus_driver sd_gb_driver = { - .probe = gb_sdio_probe, - .disconnect = gb_sdio_disconnect, - .id_table = id_table, +struct gb_connection_handler gb_sdio_connection_handler = { + .connection_init = gb_sdio_connection_init, + .connection_exit = gb_sdio_connection_exit, }; - -module_greybus_driver(sd_gb_driver); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Greybus SD/MMC Host driver"); -MODULE_AUTHOR("Greg Kroah-Hartman "); -#endif diff --git a/drivers/staging/greybus/uart-gb.c b/drivers/staging/greybus/uart-gb.c index 301868cd5878..f88a301eb9fe 100644 --- a/drivers/staging/greybus/uart-gb.c +++ b/drivers/staging/greybus/uart-gb.c @@ -35,7 +35,7 @@ struct gb_tty { struct tty_port port; - struct gb_module *gmod; + struct gb_connection *connection; u16 cport_id; unsigned int minor; unsigned char clocal; @@ -59,6 +59,10 @@ static const struct greybus_module_id id_table[] = { static struct tty_driver *gb_tty_driver; static DEFINE_IDR(tty_minors); static DEFINE_MUTEX(table_lock); +static atomic_t reference_count = ATOMIC_INIT(0); + +static int gb_tty_init(void); +static void gb_tty_exit(void); static struct gb_tty *get_gb_by_minor(unsigned minor) { @@ -386,14 +390,22 @@ static const struct tty_operations gb_ops = { }; -int gb_tty_probe(struct gb_module *gmod, - const struct greybus_module_id *id) +static int gb_uart_connection_init(struct gb_connection *connection) { struct gb_tty *gb_tty; struct device *tty_dev; int retval; int minor; + /* First time here, initialize the tty structures */ + if (atomic_inc_return(&reference_count) == 1) { + retval = gb_tty_init(); + if (retval) { + atomic_dec(&reference_count); + return retval; + } + } + gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL); if (!gb_tty) return -ENOMEM; @@ -401,14 +413,14 @@ int gb_tty_probe(struct gb_module *gmod, minor = alloc_minor(gb_tty); if (minor < 0) { if (minor == -ENOSPC) { - dev_err(&gmod->dev, "no more free minor numbers\n"); + dev_err(&connection->dev, "no more free minor numbers\n"); return -ENODEV; } return minor; } gb_tty->minor = minor; - gb_tty->gmod = gmod; + gb_tty->connection = connection; spin_lock_init(&gb_tty->write_lock); spin_lock_init(&gb_tty->read_lock); init_waitqueue_head(&gb_tty->wioctl); @@ -416,10 +428,10 @@ int gb_tty_probe(struct gb_module *gmod, /* FIXME - allocate gb buffers */ - gmod->gb_tty = gb_tty; + connection->private = gb_tty; tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor, - &gmod->dev); + &connection->dev); if (IS_ERR(tty_dev)) { retval = PTR_ERR(tty_dev); goto error; @@ -427,14 +439,14 @@ int gb_tty_probe(struct gb_module *gmod, return 0; error: - gmod->gb_tty = NULL; + connection->private = NULL; release_minor(gb_tty); return retval; } -void gb_tty_disconnect(struct gb_module *gmod) +static void gb_uart_connection_exit(struct gb_connection *connection) { - struct gb_tty *gb_tty = gmod->gb_tty; + struct gb_tty *gb_tty = connection->private; struct tty_struct *tty; if (!gb_tty) @@ -444,7 +456,7 @@ void gb_tty_disconnect(struct gb_module *gmod) gb_tty->disconnected = true; wake_up_all(&gb_tty->wioctl); - gmod->gb_tty = NULL; + connection->private = NULL; mutex_unlock(&gb_tty->mutex); tty = tty_port_tty_get(&gb_tty->port); @@ -461,17 +473,13 @@ void gb_tty_disconnect(struct gb_module *gmod) tty_port_put(&gb_tty->port); kfree(gb_tty); + + /* If last device is gone, tear down the tty structures */ + if (atomic_dec_return(&reference_count) == 0) + gb_tty_exit(); } -#if 0 -static struct greybus_driver tty_gb_driver = { - .probe = gb_tty_probe, - .disconnect = gb_tty_disconnect, - .id_table = id_table, -}; -#endif - -int __init gb_tty_init(void) +static int gb_tty_init(void) { int retval = 0; @@ -499,40 +507,25 @@ int __init gb_tty_init(void) goto fail_put_gb_tty; } -#if 0 - retval = greybus_register(&tty_gb_driver); - if (retval) { - pr_err("Can not register greybus driver.\n"); - goto fail_unregister_gb_tty; - } -#endif - return 0; -/* fail_unregister_gb_tty: */ - tty_unregister_driver(gb_tty_driver); fail_put_gb_tty: put_tty_driver(gb_tty_driver); fail_unregister_dev: return retval; } -void __exit gb_tty_exit(void) +static void gb_tty_exit(void) { int major = MAJOR(gb_tty_driver->major); int minor = gb_tty_driver->minor_start; -#if 0 - greybus_deregister(&tty_gb_driver); -#endif tty_unregister_driver(gb_tty_driver); put_tty_driver(gb_tty_driver); unregister_chrdev_region(MKDEV(major, minor), GB_NUM_MINORS); } -#if 0 -module_init(gb_tty_init); -module_exit(gb_tty_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Greg Kroah-Hartman "); -#endif +struct gb_connection_handler gb_uart_connection_handler = { + .connection_init = gb_uart_connection_init, + .connection_exit = gb_uart_connection_exit, +};