// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2023 Ondrej Zary * based on paride.c by Grant R. Guenther <grant@torque.net>
*/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/parport.h> #include"pata_parport.h"
/* * libata drivers cannot sleep so this driver claims parport before activating * the ata host and keeps it claimed (and protocol connected) until the ata * host is removed. Unfortunately, this means that you cannot use any chained * devices (neither other pata_parport devices nor a printer).
*/ staticvoid pi_connect(struct pi_adapter *pi)
{
parport_claim_or_block(pi->pardev);
pi->proto->connect(pi);
}
/* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline); if (rc) { /* * some adapters return bogus values if master device is not * present, so don't abort now if a slave device is present
*/ if (!dev1) return rc;
ret = -ENODEV;
}
/* * if device 1 was found in ata_devchk, wait for register * access briefly, then wait for BSY to clear.
*/ if (dev1) { int i;
pata_parport_dev_select(ap, 1);
/* * Wait for register access. Some ATAPI devices fail * to set nsect/lbal after reset, so don't waste too * much time on it. We're gonna wait for !BSY anyway.
*/ for (i = 0; i < 2; i++) {
u8 nsect, lbal;
nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL); if (nsect == 1 && lbal == 1) break; /* give drive a breather */
ata_msleep(ap, 50);
}
rc = ata_sff_wait_ready(link, deadline); if (rc) { if (rc != -ENODEV) return rc;
ret = rc;
}
}
pata_parport_dev_select(ap, 0); if (dev1)
pata_parport_dev_select(ap, 1); if (dev0)
pata_parport_dev_select(ap, 0);
/* We only need to flush incoming data when a command was running */ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE) return;
ap = qc->ap;
pi = ap->host->private_data; /* Drain up to 64K of data before we give up this recovery method */ for (count = 0; (pata_parport_check_status(ap) & ATA_DRQ)
&& count < 65536; count += 2) {
pi->proto->read_block(pi, junk, 2);
}
if (count)
ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
}
staticint pi_test_proto(struct pi_adapter *pi)
{ int res;
parport_claim_or_block(pi->pardev); if (pi->proto->test_proto)
res = pi->proto->test_proto(pi); else
res = default_test_proto(pi);
parport_release(pi->pardev);
return res;
}
staticbool pi_probe_mode(struct pi_adapter *pi, int max)
{ int best, range;
if (pi->mode != -1) { if (pi->mode >= max) returnfalse;
range = 3; if (pi->mode >= pi->proto->epp_first)
range = 8; if (range == 8 && pi->port % 8) returnfalse; return !pi_test_proto(pi);
}
best = -1; for (pi->mode = 0; pi->mode < max; pi->mode++) {
range = 3; if (pi->mode >= pi->proto->epp_first)
range = 8; if (range == 8 && pi->port % 8) break; if (!pi_test_proto(pi))
best = pi->mode;
}
pi->mode = best; return best > -1;
}
staticbool pi_probe_unit(struct pi_adapter *pi, int unit)
{ int max, s, e;
s = unit;
e = s + 1;
if (s == -1) {
s = 0;
e = pi->proto->max_units;
}
if (pi->proto->test_port) {
parport_claim_or_block(pi->pardev);
max = pi->proto->test_port(pi);
parport_release(pi->pardev);
} else {
max = pi->proto->max_mode;
}
if (pi->proto->probe_unit) {
parport_claim_or_block(pi->pardev); for (pi->unit = s; pi->unit < e; pi->unit++) { if (pi->proto->probe_unit(pi)) {
parport_release(pi->pardev); return pi_probe_mode(pi, max);
}
}
parport_release(pi->pardev); returnfalse;
}
staticstruct pi_adapter *pi_init_one(struct parport *parport, struct pi_protocol *pr, int mode, int unit, int delay)
{ struct pardev_cb par_cb = { }; conststruct 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(sizeof(struct pi_adapter), GFP_KERNEL); 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;
ata_host_detach(host);
pi_disconnect(pi);
pi_release(pi);
device_unregister(dev); /* pata_parport_dev_release will do ida_free(dev->id) and kfree(pi) */
}
mutex_lock(&pi_mutex);
id = idr_alloc(&parport_list, port, port->number, port->number,
GFP_KERNEL); if (id < 0) {
mutex_unlock(&pi_mutex); return;
}
if (probe) { /* probe this port using all protocols */
idr_for_each_entry(&protocols, pr, pr_num)
pi_init_one(port, pr, -1, -1, -1);
}
mutex_unlock(&pi_mutex);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.