drivers/ata/pata_parport/pata_parport.c

Source file repositories/reference/linux-study-clean/drivers/ata/pata_parport/pata_parport.c

File Facts

System
Linux kernel
Corpus path
drivers/ata/pata_parport/pata_parport.c
Extension
.c
Size
20990 bytes
Lines
829
Domain
Driver Families
Bucket
drivers/ata
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 const struct bus_type pata_parport_bus_type = {
	.name = DRV_NAME,
};

static struct device *pata_parport_bus;

static const struct scsi_host_template pata_parport_sht = {
	PATA_PARPORT_SHT("pata_parport")
};

struct pi_device_match {
	struct parport *parport;
	struct pi_protocol *proto;
};

static int pi_find_dev(struct device *dev, void *data)
{
	struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
	struct pi_device_match *match = data;

	return pi->pardev->port == match->parport && pi->proto == match->proto;
}

static struct pi_adapter *pi_init_one(struct parport *parport,
			struct pi_protocol *pr, int mode, int unit, int delay)
{
	struct pardev_cb par_cb = { };
	const struct ata_port_info *ppi[] = { &pata_parport_port_info };
	struct ata_host *host;
	struct pi_adapter *pi;
	struct pi_device_match match = { .parport = parport, .proto = pr };
	int id;

	/*
	 * Abort if there's a device already registered on the same parport
	 * using the same protocol.
	 */
	if (bus_for_each_dev(&pata_parport_bus_type, NULL, &match, pi_find_dev))
		return NULL;

	id = ida_alloc(&pata_parport_bus_dev_ids, GFP_KERNEL);
	if (id < 0)
		return NULL;

	pi = kzalloc_obj(struct pi_adapter);
	if (!pi) {
		ida_free(&pata_parport_bus_dev_ids, id);
		return NULL;
	}

	/* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
	pi->dev.parent = pata_parport_bus;
	pi->dev.bus = &pata_parport_bus_type;
	pi->dev.driver = &pr->driver;
	pi->dev.release = pata_parport_dev_release;
	pi->dev.id = id;
	dev_set_name(&pi->dev, "pata_parport.%u", pi->dev.id);
	if (device_register(&pi->dev)) {
		put_device(&pi->dev);
		/* pata_parport_dev_release will do ida_free(dev->id) and kfree(pi) */
		return NULL;
	}

	pi->proto = pr;

	if (!try_module_get(pi->proto->owner))
		goto out_unreg_dev;
	if (pi->proto->init_proto && pi->proto->init_proto(pi) < 0)
		goto out_module_put;

	pi->delay = (delay == -1) ? pi->proto->default_delay : delay;
	pi->mode = mode;
	pi->port = parport->base;

	par_cb.private = pi;
	pi->pardev = parport_register_dev_model(parport, DRV_NAME, &par_cb, id);
	if (!pi->pardev)
		goto out_module_put;

	if (!pi_probe_unit(pi, unit)) {
		dev_info(&pi->dev, "Adapter not found\n");
		goto out_unreg_parport;
	}

	pi->proto->log_adapter(pi);

	host = ata_host_alloc_pinfo(&pi->pardev->dev, ppi, 1);
	if (!host)
		goto out_unreg_parport;
	dev_set_drvdata(&pi->dev, host);

Annotation

Implementation Notes