static void gb_bundle_release(struct device *dev)
{
struct gb_bundle *bundle = to_gb_bundle(dev);
- struct gb_connection *connection;
- struct gb_connection *tmp;
-
- list_for_each_entry_safe(connection, tmp, &bundle->connections,
- bundle_links) {
- gb_connection_destroy(connection);
- }
kfree(bundle->state);
+ kfree(bundle->cport_desc);
kfree(bundle);
}
u8 class_major;
u8 class_minor;
+ size_t num_cports;
+ struct greybus_descriptor_cport *cport_desc;
+
struct list_head connections;
u8 *state;
return gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
protocol_id);
}
+EXPORT_SYMBOL_GPL(gb_connection_create_dynamic);
static int gb_connection_hd_cport_enable(struct gb_connection *connection)
{
gb_connection_put(connection);
}
+EXPORT_SYMBOL_GPL(gb_connection_destroy);
void gb_connection_latency_tag_enable(struct gb_connection *connection)
{
return -ENODEV;
retval = driver->probe(bundle, id);
- if (retval)
+ if (retval) {
+ /*
+ * Catch buggy drivers that fail to destroy their connections.
+ */
+ WARN_ON(!list_empty(&bundle->connections));
+
return retval;
+ }
return 0;
}
driver->disconnect(bundle);
- /* Catch buggy drivers that fail to disable their connections. */
- list_for_each_entry(connection, &bundle->connections, bundle_links) {
- if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
- gb_connection_disable(connection);
- }
+ /* Catch buggy drivers that fail to destroy their connections. */
+ WARN_ON(!list_empty(&bundle->connections));
return 0;
}
struct legacy_data {
size_t num_cports;
+ struct gb_connection **connections;
};
static int legacy_probe(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
{
+ struct greybus_descriptor_cport *cport_desc;
struct legacy_data *data;
struct gb_connection *connection;
- int ret;
+ int i;
+ int ret = -ENOMEM;
+
+ dev_dbg(&bundle->dev,
+ "%s - bundle class = 0x%02x, num_cports = %zu\n",
+ __func__, bundle->class, bundle->num_cports);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->num_cports = 0;
- list_for_each_entry(connection, &bundle->connections, bundle_links)
- data->num_cports++;
+ data->num_cports = bundle->num_cports;
+ data->connections = kcalloc(data->num_cports,
+ sizeof(*data->connections),
+ GFP_KERNEL);
+ if (!data->connections)
+ goto err_free_data;
- dev_dbg(&bundle->dev,
- "%s - bundle class = 0x%02x, num_cports = %zu\n",
- __func__, bundle->class, data->num_cports);
+ for (i = 0; i < data->num_cports; ++i) {
+ cport_desc = &bundle->cport_desc[i];
+
+ connection = gb_connection_create_dynamic(bundle->intf,
+ bundle,
+ le16_to_cpu(cport_desc->id),
+ cport_desc->protocol_id);
+ if (!connection)
+ goto err_connections_destroy;
+
+ data->connections[i] = connection;
+ }
greybus_set_drvdata(bundle, data);
- list_for_each_entry(connection, &bundle->connections, bundle_links) {
+ for (i = 0; i < data->num_cports; ++i) {
+ connection = data->connections[i];
dev_dbg(&bundle->dev, "enabling connection %s\n",
connection->name);
return 0;
err_connections_disable:
- list_for_each_entry_reverse(connection, &bundle->connections,
- bundle_links) {
- legacy_connection_exit(connection);
- }
+ for (--i; i >= 0; --i)
+ legacy_connection_exit(data->connections[i]);
+err_connections_destroy:
+ for (i = 0; i < data->num_cports; ++i)
+ gb_connection_destroy(data->connections[i]);
+ kfree(data->connections);
+err_free_data:
kfree(data);
return ret;
static void legacy_disconnect(struct gb_bundle *bundle)
{
struct legacy_data *data = greybus_get_drvdata(bundle);
- struct gb_connection *connection;
+ int i;
dev_dbg(&bundle->dev, "%s - bundle class = 0x%02x\n", __func__,
bundle->class);
- list_for_each_entry_reverse(connection, &bundle->connections,
- bundle_links) {
- legacy_connection_exit(connection);
+ for (i = 0; i < data->num_cports; ++i) {
+ legacy_connection_exit(data->connections[i]);
+ gb_connection_destroy(data->connections[i]);
}
+ kfree(data->connections);
kfree(data);
}
*/
static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
{
- struct gb_connection *connection;
struct gb_interface *intf = bundle->intf;
+ struct greybus_descriptor_cport *desc_cport;
struct manifest_desc *desc;
struct manifest_desc *next;
+ LIST_HEAD(list);
u8 bundle_id = bundle->id;
- u8 protocol_id;
u16 cport_id;
u32 count = 0;
+ int i;
/* Set up all cport descriptors associated with this bundle */
list_for_each_entry_safe(desc, next, &intf->manifest_descs, links) {
- struct greybus_descriptor_cport *desc_cport;
-
if (desc->type != GREYBUS_TYPE_CPORT)
continue;
if (cport_id > CPORT_ID_MAX)
goto exit;
- /* Found one. Set up its function structure */
- protocol_id = desc_cport->protocol_id;
+ /* Found one, move it to our temporary list. */
+ list_move(&desc->links, &list);
+ count++;
+ }
- connection = gb_connection_create_dynamic(intf, bundle,
- cport_id,
- protocol_id);
- if (!connection)
- goto exit;
+ if (!count)
+ return 0;
- count++;
+ bundle->cport_desc = kcalloc(count, sizeof(*bundle->cport_desc),
+ GFP_KERNEL);
+ if (!bundle->cport_desc)
+ goto exit;
+
+ bundle->num_cports = count;
+
+ i = 0;
+ list_for_each_entry_safe(desc, next, &list, links) {
+ desc_cport = desc->data;
+ memcpy(&bundle->cport_desc[i++], desc_cport,
+ sizeof(*desc_cport));
/* Release the cport descriptor */
release_manifest_descriptor(desc);
return count;
exit:
-
+ release_cport_descriptors(&list, bundle_id);
/*
* Free all cports for this bundle to avoid 'excess descriptors'
* warnings.