xref: /openbmc/linux/drivers/parport/daisy.c (revision 1da177e4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * IEEE 1284.3 Parallel port daisy chain and multiplexor code
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
71da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
81da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
91da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * ??-12-1998: Initial implementation.
121da177e4SLinus Torvalds  * 31-01-1999: Make port-cloning transparent.
131da177e4SLinus Torvalds  * 13-02-1999: Move DeviceID technique from parport_probe.
141da177e4SLinus Torvalds  * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
151da177e4SLinus Torvalds  * 22-02-2000: Count devices that are actually detected.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Any part of this program may be used in documents licensed under
181da177e4SLinus Torvalds  * the GNU Free Documentation License, Version 1.1 or any later version
191da177e4SLinus Torvalds  * published by the Free Software Foundation.
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <linux/module.h>
231da177e4SLinus Torvalds #include <linux/parport.h>
241da177e4SLinus Torvalds #include <linux/delay.h>
251da177e4SLinus Torvalds #include <linux/sched.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include <asm/current.h>
281da177e4SLinus Torvalds #include <asm/uaccess.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #undef DEBUG
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #ifdef DEBUG
331da177e4SLinus Torvalds #define DPRINTK(stuff...) printk (stuff)
341da177e4SLinus Torvalds #else
351da177e4SLinus Torvalds #define DPRINTK(stuff...)
361da177e4SLinus Torvalds #endif
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds static struct daisydev {
391da177e4SLinus Torvalds 	struct daisydev *next;
401da177e4SLinus Torvalds 	struct parport *port;
411da177e4SLinus Torvalds 	int daisy;
421da177e4SLinus Torvalds 	int devnum;
431da177e4SLinus Torvalds } *topology = NULL;
441da177e4SLinus Torvalds static DEFINE_SPINLOCK(topology_lock);
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds static int numdevs = 0;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /* Forward-declaration of lower-level functions. */
491da177e4SLinus Torvalds static int mux_present (struct parport *port);
501da177e4SLinus Torvalds static int num_mux_ports (struct parport *port);
511da177e4SLinus Torvalds static int select_port (struct parport *port);
521da177e4SLinus Torvalds static int assign_addrs (struct parport *port);
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /* Add a device to the discovered topology. */
551da177e4SLinus Torvalds static void add_dev (int devnum, struct parport *port, int daisy)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	struct daisydev *newdev, **p;
581da177e4SLinus Torvalds 	newdev = kmalloc (sizeof (struct daisydev), GFP_KERNEL);
591da177e4SLinus Torvalds 	if (newdev) {
601da177e4SLinus Torvalds 		newdev->port = port;
611da177e4SLinus Torvalds 		newdev->daisy = daisy;
621da177e4SLinus Torvalds 		newdev->devnum = devnum;
631da177e4SLinus Torvalds 		spin_lock(&topology_lock);
641da177e4SLinus Torvalds 		for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next)
651da177e4SLinus Torvalds 			;
661da177e4SLinus Torvalds 		newdev->next = *p;
671da177e4SLinus Torvalds 		*p = newdev;
681da177e4SLinus Torvalds 		spin_unlock(&topology_lock);
691da177e4SLinus Torvalds 	}
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /* Clone a parport (actually, make an alias). */
731da177e4SLinus Torvalds static struct parport *clone_parport (struct parport *real, int muxport)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	struct parport *extra = parport_register_port (real->base,
761da177e4SLinus Torvalds 						       real->irq,
771da177e4SLinus Torvalds 						       real->dma,
781da177e4SLinus Torvalds 						       real->ops);
791da177e4SLinus Torvalds 	if (extra) {
801da177e4SLinus Torvalds 		extra->portnum = real->portnum;
811da177e4SLinus Torvalds 		extra->physport = real;
821da177e4SLinus Torvalds 		extra->muxport = muxport;
831da177e4SLinus Torvalds 		real->slaves[muxport-1] = extra;
841da177e4SLinus Torvalds 	}
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	return extra;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds /* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
901da177e4SLinus Torvalds  * Return value is number of devices actually detected. */
911da177e4SLinus Torvalds int parport_daisy_init (struct parport *port)
921da177e4SLinus Torvalds {
931da177e4SLinus Torvalds 	int detected = 0;
941da177e4SLinus Torvalds 	char *deviceid;
951da177e4SLinus Torvalds 	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
961da177e4SLinus Torvalds 	int num_ports;
971da177e4SLinus Torvalds 	int i;
981da177e4SLinus Torvalds 	int last_try = 0;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds again:
1011da177e4SLinus Torvalds 	/* Because this is called before any other devices exist,
1021da177e4SLinus Torvalds 	 * we don't have to claim exclusive access.  */
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	/* If mux present on normal port, need to create new
1051da177e4SLinus Torvalds 	 * parports for each extra port. */
1061da177e4SLinus Torvalds 	if (port->muxport < 0 && mux_present (port) &&
1071da177e4SLinus Torvalds 	    /* don't be fooled: a mux must have 2 or 4 ports. */
1081da177e4SLinus Torvalds 	    ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
1091da177e4SLinus Torvalds 		/* Leave original as port zero. */
1101da177e4SLinus Torvalds 		port->muxport = 0;
1111da177e4SLinus Torvalds 		printk (KERN_INFO
1121da177e4SLinus Torvalds 			"%s: 1st (default) port of %d-way multiplexor\n",
1131da177e4SLinus Torvalds 			port->name, num_ports);
1141da177e4SLinus Torvalds 		for (i = 1; i < num_ports; i++) {
1151da177e4SLinus Torvalds 			/* Clone the port. */
1161da177e4SLinus Torvalds 			struct parport *extra = clone_parport (port, i);
1171da177e4SLinus Torvalds 			if (!extra) {
1181da177e4SLinus Torvalds 				if (signal_pending (current))
1191da177e4SLinus Torvalds 					break;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 				schedule ();
1221da177e4SLinus Torvalds 				continue;
1231da177e4SLinus Torvalds 			}
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 			printk (KERN_INFO
1261da177e4SLinus Torvalds 				"%s: %d%s port of %d-way multiplexor on %s\n",
1271da177e4SLinus Torvalds 				extra->name, i + 1, th[i + 1], num_ports,
1281da177e4SLinus Torvalds 				port->name);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 			/* Analyse that port too.  We won't recurse
1311da177e4SLinus Torvalds 			   forever because of the 'port->muxport < 0'
1321da177e4SLinus Torvalds 			   test above. */
1331da177e4SLinus Torvalds 			parport_daisy_init(extra);
1341da177e4SLinus Torvalds 		}
1351da177e4SLinus Torvalds 	}
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	if (port->muxport >= 0)
1381da177e4SLinus Torvalds 		select_port (port);
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	parport_daisy_deselect_all (port);
1411da177e4SLinus Torvalds 	detected += assign_addrs (port);
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	/* Count the potential legacy device at the end. */
1441da177e4SLinus Torvalds 	add_dev (numdevs++, port, -1);
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 	/* Find out the legacy device's IEEE 1284 device ID. */
1471da177e4SLinus Torvalds 	deviceid = kmalloc (1000, GFP_KERNEL);
1481da177e4SLinus Torvalds 	if (deviceid) {
1491da177e4SLinus Torvalds 		if (parport_device_id (numdevs - 1, deviceid, 1000) > 2)
1501da177e4SLinus Torvalds 			detected++;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 		kfree (deviceid);
1531da177e4SLinus Torvalds 	}
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	if (!detected && !last_try) {
1561da177e4SLinus Torvalds 		/* No devices were detected.  Perhaps they are in some
1571da177e4SLinus Torvalds                    funny state; let's try to reset them and see if
1581da177e4SLinus Torvalds                    they wake up. */
1591da177e4SLinus Torvalds 		parport_daisy_fini (port);
1601da177e4SLinus Torvalds 		parport_write_control (port, PARPORT_CONTROL_SELECT);
1611da177e4SLinus Torvalds 		udelay (50);
1621da177e4SLinus Torvalds 		parport_write_control (port,
1631da177e4SLinus Torvalds 				       PARPORT_CONTROL_SELECT |
1641da177e4SLinus Torvalds 				       PARPORT_CONTROL_INIT);
1651da177e4SLinus Torvalds 		udelay (50);
1661da177e4SLinus Torvalds 		last_try = 1;
1671da177e4SLinus Torvalds 		goto again;
1681da177e4SLinus Torvalds 	}
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	return detected;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds /* Forget about devices on a physical port. */
1741da177e4SLinus Torvalds void parport_daisy_fini (struct parport *port)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	struct daisydev **p;
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	spin_lock(&topology_lock);
1791da177e4SLinus Torvalds 	p = &topology;
1801da177e4SLinus Torvalds 	while (*p) {
1811da177e4SLinus Torvalds 		struct daisydev *dev = *p;
1821da177e4SLinus Torvalds 		if (dev->port != port) {
1831da177e4SLinus Torvalds 			p = &dev->next;
1841da177e4SLinus Torvalds 			continue;
1851da177e4SLinus Torvalds 		}
1861da177e4SLinus Torvalds 		*p = dev->next;
1871da177e4SLinus Torvalds 		kfree(dev);
1881da177e4SLinus Torvalds 	}
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	/* Gaps in the numbering could be handled better.  How should
1911da177e4SLinus Torvalds            someone enumerate through all IEEE1284.3 devices in the
1921da177e4SLinus Torvalds            topology?. */
1931da177e4SLinus Torvalds 	if (!topology) numdevs = 0;
1941da177e4SLinus Torvalds 	spin_unlock(&topology_lock);
1951da177e4SLinus Torvalds 	return;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds /**
1991da177e4SLinus Torvalds  *	parport_open - find a device by canonical device number
2001da177e4SLinus Torvalds  *	@devnum: canonical device number
2011da177e4SLinus Torvalds  *	@name: name to associate with the device
2021da177e4SLinus Torvalds  *	@pf: preemption callback
2031da177e4SLinus Torvalds  *	@kf: kick callback
2041da177e4SLinus Torvalds  *	@irqf: interrupt handler
2051da177e4SLinus Torvalds  *	@flags: registration flags
2061da177e4SLinus Torvalds  *	@handle: driver data
2071da177e4SLinus Torvalds  *
2081da177e4SLinus Torvalds  *	This function is similar to parport_register_device(), except
2091da177e4SLinus Torvalds  *	that it locates a device by its number rather than by the port
2101da177e4SLinus Torvalds  *	it is attached to.
2111da177e4SLinus Torvalds  *
2121da177e4SLinus Torvalds  *	All parameters except for @devnum are the same as for
2131da177e4SLinus Torvalds  *	parport_register_device().  The return value is the same as
2141da177e4SLinus Torvalds  *	for parport_register_device().
2151da177e4SLinus Torvalds  **/
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds struct pardevice *parport_open (int devnum, const char *name,
2181da177e4SLinus Torvalds 				int (*pf) (void *), void (*kf) (void *),
2191da177e4SLinus Torvalds 				void (*irqf) (int, void *, struct pt_regs *),
2201da177e4SLinus Torvalds 				int flags, void *handle)
2211da177e4SLinus Torvalds {
2221da177e4SLinus Torvalds 	struct daisydev *p = topology;
2231da177e4SLinus Torvalds 	struct parport *port;
2241da177e4SLinus Torvalds 	struct pardevice *dev;
2251da177e4SLinus Torvalds 	int daisy;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 	spin_lock(&topology_lock);
2281da177e4SLinus Torvalds 	while (p && p->devnum != devnum)
2291da177e4SLinus Torvalds 		p = p->next;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	if (!p) {
2321da177e4SLinus Torvalds 		spin_unlock(&topology_lock);
2331da177e4SLinus Torvalds 		return NULL;
2341da177e4SLinus Torvalds 	}
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	daisy = p->daisy;
2371da177e4SLinus Torvalds 	port = parport_get_port(p->port);
2381da177e4SLinus Torvalds 	spin_unlock(&topology_lock);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	dev = parport_register_device (port, name, pf, kf,
2411da177e4SLinus Torvalds 				       irqf, flags, handle);
2421da177e4SLinus Torvalds 	parport_put_port(port);
2431da177e4SLinus Torvalds 	if (!dev)
2441da177e4SLinus Torvalds 		return NULL;
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 	dev->daisy = daisy;
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	/* Check that there really is a device to select. */
2491da177e4SLinus Torvalds 	if (daisy >= 0) {
2501da177e4SLinus Torvalds 		int selected;
2511da177e4SLinus Torvalds 		parport_claim_or_block (dev);
2521da177e4SLinus Torvalds 		selected = port->daisy;
2531da177e4SLinus Torvalds 		parport_release (dev);
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 		if (selected != port->daisy) {
2561da177e4SLinus Torvalds 			/* No corresponding device. */
2571da177e4SLinus Torvalds 			parport_unregister_device (dev);
2581da177e4SLinus Torvalds 			return NULL;
2591da177e4SLinus Torvalds 		}
2601da177e4SLinus Torvalds 	}
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	return dev;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds /**
2661da177e4SLinus Torvalds  *	parport_close - close a device opened with parport_open()
2671da177e4SLinus Torvalds  *	@dev: device to close
2681da177e4SLinus Torvalds  *
2691da177e4SLinus Torvalds  *	This is to parport_open() as parport_unregister_device() is to
2701da177e4SLinus Torvalds  *	parport_register_device().
2711da177e4SLinus Torvalds  **/
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds void parport_close (struct pardevice *dev)
2741da177e4SLinus Torvalds {
2751da177e4SLinus Torvalds 	parport_unregister_device (dev);
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds /**
2791da177e4SLinus Torvalds  *	parport_device_num - convert device coordinates
2801da177e4SLinus Torvalds  *	@parport: parallel port number
2811da177e4SLinus Torvalds  *	@mux: multiplexor port number (-1 for no multiplexor)
2821da177e4SLinus Torvalds  *	@daisy: daisy chain address (-1 for no daisy chain address)
2831da177e4SLinus Torvalds  *
2841da177e4SLinus Torvalds  *	This tries to locate a device on the given parallel port,
2851da177e4SLinus Torvalds  *	multiplexor port and daisy chain address, and returns its
2861da177e4SLinus Torvalds  *	device number or -NXIO if no device with those coordinates
2871da177e4SLinus Torvalds  *	exists.
2881da177e4SLinus Torvalds  **/
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds int parport_device_num (int parport, int mux, int daisy)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	int res = -ENXIO;
2931da177e4SLinus Torvalds 	struct daisydev *dev;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	spin_lock(&topology_lock);
2961da177e4SLinus Torvalds 	dev = topology;
2971da177e4SLinus Torvalds 	while (dev && dev->port->portnum != parport &&
2981da177e4SLinus Torvalds 	       dev->port->muxport != mux && dev->daisy != daisy)
2991da177e4SLinus Torvalds 		dev = dev->next;
3001da177e4SLinus Torvalds 	if (dev)
3011da177e4SLinus Torvalds 		res = dev->devnum;
3021da177e4SLinus Torvalds 	spin_unlock(&topology_lock);
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	return res;
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds /* Send a daisy-chain-style CPP command packet. */
3081da177e4SLinus Torvalds static int cpp_daisy (struct parport *port, int cmd)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds 	unsigned char s;
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	parport_data_forward (port);
3131da177e4SLinus Torvalds 	parport_write_data (port, 0xaa); udelay (2);
3141da177e4SLinus Torvalds 	parport_write_data (port, 0x55); udelay (2);
3151da177e4SLinus Torvalds 	parport_write_data (port, 0x00); udelay (2);
3161da177e4SLinus Torvalds 	parport_write_data (port, 0xff); udelay (2);
3171da177e4SLinus Torvalds 	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
3181da177e4SLinus Torvalds 					  | PARPORT_STATUS_PAPEROUT
3191da177e4SLinus Torvalds 					  | PARPORT_STATUS_SELECT
3201da177e4SLinus Torvalds 					  | PARPORT_STATUS_ERROR);
3211da177e4SLinus Torvalds 	if (s != (PARPORT_STATUS_BUSY
3221da177e4SLinus Torvalds 		  | PARPORT_STATUS_PAPEROUT
3231da177e4SLinus Torvalds 		  | PARPORT_STATUS_SELECT
3241da177e4SLinus Torvalds 		  | PARPORT_STATUS_ERROR)) {
3251da177e4SLinus Torvalds 		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
3261da177e4SLinus Torvalds 			 port->name, s);
3271da177e4SLinus Torvalds 		return -ENXIO;
3281da177e4SLinus Torvalds 	}
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	parport_write_data (port, 0x87); udelay (2);
3311da177e4SLinus Torvalds 	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
3321da177e4SLinus Torvalds 					  | PARPORT_STATUS_PAPEROUT
3331da177e4SLinus Torvalds 					  | PARPORT_STATUS_SELECT
3341da177e4SLinus Torvalds 					  | PARPORT_STATUS_ERROR);
3351da177e4SLinus Torvalds 	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
3361da177e4SLinus Torvalds 		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
3371da177e4SLinus Torvalds 			 port->name, s);
3381da177e4SLinus Torvalds 		return -ENXIO;
3391da177e4SLinus Torvalds 	}
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	parport_write_data (port, 0x78); udelay (2);
3421da177e4SLinus Torvalds 	parport_write_data (port, cmd); udelay (2);
3431da177e4SLinus Torvalds 	parport_frob_control (port,
3441da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE,
3451da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE);
3461da177e4SLinus Torvalds 	udelay (1);
3471da177e4SLinus Torvalds 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
3481da177e4SLinus Torvalds 	udelay (1);
3491da177e4SLinus Torvalds 	s = parport_read_status (port);
3501da177e4SLinus Torvalds 	parport_write_data (port, 0xff); udelay (2);
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	return s;
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds /* Send a mux-style CPP command packet. */
3561da177e4SLinus Torvalds static int cpp_mux (struct parport *port, int cmd)
3571da177e4SLinus Torvalds {
3581da177e4SLinus Torvalds 	unsigned char s;
3591da177e4SLinus Torvalds 	int rc;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	parport_data_forward (port);
3621da177e4SLinus Torvalds 	parport_write_data (port, 0xaa); udelay (2);
3631da177e4SLinus Torvalds 	parport_write_data (port, 0x55); udelay (2);
3641da177e4SLinus Torvalds 	parport_write_data (port, 0xf0); udelay (2);
3651da177e4SLinus Torvalds 	parport_write_data (port, 0x0f); udelay (2);
3661da177e4SLinus Torvalds 	parport_write_data (port, 0x52); udelay (2);
3671da177e4SLinus Torvalds 	parport_write_data (port, 0xad); udelay (2);
3681da177e4SLinus Torvalds 	parport_write_data (port, cmd); udelay (2);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	s = parport_read_status (port);
3711da177e4SLinus Torvalds 	if (!(s & PARPORT_STATUS_ACK)) {
3721da177e4SLinus Torvalds 		DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
3731da177e4SLinus Torvalds 			 port->name, cmd, s);
3741da177e4SLinus Torvalds 		return -EIO;
3751da177e4SLinus Torvalds 	}
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
3781da177e4SLinus Torvalds 	      ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
3791da177e4SLinus Torvalds 	      ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
3801da177e4SLinus Torvalds 	      ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	return rc;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds void parport_daisy_deselect_all (struct parport *port)
3861da177e4SLinus Torvalds {
3871da177e4SLinus Torvalds 	cpp_daisy (port, 0x30);
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds int parport_daisy_select (struct parport *port, int daisy, int mode)
3911da177e4SLinus Torvalds {
3921da177e4SLinus Torvalds 	switch (mode)
3931da177e4SLinus Torvalds 	{
3941da177e4SLinus Torvalds 		// For these modes we should switch to EPP mode:
3951da177e4SLinus Torvalds 		case IEEE1284_MODE_EPP:
3961da177e4SLinus Torvalds 		case IEEE1284_MODE_EPPSL:
3971da177e4SLinus Torvalds 		case IEEE1284_MODE_EPPSWE:
3981da177e4SLinus Torvalds 			return (cpp_daisy (port, 0x20 + daisy) &
3991da177e4SLinus Torvalds 				PARPORT_STATUS_ERROR);
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds 		// For these modes we should switch to ECP mode:
4021da177e4SLinus Torvalds 		case IEEE1284_MODE_ECP:
4031da177e4SLinus Torvalds 		case IEEE1284_MODE_ECPRLE:
4041da177e4SLinus Torvalds 		case IEEE1284_MODE_ECPSWE:
4051da177e4SLinus Torvalds 			return (cpp_daisy (port, 0xd0 + daisy) &
4061da177e4SLinus Torvalds 				PARPORT_STATUS_ERROR);
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 		// Nothing was told for BECP in Daisy chain specification.
4091da177e4SLinus Torvalds 		// May be it's wise to use ECP?
4101da177e4SLinus Torvalds 		case IEEE1284_MODE_BECP:
4111da177e4SLinus Torvalds 		// Others use compat mode
4121da177e4SLinus Torvalds 		case IEEE1284_MODE_NIBBLE:
4131da177e4SLinus Torvalds 		case IEEE1284_MODE_BYTE:
4141da177e4SLinus Torvalds 		case IEEE1284_MODE_COMPAT:
4151da177e4SLinus Torvalds 		default:
4161da177e4SLinus Torvalds 			return (cpp_daisy (port, 0xe0 + daisy) &
4171da177e4SLinus Torvalds 				PARPORT_STATUS_ERROR);
4181da177e4SLinus Torvalds 	}
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds static int mux_present (struct parport *port)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds 	return cpp_mux (port, 0x51) == 3;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds static int num_mux_ports (struct parport *port)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds 	return cpp_mux (port, 0x58);
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds static int select_port (struct parport *port)
4321da177e4SLinus Torvalds {
4331da177e4SLinus Torvalds 	int muxport = port->muxport;
4341da177e4SLinus Torvalds 	return cpp_mux (port, 0x60 + muxport) == muxport;
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds static int assign_addrs (struct parport *port)
4381da177e4SLinus Torvalds {
4391da177e4SLinus Torvalds 	unsigned char s, last_dev;
4401da177e4SLinus Torvalds 	unsigned char daisy;
4411da177e4SLinus Torvalds 	int thisdev = numdevs;
4421da177e4SLinus Torvalds 	int detected;
4431da177e4SLinus Torvalds 	char *deviceid;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	parport_data_forward (port);
4461da177e4SLinus Torvalds 	parport_write_data (port, 0xaa); udelay (2);
4471da177e4SLinus Torvalds 	parport_write_data (port, 0x55); udelay (2);
4481da177e4SLinus Torvalds 	parport_write_data (port, 0x00); udelay (2);
4491da177e4SLinus Torvalds 	parport_write_data (port, 0xff); udelay (2);
4501da177e4SLinus Torvalds 	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
4511da177e4SLinus Torvalds 					  | PARPORT_STATUS_PAPEROUT
4521da177e4SLinus Torvalds 					  | PARPORT_STATUS_SELECT
4531da177e4SLinus Torvalds 					  | PARPORT_STATUS_ERROR);
4541da177e4SLinus Torvalds 	if (s != (PARPORT_STATUS_BUSY
4551da177e4SLinus Torvalds 		  | PARPORT_STATUS_PAPEROUT
4561da177e4SLinus Torvalds 		  | PARPORT_STATUS_SELECT
4571da177e4SLinus Torvalds 		  | PARPORT_STATUS_ERROR)) {
4581da177e4SLinus Torvalds 		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
4591da177e4SLinus Torvalds 			 port->name, s);
4601da177e4SLinus Torvalds 		return 0;
4611da177e4SLinus Torvalds 	}
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	parport_write_data (port, 0x87); udelay (2);
4641da177e4SLinus Torvalds 	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
4651da177e4SLinus Torvalds 					  | PARPORT_STATUS_PAPEROUT
4661da177e4SLinus Torvalds 					  | PARPORT_STATUS_SELECT
4671da177e4SLinus Torvalds 					  | PARPORT_STATUS_ERROR);
4681da177e4SLinus Torvalds 	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
4691da177e4SLinus Torvalds 		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
4701da177e4SLinus Torvalds 			 port->name, s);
4711da177e4SLinus Torvalds 		return 0;
4721da177e4SLinus Torvalds 	}
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	parport_write_data (port, 0x78); udelay (2);
4751da177e4SLinus Torvalds 	last_dev = 0; /* We've just been speaking to a device, so we
4761da177e4SLinus Torvalds 			 know there must be at least _one_ out there. */
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 	for (daisy = 0; daisy < 4; daisy++) {
4791da177e4SLinus Torvalds 		parport_write_data (port, daisy);
4801da177e4SLinus Torvalds 		udelay (2);
4811da177e4SLinus Torvalds 		parport_frob_control (port,
4821da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE,
4831da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE);
4841da177e4SLinus Torvalds 		udelay (1);
4851da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
4861da177e4SLinus Torvalds 		udelay (1);
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds 		if (last_dev)
4891da177e4SLinus Torvalds 			/* No more devices. */
4901da177e4SLinus Torvalds 			break;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 		last_dev = !(parport_read_status (port)
4931da177e4SLinus Torvalds 			     & PARPORT_STATUS_BUSY);
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 		add_dev (numdevs++, port, daisy);
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	parport_write_data (port, 0xff); udelay (2);
4991da177e4SLinus Torvalds 	detected = numdevs - thisdev;
5001da177e4SLinus Torvalds 	DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
5011da177e4SLinus Torvalds 		 detected);
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	/* Ask the new devices to introduce themselves. */
5041da177e4SLinus Torvalds 	deviceid = kmalloc (1000, GFP_KERNEL);
5051da177e4SLinus Torvalds 	if (!deviceid) return 0;
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
5081da177e4SLinus Torvalds 		parport_device_id (thisdev, deviceid, 1000);
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	kfree (deviceid);
5111da177e4SLinus Torvalds 	return detected;
5121da177e4SLinus Torvalds }
513