{
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);
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);
}
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;
{
gb_interfaces_remove(hd);
- gb_connection_exit(hd->svc_connection);
+ gb_svc_del(hd->svc);
device_del(&hd->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);
.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;
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,
};
#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);