diff options
-rw-r--r-- | drivers/staging/greybus/hd.c | 15 | ||||
-rw-r--r-- | drivers/staging/greybus/hd.h | 2 | ||||
-rw-r--r-- | drivers/staging/greybus/svc.c | 68 | ||||
-rw-r--r-- | drivers/staging/greybus/svc.h | 5 |
4 files changed, 67 insertions, 23 deletions
diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c index 469b31e00237..bff6861b8af7 100644 --- a/drivers/staging/greybus/hd.c +++ b/drivers/staging/greybus/hd.c @@ -21,8 +21,8 @@ static void gb_hd_release(struct device *dev) { struct gb_host_device *hd = to_gb_host_device(dev); - if (hd->svc_connection) - gb_connection_destroy(hd->svc_connection); + if (hd->svc) + gb_svc_put(hd->svc); ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id); ida_destroy(&hd->cport_id_map); kfree(hd); @@ -95,10 +95,9 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, device_initialize(&hd->dev); dev_set_name(&hd->dev, "greybus%d", hd->bus_id); - hd->svc_connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID, - GREYBUS_PROTOCOL_SVC); - if (!hd->svc_connection) { - dev_err(&hd->dev, "failed to create svc connection\n"); + hd->svc = gb_svc_create(hd); + if (!hd->svc) { + dev_err(&hd->dev, "failed to create svc\n"); put_device(&hd->dev); return ERR_PTR(-ENOMEM); } @@ -115,7 +114,7 @@ int gb_hd_add(struct gb_host_device *hd) if (ret) return ret; - ret = gb_connection_init(hd->svc_connection); + ret = gb_svc_add(hd->svc); if (ret) { device_del(&hd->dev); return ret; @@ -129,7 +128,7 @@ void gb_hd_del(struct gb_host_device *hd) { gb_interfaces_remove(hd); - gb_connection_exit(hd->svc_connection); + gb_svc_del(hd->svc); device_del(&hd->dev); } diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h index 5612b489dd24..d828129475cd 100644 --- a/drivers/staging/greybus/hd.h +++ b/drivers/staging/greybus/hd.h @@ -41,8 +41,6 @@ struct gb_host_device { size_t buffer_size_max; struct gb_svc *svc; - struct gb_connection *svc_connection; - /* Private data for the host driver */ unsigned long hd_priv[0] __aligned(sizeof(s64)); }; diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c index 2a8f79e95b3c..c013083d79f6 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/staging/greybus/svc.c @@ -661,6 +661,8 @@ static void gb_svc_release(struct device *dev) { struct gb_svc *svc = to_gb_svc(dev); + if (svc->connection) + gb_connection_destroy(svc->connection); ida_destroy(&svc->device_id_map); destroy_workqueue(svc->wq); kfree(svc); @@ -671,19 +673,18 @@ struct device_type greybus_svc_type = { .release = gb_svc_release, }; -static int gb_svc_connection_init(struct gb_connection *connection) +struct gb_svc *gb_svc_create(struct gb_host_device *hd) { - struct gb_host_device *hd = connection->hd; struct gb_svc *svc; svc = kzalloc(sizeof(*svc), GFP_KERNEL); if (!svc) - return -ENOMEM; + return NULL; svc->wq = alloc_workqueue("%s:svc", WQ_UNBOUND, 1, dev_name(&hd->dev)); if (!svc->wq) { kfree(svc); - return -ENOMEM; + return NULL; } svc->dev.parent = &hd->dev; @@ -697,30 +698,71 @@ static int gb_svc_connection_init(struct gb_connection *connection) ida_init(&svc->device_id_map); svc->state = GB_SVC_STATE_RESET; - svc->connection = connection; svc->hd = hd; - connection->private = svc; - hd->svc = svc; + svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID, + GREYBUS_PROTOCOL_SVC); + if (!svc->connection) { + dev_err(&svc->dev, "failed to create connection\n"); + put_device(&svc->dev); + return NULL; + } + + svc->connection->private = svc; - return 0; + return svc; } -static void gb_svc_connection_exit(struct gb_connection *connection) +int gb_svc_add(struct gb_svc *svc) { - struct gb_svc *svc = connection->private; + int ret; + /* + * The SVC protocol is currently driven by the SVC, so the SVC device + * is added from the connection request handler when enough + * information has been received. + */ + ret = gb_connection_init(svc->connection); + if (ret) + return ret; + + return 0; +} + +void gb_svc_del(struct gb_svc *svc) +{ + /* + * The SVC device may have been registered from the request handler. + */ if (device_is_registered(&svc->dev)) device_del(&svc->dev); - flush_workqueue(svc->wq); + gb_connection_exit(svc->connection); - connection->hd->svc = NULL; - connection->private = NULL; + flush_workqueue(svc->wq); +} +void gb_svc_put(struct gb_svc *svc) +{ put_device(&svc->dev); } +static int gb_svc_connection_init(struct gb_connection *connection) +{ + struct gb_svc *svc = connection->private; + + dev_dbg(&svc->dev, "%s\n", __func__); + + return 0; +} + +static void gb_svc_connection_exit(struct gb_connection *connection) +{ + struct gb_svc *svc = connection->private; + + dev_dbg(&svc->dev, "%s\n", __func__); +} + static struct gb_protocol svc_protocol = { .name = "svc", .id = GREYBUS_PROTOCOL_SVC, diff --git a/drivers/staging/greybus/svc.h b/drivers/staging/greybus/svc.h index ca0f71d059b1..b7cb7e4c6cf5 100644 --- a/drivers/staging/greybus/svc.h +++ b/drivers/staging/greybus/svc.h @@ -30,6 +30,11 @@ struct gb_svc { }; #define to_gb_svc(d) container_of(d, struct gb_svc, d) +struct gb_svc *gb_svc_create(struct gb_host_device *hd); +int gb_svc_add(struct gb_svc *svc); +void gb_svc_del(struct gb_svc *svc); +void gb_svc_put(struct gb_svc *svc); + int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id); int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id, u8 intf2_id, u16 cport2_id, bool boot_over_unipro); |