int gb_connection_bind_protocol(struct gb_connection *connection) { struct gb_protocol *protocol; int ret; /* If we already have a protocol bound here, just return */ if (connection->protocol) return 0; protocol = gb_protocol_get(connection->protocol_id, connection->major, connection->minor); if (!protocol) return 0; connection->protocol = protocol; /* * If we have a valid device_id for the interface block, then we have an * active device, so bring up the connection at the same time. */ if ((!connection->bundle && protocol->flags & GB_PROTOCOL_NO_BUNDLE) || connection->bundle->intf->device_id != GB_DEVICE_ID_BAD) { ret = gb_connection_init(connection); if (ret) { gb_protocol_put(protocol); connection->protocol = NULL; return ret; } } return 0; }
static int legacy_connection_create(struct legacy_connection *lc, struct gb_bundle *bundle, struct greybus_descriptor_cport *desc) { struct gb_connection *connection; struct gb_protocol *protocol; gb_request_handler_t handler; u8 major, minor; int ret; /* * The legacy protocols have always been looked up using a hard-coded * version of 0.1, despite (or perhaps rather, due to) the fact that * module version negotiation could not take place until after the * protocol was bound. */ major = 0; minor = 1; protocol = gb_protocol_get(desc->protocol_id, major, minor); if (!protocol) { dev_err(&bundle->dev, "protocol 0x%02x version %u.%u not found\n", desc->protocol_id, major, minor); return -EPROTONOSUPPORT; } if (protocol->request_recv) handler = legacy_request_handler; else handler = NULL; connection = gb_connection_create(bundle, le16_to_cpu(desc->id), handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto err_protocol_put; } /* * NOTE: We need to keep a pointer to the protocol in the actual * connection structure for now. */ connection->protocol = protocol; lc->connection = connection; lc->protocol = protocol; return 0; err_protocol_put: gb_protocol_put(protocol); return ret; }
static void legacy_connection_destroy(struct legacy_connection *lc) { if (!lc->connection) return; lc->connection->protocol = NULL; gb_connection_destroy(lc->connection); gb_protocol_put(lc->protocol); }
/* * Tear down a previously set up connection. */ void gb_connection_destroy(struct gb_connection *connection) { struct ida *id_map; if (WARN_ON(!connection)) return; gb_connection_exit(connection); spin_lock_irq(&gb_connections_lock); list_del(&connection->bundle_links); list_del(&connection->hd_links); spin_unlock_irq(&gb_connections_lock); if (connection->protocol) gb_protocol_put(connection->protocol); connection->protocol = NULL; id_map = &connection->hd->cport_id_map; ida_simple_remove(id_map, connection->hd_cport_id); connection->hd_cport_id = CPORT_ID_BAD; device_unregister(&connection->dev); }