aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/greybus/hd.c15
-rw-r--r--drivers/staging/greybus/hd.h2
-rw-r--r--drivers/staging/greybus/svc.c68
-rw-r--r--drivers/staging/greybus/svc.h5
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);