18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci        paride.c  (c) 1997-8  Grant R. Guenther <grant@torque.net>
38c2ecf20Sopenharmony_ci                              Under the terms of the GNU General Public License.
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci	This is the base module for the family of device drivers
68c2ecf20Sopenharmony_ci        that support parallel port IDE devices.
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci*/
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Changes:
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci	1.01	GRG 1998.05.03	Use spinlocks
138c2ecf20Sopenharmony_ci	1.02	GRG 1998.05.05  init_proto, release_proto, ktti
148c2ecf20Sopenharmony_ci	1.03	GRG 1998.08.15  eliminate compiler warning
158c2ecf20Sopenharmony_ci	1.04    GRG 1998.11.28  added support for FRIQ
168c2ecf20Sopenharmony_ci	1.05    TMW 2000.06.06  use parport_find_number instead of
178c2ecf20Sopenharmony_ci				parport_enumerate
188c2ecf20Sopenharmony_ci	1.06    TMW 2001.03.26  more sane parport-or-not resource management
198c2ecf20Sopenharmony_ci*/
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define PI_VERSION      "1.06"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/kmod.h>
258c2ecf20Sopenharmony_ci#include <linux/types.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/ioport.h>
288c2ecf20Sopenharmony_ci#include <linux/string.h>
298c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
308c2ecf20Sopenharmony_ci#include <linux/wait.h>
318c2ecf20Sopenharmony_ci#include <linux/sched.h>	/* TASK_* */
328c2ecf20Sopenharmony_ci#include <linux/parport.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "paride.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define MAX_PROTOS	32
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic struct pi_protocol *protocols[MAX_PROTOS];
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(pi_spinlock);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid pi_write_regr(PIA * pi, int cont, int regr, int val)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	pi->proto->write_regr(pi, cont, regr, val);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_write_regr);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint pi_read_regr(PIA * pi, int cont, int regr)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return pi->proto->read_regr(pi, cont, regr);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_read_regr);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_civoid pi_write_block(PIA * pi, char *buf, int count)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	pi->proto->write_block(pi, buf, count);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_write_block);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_civoid pi_read_block(PIA * pi, char *buf, int count)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	pi->proto->read_block(pi, buf, count);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_read_block);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void pi_wake_up(void *p)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	PIA *pi = (PIA *) p;
768c2ecf20Sopenharmony_ci	unsigned long flags;
778c2ecf20Sopenharmony_ci	void (*cont) (void) = NULL;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pi_spinlock, flags);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (pi->claim_cont && !parport_claim(pi->pardev)) {
828c2ecf20Sopenharmony_ci		cont = pi->claim_cont;
838c2ecf20Sopenharmony_ci		pi->claim_cont = NULL;
848c2ecf20Sopenharmony_ci		pi->claimed = 1;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pi_spinlock, flags);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	wake_up(&(pi->parq));
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (cont)
928c2ecf20Sopenharmony_ci		cont();
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ciint pi_schedule_claimed(PIA * pi, void (*cont) (void))
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	unsigned long flags;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pi_spinlock, flags);
1008c2ecf20Sopenharmony_ci	if (pi->pardev && parport_claim(pi->pardev)) {
1018c2ecf20Sopenharmony_ci		pi->claim_cont = cont;
1028c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&pi_spinlock, flags);
1038c2ecf20Sopenharmony_ci		return 0;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci	pi->claimed = 1;
1068c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pi_spinlock, flags);
1078c2ecf20Sopenharmony_ci	return 1;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_schedule_claimed);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_civoid pi_do_claimed(PIA * pi, void (*cont) (void))
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	if (pi_schedule_claimed(pi, cont))
1148c2ecf20Sopenharmony_ci		cont();
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_do_claimed);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void pi_claim(PIA * pi)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	if (pi->claimed)
1228c2ecf20Sopenharmony_ci		return;
1238c2ecf20Sopenharmony_ci	pi->claimed = 1;
1248c2ecf20Sopenharmony_ci	if (pi->pardev)
1258c2ecf20Sopenharmony_ci		wait_event(pi->parq,
1268c2ecf20Sopenharmony_ci			   !parport_claim((struct pardevice *) pi->pardev));
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic void pi_unclaim(PIA * pi)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	pi->claimed = 0;
1328c2ecf20Sopenharmony_ci	if (pi->pardev)
1338c2ecf20Sopenharmony_ci		parport_release((struct pardevice *) (pi->pardev));
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_civoid pi_connect(PIA * pi)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	pi_claim(pi);
1398c2ecf20Sopenharmony_ci	pi->proto->connect(pi);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_connect);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_civoid pi_disconnect(PIA * pi)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	pi->proto->disconnect(pi);
1478c2ecf20Sopenharmony_ci	pi_unclaim(pi);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_disconnect);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void pi_unregister_parport(PIA * pi)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	if (pi->pardev) {
1558c2ecf20Sopenharmony_ci		parport_unregister_device((struct pardevice *) (pi->pardev));
1568c2ecf20Sopenharmony_ci		pi->pardev = NULL;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_civoid pi_release(PIA * pi)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	pi_unregister_parport(pi);
1638c2ecf20Sopenharmony_ci	if (pi->proto->release_proto)
1648c2ecf20Sopenharmony_ci		pi->proto->release_proto(pi);
1658c2ecf20Sopenharmony_ci	module_put(pi->proto->owner);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_release);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int default_test_proto(PIA * pi, char *scratch, int verbose)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	int j, k;
1738c2ecf20Sopenharmony_ci	int e[2] = { 0, 0 };
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	pi->proto->connect(pi);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	for (j = 0; j < 2; j++) {
1788c2ecf20Sopenharmony_ci		pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10);
1798c2ecf20Sopenharmony_ci		for (k = 0; k < 256; k++) {
1808c2ecf20Sopenharmony_ci			pi_write_regr(pi, 0, 2, k ^ 0xaa);
1818c2ecf20Sopenharmony_ci			pi_write_regr(pi, 0, 3, k ^ 0x55);
1828c2ecf20Sopenharmony_ci			if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa))
1838c2ecf20Sopenharmony_ci				e[j]++;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	pi->proto->disconnect(pi);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (verbose)
1898c2ecf20Sopenharmony_ci		printk("%s: %s: port 0x%x, mode  %d, test=(%d,%d)\n",
1908c2ecf20Sopenharmony_ci		       pi->device, pi->proto->name, pi->port,
1918c2ecf20Sopenharmony_ci		       pi->mode, e[0], e[1]);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return (e[0] && e[1]);	/* not here if both > 0 */
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int pi_test_proto(PIA * pi, char *scratch, int verbose)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	int res;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	pi_claim(pi);
2018c2ecf20Sopenharmony_ci	if (pi->proto->test_proto)
2028c2ecf20Sopenharmony_ci		res = pi->proto->test_proto(pi, scratch, verbose);
2038c2ecf20Sopenharmony_ci	else
2048c2ecf20Sopenharmony_ci		res = default_test_proto(pi, scratch, verbose);
2058c2ecf20Sopenharmony_ci	pi_unclaim(pi);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return res;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciint paride_register(PIP * pr)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	int k;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	for (k = 0; k < MAX_PROTOS; k++)
2158c2ecf20Sopenharmony_ci		if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) {
2168c2ecf20Sopenharmony_ci			printk("paride: %s protocol already registered\n",
2178c2ecf20Sopenharmony_ci			       pr->name);
2188c2ecf20Sopenharmony_ci			return -1;
2198c2ecf20Sopenharmony_ci		}
2208c2ecf20Sopenharmony_ci	k = 0;
2218c2ecf20Sopenharmony_ci	while ((k < MAX_PROTOS) && (protocols[k]))
2228c2ecf20Sopenharmony_ci		k++;
2238c2ecf20Sopenharmony_ci	if (k == MAX_PROTOS) {
2248c2ecf20Sopenharmony_ci		printk("paride: protocol table full\n");
2258c2ecf20Sopenharmony_ci		return -1;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci	protocols[k] = pr;
2288c2ecf20Sopenharmony_ci	pr->index = k;
2298c2ecf20Sopenharmony_ci	printk("paride: %s registered as protocol %d\n", pr->name, k);
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(paride_register);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_civoid paride_unregister(PIP * pr)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	if (!pr)
2388c2ecf20Sopenharmony_ci		return;
2398c2ecf20Sopenharmony_ci	if (protocols[pr->index] != pr) {
2408c2ecf20Sopenharmony_ci		printk("paride: %s not registered\n", pr->name);
2418c2ecf20Sopenharmony_ci		return;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	protocols[pr->index] = NULL;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(paride_unregister);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int pi_register_parport(PIA *pi, int verbose, int unit)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct parport *port;
2518c2ecf20Sopenharmony_ci	struct pardev_cb par_cb;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	port = parport_find_base(pi->port);
2548c2ecf20Sopenharmony_ci	if (!port)
2558c2ecf20Sopenharmony_ci		return 0;
2568c2ecf20Sopenharmony_ci	memset(&par_cb, 0, sizeof(par_cb));
2578c2ecf20Sopenharmony_ci	par_cb.wakeup = pi_wake_up;
2588c2ecf20Sopenharmony_ci	par_cb.private = (void *)pi;
2598c2ecf20Sopenharmony_ci	pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
2608c2ecf20Sopenharmony_ci						unit);
2618c2ecf20Sopenharmony_ci	parport_put_port(port);
2628c2ecf20Sopenharmony_ci	if (!pi->pardev)
2638c2ecf20Sopenharmony_ci		return 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	init_waitqueue_head(&pi->parq);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (verbose)
2688c2ecf20Sopenharmony_ci		printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	pi->parname = (char *) port->name;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return 1;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int best, range;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (pi->mode != -1) {
2808c2ecf20Sopenharmony_ci		if (pi->mode >= max)
2818c2ecf20Sopenharmony_ci			return 0;
2828c2ecf20Sopenharmony_ci		range = 3;
2838c2ecf20Sopenharmony_ci		if (pi->mode >= pi->proto->epp_first)
2848c2ecf20Sopenharmony_ci			range = 8;
2858c2ecf20Sopenharmony_ci		if ((range == 8) && (pi->port % 8))
2868c2ecf20Sopenharmony_ci			return 0;
2878c2ecf20Sopenharmony_ci		pi->reserved = range;
2888c2ecf20Sopenharmony_ci		return (!pi_test_proto(pi, scratch, verbose));
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci	best = -1;
2918c2ecf20Sopenharmony_ci	for (pi->mode = 0; pi->mode < max; pi->mode++) {
2928c2ecf20Sopenharmony_ci		range = 3;
2938c2ecf20Sopenharmony_ci		if (pi->mode >= pi->proto->epp_first)
2948c2ecf20Sopenharmony_ci			range = 8;
2958c2ecf20Sopenharmony_ci		if ((range == 8) && (pi->port % 8))
2968c2ecf20Sopenharmony_ci			break;
2978c2ecf20Sopenharmony_ci		pi->reserved = range;
2988c2ecf20Sopenharmony_ci		if (!pi_test_proto(pi, scratch, verbose))
2998c2ecf20Sopenharmony_ci			best = pi->mode;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	pi->mode = best;
3028c2ecf20Sopenharmony_ci	return (best > -1);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int max, s, e;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	s = unit;
3108c2ecf20Sopenharmony_ci	e = s + 1;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (s == -1) {
3138c2ecf20Sopenharmony_ci		s = 0;
3148c2ecf20Sopenharmony_ci		e = pi->proto->max_units;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (!pi_register_parport(pi, verbose, s))
3188c2ecf20Sopenharmony_ci		return 0;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (pi->proto->test_port) {
3218c2ecf20Sopenharmony_ci		pi_claim(pi);
3228c2ecf20Sopenharmony_ci		max = pi->proto->test_port(pi);
3238c2ecf20Sopenharmony_ci		pi_unclaim(pi);
3248c2ecf20Sopenharmony_ci	} else
3258c2ecf20Sopenharmony_ci		max = pi->proto->max_mode;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (pi->proto->probe_unit) {
3288c2ecf20Sopenharmony_ci		pi_claim(pi);
3298c2ecf20Sopenharmony_ci		for (pi->unit = s; pi->unit < e; pi->unit++)
3308c2ecf20Sopenharmony_ci			if (pi->proto->probe_unit(pi)) {
3318c2ecf20Sopenharmony_ci				pi_unclaim(pi);
3328c2ecf20Sopenharmony_ci				if (pi_probe_mode(pi, max, scratch, verbose))
3338c2ecf20Sopenharmony_ci					return 1;
3348c2ecf20Sopenharmony_ci				pi_unregister_parport(pi);
3358c2ecf20Sopenharmony_ci				return 0;
3368c2ecf20Sopenharmony_ci			}
3378c2ecf20Sopenharmony_ci		pi_unclaim(pi);
3388c2ecf20Sopenharmony_ci		pi_unregister_parport(pi);
3398c2ecf20Sopenharmony_ci		return 0;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (!pi_probe_mode(pi, max, scratch, verbose)) {
3438c2ecf20Sopenharmony_ci		pi_unregister_parport(pi);
3448c2ecf20Sopenharmony_ci		return 0;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci	return 1;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ciint pi_init(PIA * pi, int autoprobe, int port, int mode,
3518c2ecf20Sopenharmony_ci	int unit, int protocol, int delay, char *scratch,
3528c2ecf20Sopenharmony_ci	int devtype, int verbose, char *device)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	int p, k, s, e;
3558c2ecf20Sopenharmony_ci	int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 };
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	s = protocol;
3588c2ecf20Sopenharmony_ci	e = s + 1;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (!protocols[0])
3618c2ecf20Sopenharmony_ci		request_module("paride_protocol");
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (autoprobe) {
3648c2ecf20Sopenharmony_ci		s = 0;
3658c2ecf20Sopenharmony_ci		e = MAX_PROTOS;
3668c2ecf20Sopenharmony_ci	} else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
3678c2ecf20Sopenharmony_ci		   (!protocols[s]) || (unit < 0) ||
3688c2ecf20Sopenharmony_ci		   (unit >= protocols[s]->max_units)) {
3698c2ecf20Sopenharmony_ci		printk("%s: Invalid parameters\n", device);
3708c2ecf20Sopenharmony_ci		return 0;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	for (p = s; p < e; p++) {
3748c2ecf20Sopenharmony_ci		struct pi_protocol *proto = protocols[p];
3758c2ecf20Sopenharmony_ci		if (!proto)
3768c2ecf20Sopenharmony_ci			continue;
3778c2ecf20Sopenharmony_ci		/* still racy */
3788c2ecf20Sopenharmony_ci		if (!try_module_get(proto->owner))
3798c2ecf20Sopenharmony_ci			continue;
3808c2ecf20Sopenharmony_ci		pi->proto = proto;
3818c2ecf20Sopenharmony_ci		pi->private = 0;
3828c2ecf20Sopenharmony_ci		if (proto->init_proto && proto->init_proto(pi) < 0) {
3838c2ecf20Sopenharmony_ci			pi->proto = NULL;
3848c2ecf20Sopenharmony_ci			module_put(proto->owner);
3858c2ecf20Sopenharmony_ci			continue;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci		if (delay == -1)
3888c2ecf20Sopenharmony_ci			pi->delay = pi->proto->default_delay;
3898c2ecf20Sopenharmony_ci		else
3908c2ecf20Sopenharmony_ci			pi->delay = delay;
3918c2ecf20Sopenharmony_ci		pi->devtype = devtype;
3928c2ecf20Sopenharmony_ci		pi->device = device;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		pi->parname = NULL;
3958c2ecf20Sopenharmony_ci		pi->pardev = NULL;
3968c2ecf20Sopenharmony_ci		init_waitqueue_head(&pi->parq);
3978c2ecf20Sopenharmony_ci		pi->claimed = 0;
3988c2ecf20Sopenharmony_ci		pi->claim_cont = NULL;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		pi->mode = mode;
4018c2ecf20Sopenharmony_ci		if (port != -1) {
4028c2ecf20Sopenharmony_ci			pi->port = port;
4038c2ecf20Sopenharmony_ci			if (pi_probe_unit(pi, unit, scratch, verbose))
4048c2ecf20Sopenharmony_ci				break;
4058c2ecf20Sopenharmony_ci			pi->port = 0;
4068c2ecf20Sopenharmony_ci		} else {
4078c2ecf20Sopenharmony_ci			k = 0;
4088c2ecf20Sopenharmony_ci			while ((pi->port = lpts[k++]))
4098c2ecf20Sopenharmony_ci				if (pi_probe_unit
4108c2ecf20Sopenharmony_ci				    (pi, unit, scratch, verbose))
4118c2ecf20Sopenharmony_ci					break;
4128c2ecf20Sopenharmony_ci			if (pi->port)
4138c2ecf20Sopenharmony_ci				break;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci		if (pi->proto->release_proto)
4168c2ecf20Sopenharmony_ci			pi->proto->release_proto(pi);
4178c2ecf20Sopenharmony_ci		module_put(proto->owner);
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (!pi->port) {
4218c2ecf20Sopenharmony_ci		if (autoprobe)
4228c2ecf20Sopenharmony_ci			printk("%s: Autoprobe failed\n", device);
4238c2ecf20Sopenharmony_ci		else
4248c2ecf20Sopenharmony_ci			printk("%s: Adapter not found\n", device);
4258c2ecf20Sopenharmony_ci		return 0;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (pi->parname)
4298c2ecf20Sopenharmony_ci		printk("%s: Sharing %s at 0x%x\n", pi->device,
4308c2ecf20Sopenharmony_ci		       pi->parname, pi->port);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	pi->proto->log_adapter(pi, scratch, verbose);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 1;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_init);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic int pi_probe(struct pardevice *par_dev)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct device_driver *drv = par_dev->dev.driver;
4428c2ecf20Sopenharmony_ci	int len = strlen(drv->name);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (strncmp(par_dev->name, drv->name, len))
4458c2ecf20Sopenharmony_ci		return -ENODEV;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_civoid *pi_register_driver(char *name)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct parport_driver *parp_drv;
4538c2ecf20Sopenharmony_ci	int ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
4568c2ecf20Sopenharmony_ci	if (!parp_drv)
4578c2ecf20Sopenharmony_ci		return NULL;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	parp_drv->name = name;
4608c2ecf20Sopenharmony_ci	parp_drv->probe = pi_probe;
4618c2ecf20Sopenharmony_ci	parp_drv->devmodel = true;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	ret = parport_register_driver(parp_drv);
4648c2ecf20Sopenharmony_ci	if (ret) {
4658c2ecf20Sopenharmony_ci		kfree(parp_drv);
4668c2ecf20Sopenharmony_ci		return NULL;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci	return (void *)parp_drv;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_register_driver);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_civoid pi_unregister_driver(void *_drv)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct parport_driver *drv = _drv;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	parport_unregister_driver(drv);
4778c2ecf20Sopenharmony_ci	kfree(drv);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pi_unregister_driver);
480