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>
255a0e3ad6STejun Heo #include <linux/slab.h>
26174cd4b1SIngo Molnar #include <linux/sched/signal.h>
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #include <asm/current.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds #undef DEBUG
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds static struct daisydev {
341da177e4SLinus Torvalds struct daisydev *next;
351da177e4SLinus Torvalds struct parport *port;
361da177e4SLinus Torvalds int daisy;
371da177e4SLinus Torvalds int devnum;
381da177e4SLinus Torvalds } *topology = NULL;
391da177e4SLinus Torvalds static DEFINE_SPINLOCK(topology_lock);
401da177e4SLinus Torvalds
41df4c756eSCarlos Palminha static int numdevs;
4260f8a59dSSudip Mukherjee static bool daisy_init_done;
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds /* Forward-declaration of lower-level functions. */
451da177e4SLinus Torvalds static int mux_present(struct parport *port);
461da177e4SLinus Torvalds static int num_mux_ports(struct parport *port);
471da177e4SLinus Torvalds static int select_port(struct parport *port);
481da177e4SLinus Torvalds static int assign_addrs(struct parport *port);
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds /* Add a device to the discovered topology. */
add_dev(int devnum,struct parport * port,int daisy)511da177e4SLinus Torvalds static void add_dev(int devnum, struct parport *port, int daisy)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds struct daisydev *newdev, **p;
541da177e4SLinus Torvalds newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL);
551da177e4SLinus Torvalds if (newdev) {
561da177e4SLinus Torvalds newdev->port = port;
571da177e4SLinus Torvalds newdev->daisy = daisy;
581da177e4SLinus Torvalds newdev->devnum = devnum;
591da177e4SLinus Torvalds spin_lock(&topology_lock);
601da177e4SLinus Torvalds for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next)
611da177e4SLinus Torvalds ;
621da177e4SLinus Torvalds newdev->next = *p;
631da177e4SLinus Torvalds *p = newdev;
641da177e4SLinus Torvalds spin_unlock(&topology_lock);
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds /* Clone a parport (actually, make an alias). */
clone_parport(struct parport * real,int muxport)691da177e4SLinus Torvalds static struct parport *clone_parport(struct parport *real, int muxport)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds struct parport *extra = parport_register_port(real->base,
721da177e4SLinus Torvalds real->irq,
731da177e4SLinus Torvalds real->dma,
741da177e4SLinus Torvalds real->ops);
751da177e4SLinus Torvalds if (extra) {
761da177e4SLinus Torvalds extra->portnum = real->portnum;
771da177e4SLinus Torvalds extra->physport = real;
781da177e4SLinus Torvalds extra->muxport = muxport;
791da177e4SLinus Torvalds real->slaves[muxport-1] = extra;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds return extra;
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds
daisy_drv_probe(struct pardevice * par_dev)8560f8a59dSSudip Mukherjee static int daisy_drv_probe(struct pardevice *par_dev)
8660f8a59dSSudip Mukherjee {
8760f8a59dSSudip Mukherjee struct device_driver *drv = par_dev->dev.driver;
8860f8a59dSSudip Mukherjee
8960f8a59dSSudip Mukherjee if (strcmp(drv->name, "daisy_drv"))
9060f8a59dSSudip Mukherjee return -ENODEV;
9160f8a59dSSudip Mukherjee if (strcmp(par_dev->name, daisy_dev_name))
9260f8a59dSSudip Mukherjee return -ENODEV;
9360f8a59dSSudip Mukherjee
9460f8a59dSSudip Mukherjee return 0;
9560f8a59dSSudip Mukherjee }
9660f8a59dSSudip Mukherjee
9760f8a59dSSudip Mukherjee static struct parport_driver daisy_driver = {
9860f8a59dSSudip Mukherjee .name = "daisy_drv",
9960f8a59dSSudip Mukherjee .probe = daisy_drv_probe,
10060f8a59dSSudip Mukherjee .devmodel = true,
10160f8a59dSSudip Mukherjee };
10260f8a59dSSudip Mukherjee
1031da177e4SLinus Torvalds /* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
1041da177e4SLinus Torvalds * Return value is number of devices actually detected. */
parport_daisy_init(struct parport * port)1051da177e4SLinus Torvalds int parport_daisy_init(struct parport *port)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds int detected = 0;
1081da177e4SLinus Torvalds char *deviceid;
1091da177e4SLinus Torvalds static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
1101da177e4SLinus Torvalds int num_ports;
1111da177e4SLinus Torvalds int i;
1121da177e4SLinus Torvalds int last_try = 0;
1131da177e4SLinus Torvalds
11460f8a59dSSudip Mukherjee if (!daisy_init_done) {
11560f8a59dSSudip Mukherjee /*
11660f8a59dSSudip Mukherjee * flag should be marked true first as
11760f8a59dSSudip Mukherjee * parport_register_driver() might try to load the low
11860f8a59dSSudip Mukherjee * level driver which will lead to announcing new ports
11960f8a59dSSudip Mukherjee * and which will again come back here at
12060f8a59dSSudip Mukherjee * parport_daisy_init()
12160f8a59dSSudip Mukherjee */
12260f8a59dSSudip Mukherjee daisy_init_done = true;
12360f8a59dSSudip Mukherjee i = parport_register_driver(&daisy_driver);
12460f8a59dSSudip Mukherjee if (i) {
12560f8a59dSSudip Mukherjee pr_err("daisy registration failed\n");
12660f8a59dSSudip Mukherjee daisy_init_done = false;
12760f8a59dSSudip Mukherjee return i;
12860f8a59dSSudip Mukherjee }
12960f8a59dSSudip Mukherjee }
13060f8a59dSSudip Mukherjee
1311da177e4SLinus Torvalds again:
1321da177e4SLinus Torvalds /* Because this is called before any other devices exist,
1331da177e4SLinus Torvalds * we don't have to claim exclusive access. */
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds /* If mux present on normal port, need to create new
1361da177e4SLinus Torvalds * parports for each extra port. */
1371da177e4SLinus Torvalds if (port->muxport < 0 && mux_present(port) &&
1381da177e4SLinus Torvalds /* don't be fooled: a mux must have 2 or 4 ports. */
1391da177e4SLinus Torvalds ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) {
1401da177e4SLinus Torvalds /* Leave original as port zero. */
1411da177e4SLinus Torvalds port->muxport = 0;
142decf26f6SJoe Perches pr_info("%s: 1st (default) port of %d-way multiplexor\n",
1431da177e4SLinus Torvalds port->name, num_ports);
1441da177e4SLinus Torvalds for (i = 1; i < num_ports; i++) {
1451da177e4SLinus Torvalds /* Clone the port. */
1461da177e4SLinus Torvalds struct parport *extra = clone_parport(port, i);
1471da177e4SLinus Torvalds if (!extra) {
1481da177e4SLinus Torvalds if (signal_pending(current))
1491da177e4SLinus Torvalds break;
1501da177e4SLinus Torvalds
1511da177e4SLinus Torvalds schedule();
1521da177e4SLinus Torvalds continue;
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds
155decf26f6SJoe Perches pr_info("%s: %d%s port of %d-way multiplexor on %s\n",
1561da177e4SLinus Torvalds extra->name, i + 1, th[i + 1], num_ports,
1571da177e4SLinus Torvalds port->name);
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds /* Analyse that port too. We won't recurse
1601da177e4SLinus Torvalds forever because of the 'port->muxport < 0'
1611da177e4SLinus Torvalds test above. */
1621da177e4SLinus Torvalds parport_daisy_init(extra);
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds if (port->muxport >= 0)
1671da177e4SLinus Torvalds select_port(port);
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds parport_daisy_deselect_all(port);
1701da177e4SLinus Torvalds detected += assign_addrs(port);
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds /* Count the potential legacy device at the end. */
1731da177e4SLinus Torvalds add_dev(numdevs++, port, -1);
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds /* Find out the legacy device's IEEE 1284 device ID. */
176b44d3bddSMarko Kohtala deviceid = kmalloc(1024, GFP_KERNEL);
1771da177e4SLinus Torvalds if (deviceid) {
178b44d3bddSMarko Kohtala if (parport_device_id(numdevs - 1, deviceid, 1024) > 2)
1791da177e4SLinus Torvalds detected++;
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds kfree(deviceid);
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds if (!detected && !last_try) {
1851da177e4SLinus Torvalds /* No devices were detected. Perhaps they are in some
1861da177e4SLinus Torvalds funny state; let's try to reset them and see if
1871da177e4SLinus Torvalds they wake up. */
1881da177e4SLinus Torvalds parport_daisy_fini(port);
1891da177e4SLinus Torvalds parport_write_control(port, PARPORT_CONTROL_SELECT);
1901da177e4SLinus Torvalds udelay(50);
1911da177e4SLinus Torvalds parport_write_control(port,
1921da177e4SLinus Torvalds PARPORT_CONTROL_SELECT |
1931da177e4SLinus Torvalds PARPORT_CONTROL_INIT);
1941da177e4SLinus Torvalds udelay(50);
1951da177e4SLinus Torvalds last_try = 1;
1961da177e4SLinus Torvalds goto again;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds return detected;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds /* Forget about devices on a physical port. */
parport_daisy_fini(struct parport * port)2031da177e4SLinus Torvalds void parport_daisy_fini(struct parport *port)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds struct daisydev **p;
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds spin_lock(&topology_lock);
2081da177e4SLinus Torvalds p = &topology;
2091da177e4SLinus Torvalds while (*p) {
2101da177e4SLinus Torvalds struct daisydev *dev = *p;
2111da177e4SLinus Torvalds if (dev->port != port) {
2121da177e4SLinus Torvalds p = &dev->next;
2131da177e4SLinus Torvalds continue;
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds *p = dev->next;
2161da177e4SLinus Torvalds kfree(dev);
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds
2191da177e4SLinus Torvalds /* Gaps in the numbering could be handled better. How should
2201da177e4SLinus Torvalds someone enumerate through all IEEE1284.3 devices in the
2211da177e4SLinus Torvalds topology?. */
2221da177e4SLinus Torvalds if (!topology) numdevs = 0;
2231da177e4SLinus Torvalds spin_unlock(&topology_lock);
2241da177e4SLinus Torvalds return;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds
2271da177e4SLinus Torvalds /**
2281da177e4SLinus Torvalds * parport_open - find a device by canonical device number
2291da177e4SLinus Torvalds * @devnum: canonical device number
2301da177e4SLinus Torvalds * @name: name to associate with the device
2311da177e4SLinus Torvalds *
2321da177e4SLinus Torvalds * This function is similar to parport_register_device(), except
2331da177e4SLinus Torvalds * that it locates a device by its number rather than by the port
2341da177e4SLinus Torvalds * it is attached to.
2351da177e4SLinus Torvalds *
2361da177e4SLinus Torvalds * All parameters except for @devnum are the same as for
2371da177e4SLinus Torvalds * parport_register_device(). The return value is the same as
2381da177e4SLinus Torvalds * for parport_register_device().
2391da177e4SLinus Torvalds **/
2401da177e4SLinus Torvalds
parport_open(int devnum,const char * name)2415712cb3dSJeff Garzik struct pardevice *parport_open(int devnum, const char *name)
2421da177e4SLinus Torvalds {
2431da177e4SLinus Torvalds struct daisydev *p = topology;
24460f8a59dSSudip Mukherjee struct pardev_cb par_cb;
2451da177e4SLinus Torvalds struct parport *port;
2461da177e4SLinus Torvalds struct pardevice *dev;
2471da177e4SLinus Torvalds int daisy;
2481da177e4SLinus Torvalds
24960f8a59dSSudip Mukherjee memset(&par_cb, 0, sizeof(par_cb));
2501da177e4SLinus Torvalds spin_lock(&topology_lock);
2511da177e4SLinus Torvalds while (p && p->devnum != devnum)
2521da177e4SLinus Torvalds p = p->next;
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds if (!p) {
2551da177e4SLinus Torvalds spin_unlock(&topology_lock);
2561da177e4SLinus Torvalds return NULL;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds daisy = p->daisy;
2601da177e4SLinus Torvalds port = parport_get_port(p->port);
2611da177e4SLinus Torvalds spin_unlock(&topology_lock);
2621da177e4SLinus Torvalds
26360f8a59dSSudip Mukherjee dev = parport_register_dev_model(port, name, &par_cb, devnum);
2641da177e4SLinus Torvalds parport_put_port(port);
2651da177e4SLinus Torvalds if (!dev)
2661da177e4SLinus Torvalds return NULL;
2671da177e4SLinus Torvalds
2681da177e4SLinus Torvalds dev->daisy = daisy;
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds /* Check that there really is a device to select. */
2711da177e4SLinus Torvalds if (daisy >= 0) {
2721da177e4SLinus Torvalds int selected;
2731da177e4SLinus Torvalds parport_claim_or_block(dev);
2741da177e4SLinus Torvalds selected = port->daisy;
2751da177e4SLinus Torvalds parport_release(dev);
2761da177e4SLinus Torvalds
277c29a75edSMarko Kohtala if (selected != daisy) {
2781da177e4SLinus Torvalds /* No corresponding device. */
2791da177e4SLinus Torvalds parport_unregister_device(dev);
2801da177e4SLinus Torvalds return NULL;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds return dev;
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds /**
2881da177e4SLinus Torvalds * parport_close - close a device opened with parport_open()
2891da177e4SLinus Torvalds * @dev: device to close
2901da177e4SLinus Torvalds *
2911da177e4SLinus Torvalds * This is to parport_open() as parport_unregister_device() is to
2921da177e4SLinus Torvalds * parport_register_device().
2931da177e4SLinus Torvalds **/
2941da177e4SLinus Torvalds
parport_close(struct pardevice * dev)2951da177e4SLinus Torvalds void parport_close(struct pardevice *dev)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds parport_unregister_device(dev);
2981da177e4SLinus Torvalds }
2991da177e4SLinus Torvalds
3001da177e4SLinus Torvalds /* Send a daisy-chain-style CPP command packet. */
cpp_daisy(struct parport * port,int cmd)3011da177e4SLinus Torvalds static int cpp_daisy(struct parport *port, int cmd)
3021da177e4SLinus Torvalds {
3031da177e4SLinus Torvalds unsigned char s;
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds parport_data_forward(port);
3061da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2);
3071da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2);
3081da177e4SLinus Torvalds parport_write_data(port, 0x00); udelay(2);
3091da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2);
3101da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY
3111da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
3121da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
3131da177e4SLinus Torvalds | PARPORT_STATUS_ERROR);
3141da177e4SLinus Torvalds if (s != (PARPORT_STATUS_BUSY
3151da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
3161da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
3171da177e4SLinus Torvalds | PARPORT_STATUS_ERROR)) {
318*88c5cbdeSJoe Perches pr_debug("%s: cpp_daisy: aa5500ff(%02x)\n", port->name, s);
3191da177e4SLinus Torvalds return -ENXIO;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds parport_write_data(port, 0x87); udelay(2);
3231da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY
3241da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
3251da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
3261da177e4SLinus Torvalds | PARPORT_STATUS_ERROR);
3271da177e4SLinus Torvalds if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
328*88c5cbdeSJoe Perches pr_debug("%s: cpp_daisy: aa5500ff87(%02x)\n", port->name, s);
3291da177e4SLinus Torvalds return -ENXIO;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds
3321da177e4SLinus Torvalds parport_write_data(port, 0x78); udelay(2);
3331da177e4SLinus Torvalds parport_write_data(port, cmd); udelay(2);
3341da177e4SLinus Torvalds parport_frob_control(port,
3351da177e4SLinus Torvalds PARPORT_CONTROL_STROBE,
3361da177e4SLinus Torvalds PARPORT_CONTROL_STROBE);
3371da177e4SLinus Torvalds udelay(1);
3387c9cc3beSMarko Kohtala s = parport_read_status(port);
3391da177e4SLinus Torvalds parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
3401da177e4SLinus Torvalds udelay(1);
3411da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2);
3421da177e4SLinus Torvalds
3431da177e4SLinus Torvalds return s;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds
3461da177e4SLinus Torvalds /* Send a mux-style CPP command packet. */
cpp_mux(struct parport * port,int cmd)3471da177e4SLinus Torvalds static int cpp_mux(struct parport *port, int cmd)
3481da177e4SLinus Torvalds {
3491da177e4SLinus Torvalds unsigned char s;
3501da177e4SLinus Torvalds int rc;
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds parport_data_forward(port);
3531da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2);
3541da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2);
3551da177e4SLinus Torvalds parport_write_data(port, 0xf0); udelay(2);
3561da177e4SLinus Torvalds parport_write_data(port, 0x0f); udelay(2);
3571da177e4SLinus Torvalds parport_write_data(port, 0x52); udelay(2);
3581da177e4SLinus Torvalds parport_write_data(port, 0xad); udelay(2);
3591da177e4SLinus Torvalds parport_write_data(port, cmd); udelay(2);
3601da177e4SLinus Torvalds
3611da177e4SLinus Torvalds s = parport_read_status(port);
3621da177e4SLinus Torvalds if (!(s & PARPORT_STATUS_ACK)) {
363*88c5cbdeSJoe Perches pr_debug("%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
3641da177e4SLinus Torvalds port->name, cmd, s);
3651da177e4SLinus Torvalds return -EIO;
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) |
3691da177e4SLinus Torvalds ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
3701da177e4SLinus Torvalds ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) |
3711da177e4SLinus Torvalds ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3));
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds return rc;
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds
parport_daisy_deselect_all(struct parport * port)3761da177e4SLinus Torvalds void parport_daisy_deselect_all(struct parport *port)
3771da177e4SLinus Torvalds {
3781da177e4SLinus Torvalds cpp_daisy(port, 0x30);
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds
parport_daisy_select(struct parport * port,int daisy,int mode)3811da177e4SLinus Torvalds int parport_daisy_select(struct parport *port, int daisy, int mode)
3821da177e4SLinus Torvalds {
3831da177e4SLinus Torvalds switch (mode)
3841da177e4SLinus Torvalds {
3851da177e4SLinus Torvalds // For these modes we should switch to EPP mode:
3861da177e4SLinus Torvalds case IEEE1284_MODE_EPP:
3871da177e4SLinus Torvalds case IEEE1284_MODE_EPPSL:
3881da177e4SLinus Torvalds case IEEE1284_MODE_EPPSWE:
3897c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0x20 + daisy) &
3901da177e4SLinus Torvalds PARPORT_STATUS_ERROR);
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds // For these modes we should switch to ECP mode:
3931da177e4SLinus Torvalds case IEEE1284_MODE_ECP:
3941da177e4SLinus Torvalds case IEEE1284_MODE_ECPRLE:
3951da177e4SLinus Torvalds case IEEE1284_MODE_ECPSWE:
3967c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0xd0 + daisy) &
3971da177e4SLinus Torvalds PARPORT_STATUS_ERROR);
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds // Nothing was told for BECP in Daisy chain specification.
4001da177e4SLinus Torvalds // May be it's wise to use ECP?
4011da177e4SLinus Torvalds case IEEE1284_MODE_BECP:
4021da177e4SLinus Torvalds // Others use compat mode
4031da177e4SLinus Torvalds case IEEE1284_MODE_NIBBLE:
4041da177e4SLinus Torvalds case IEEE1284_MODE_BYTE:
4051da177e4SLinus Torvalds case IEEE1284_MODE_COMPAT:
4061da177e4SLinus Torvalds default:
4077c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0xe0 + daisy) &
4081da177e4SLinus Torvalds PARPORT_STATUS_ERROR);
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds
mux_present(struct parport * port)4121da177e4SLinus Torvalds static int mux_present(struct parport *port)
4131da177e4SLinus Torvalds {
4141da177e4SLinus Torvalds return cpp_mux(port, 0x51) == 3;
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds
num_mux_ports(struct parport * port)4171da177e4SLinus Torvalds static int num_mux_ports(struct parport *port)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds return cpp_mux(port, 0x58);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
select_port(struct parport * port)4221da177e4SLinus Torvalds static int select_port(struct parport *port)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds int muxport = port->muxport;
4251da177e4SLinus Torvalds return cpp_mux(port, 0x60 + muxport) == muxport;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds
assign_addrs(struct parport * port)4281da177e4SLinus Torvalds static int assign_addrs(struct parport *port)
4291da177e4SLinus Torvalds {
430310c8c32SMarko Kohtala unsigned char s;
4311da177e4SLinus Torvalds unsigned char daisy;
4321da177e4SLinus Torvalds int thisdev = numdevs;
4331da177e4SLinus Torvalds int detected;
4341da177e4SLinus Torvalds char *deviceid;
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds parport_data_forward(port);
4371da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2);
4381da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2);
4391da177e4SLinus Torvalds parport_write_data(port, 0x00); udelay(2);
4401da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2);
4411da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY
4421da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
4431da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
4441da177e4SLinus Torvalds | PARPORT_STATUS_ERROR);
4451da177e4SLinus Torvalds if (s != (PARPORT_STATUS_BUSY
4461da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
4471da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
4481da177e4SLinus Torvalds | PARPORT_STATUS_ERROR)) {
449*88c5cbdeSJoe Perches pr_debug("%s: assign_addrs: aa5500ff(%02x)\n", port->name, s);
4501da177e4SLinus Torvalds return 0;
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds
4531da177e4SLinus Torvalds parport_write_data(port, 0x87); udelay(2);
4541da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY
4551da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT
4561da177e4SLinus Torvalds | PARPORT_STATUS_SELECT
4571da177e4SLinus Torvalds | PARPORT_STATUS_ERROR);
4581da177e4SLinus Torvalds if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
459*88c5cbdeSJoe Perches pr_debug("%s: assign_addrs: aa5500ff87(%02x)\n", port->name, s);
4601da177e4SLinus Torvalds return 0;
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds
4631da177e4SLinus Torvalds parport_write_data(port, 0x78); udelay(2);
464310c8c32SMarko Kohtala s = parport_read_status(port);
4651da177e4SLinus Torvalds
466310c8c32SMarko Kohtala for (daisy = 0;
467310c8c32SMarko Kohtala (s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT))
468310c8c32SMarko Kohtala == (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)
469310c8c32SMarko Kohtala && daisy < 4;
470310c8c32SMarko Kohtala ++daisy) {
4711da177e4SLinus Torvalds parport_write_data(port, daisy);
4721da177e4SLinus Torvalds udelay(2);
4731da177e4SLinus Torvalds parport_frob_control(port,
4741da177e4SLinus Torvalds PARPORT_CONTROL_STROBE,
4751da177e4SLinus Torvalds PARPORT_CONTROL_STROBE);
4761da177e4SLinus Torvalds udelay(1);
4771da177e4SLinus Torvalds parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
4781da177e4SLinus Torvalds udelay(1);
4791da177e4SLinus Torvalds
480310c8c32SMarko Kohtala add_dev(numdevs++, port, daisy);
481310c8c32SMarko Kohtala
482310c8c32SMarko Kohtala /* See if this device thought it was the last in the
483310c8c32SMarko Kohtala * chain. */
484310c8c32SMarko Kohtala if (!(s & PARPORT_STATUS_BUSY))
4851da177e4SLinus Torvalds break;
4861da177e4SLinus Torvalds
487310c8c32SMarko Kohtala /* We are seeing pass through status now. We see
488310c8c32SMarko Kohtala last_dev from next device or if last_dev does not
489310c8c32SMarko Kohtala work status lines from some non-daisy chain
490310c8c32SMarko Kohtala device. */
491310c8c32SMarko Kohtala s = parport_read_status(port);
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds
4941da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2);
4951da177e4SLinus Torvalds detected = numdevs - thisdev;
496*88c5cbdeSJoe Perches pr_debug("%s: Found %d daisy-chained devices\n", port->name, detected);
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds /* Ask the new devices to introduce themselves. */
499b44d3bddSMarko Kohtala deviceid = kmalloc(1024, GFP_KERNEL);
5001da177e4SLinus Torvalds if (!deviceid) return 0;
5011da177e4SLinus Torvalds
5021da177e4SLinus Torvalds for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
503b44d3bddSMarko Kohtala parport_device_id(thisdev, deviceid, 1024);
5041da177e4SLinus Torvalds
5051da177e4SLinus Torvalds kfree(deviceid);
5061da177e4SLinus Torvalds return detected;
5071da177e4SLinus Torvalds }
508