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