static u32 gb_manifest_parse_cports()

in manifest.c [228:305]


static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
{
	struct gb_interface *intf = bundle->intf;
	struct greybus_descriptor_cport *desc_cport;
	struct manifest_desc *desc, *next, *tmp;
	LIST_HEAD(list);
	u8 bundle_id = bundle->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) {
		if (desc->type != GREYBUS_TYPE_CPORT)
			continue;

		desc_cport = desc->data;
		if (desc_cport->bundle != bundle_id)
			continue;

		cport_id = le16_to_cpu(desc_cport->id);
		if (cport_id > CPORT_ID_MAX)
			goto exit;

		/* Nothing else should have its cport_id as control cport id */
		if (cport_id == GB_CONTROL_CPORT_ID) {
			dev_err(&bundle->dev, "invalid cport id found (%02u)\n",
				cport_id);
			goto exit;
		}

		/*
		 * Found one, move it to our temporary list after checking for
		 * duplicates.
		 */
		list_for_each_entry(tmp, &list, links) {
			desc_cport = tmp->data;
			if (cport_id == le16_to_cpu(desc_cport->id)) {
				dev_err(&bundle->dev,
					"duplicate CPort %u found\n", cport_id);
				goto exit;
			}
		}
		list_move_tail(&desc->links, &list);
		count++;
	}

	if (!count)
		return 0;

	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.
	 */
	release_cport_descriptors(&intf->manifest_descs, bundle_id);

	return 0;	/* Error; count should also be 0 */
}