drivers/hsi/hsi_core.c

Source file repositories/reference/linux-study-clean/drivers/hsi/hsi_core.c

File Facts

System
Linux kernel
Corpus path
drivers/hsi/hsi_core.c
Extension
.c
Size
18081 bytes
Lines
761
Domain
Driver Families
Bucket
drivers/hsi
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static int hsi_bus_match(struct device *dev, const struct device_driver *driver)
{
	if (of_driver_match_device(dev, driver))
		return true;

	if (strcmp(dev_name(dev), driver->name) == 0)
		return true;

	return false;
}

static const struct bus_type hsi_bus_type = {
	.name		= "hsi",
	.dev_groups	= hsi_bus_dev_groups,
	.match		= hsi_bus_match,
	.uevent		= hsi_bus_uevent,
};

static void hsi_client_release(struct device *dev)
{
	struct hsi_client *cl = to_hsi_client(dev);

	kfree(cl->tx_cfg.channels);
	kfree(cl->rx_cfg.channels);
	kfree(cl);
}

struct hsi_client *hsi_new_client(struct hsi_port *port,
						struct hsi_board_info *info)
{
	struct hsi_client *cl;
	size_t size;

	cl = kzalloc_obj(*cl);
	if (!cl)
		goto err;

	cl->tx_cfg = info->tx_cfg;
	if (cl->tx_cfg.channels) {
		size = cl->tx_cfg.num_channels * sizeof(*cl->tx_cfg.channels);
		cl->tx_cfg.channels = kmemdup(info->tx_cfg.channels, size,
					      GFP_KERNEL);
		if (!cl->tx_cfg.channels)
			goto err_tx;
	}

	cl->rx_cfg = info->rx_cfg;
	if (cl->rx_cfg.channels) {
		size = cl->rx_cfg.num_channels * sizeof(*cl->rx_cfg.channels);
		cl->rx_cfg.channels = kmemdup(info->rx_cfg.channels, size,
					      GFP_KERNEL);
		if (!cl->rx_cfg.channels)
			goto err_rx;
	}

	cl->device.bus = &hsi_bus_type;
	cl->device.parent = &port->device;
	cl->device.release = hsi_client_release;
	dev_set_name(&cl->device, "%s", info->name);
	cl->device.platform_data = info->platform_data;
	if (info->archdata)
		cl->device.archdata = *info->archdata;
	if (device_register(&cl->device) < 0) {
		pr_err("hsi: failed to register client: %s\n", info->name);
		put_device(&cl->device);
		goto err;
	}

	return cl;
err_rx:
	kfree(cl->tx_cfg.channels);
err_tx:
	kfree(cl);
err:
	return NULL;
}
EXPORT_SYMBOL_GPL(hsi_new_client);

static void hsi_scan_board_info(struct hsi_controller *hsi)
{
	struct hsi_cl_info *cl_info;
	struct hsi_port	*p;

	list_for_each_entry(cl_info, &hsi_board_list, list)
		if (cl_info->info.hsi_id == hsi->id) {
			p = hsi_find_port_num(hsi, cl_info->info.port);
			if (!p)
				continue;
			hsi_new_client(p, &cl_info->info);
		}

Annotation

Implementation Notes