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 #ifdef DEBUG 341da177e4SLinus Torvalds #define DPRINTK(stuff...) printk(stuff) 351da177e4SLinus Torvalds #else 361da177e4SLinus Torvalds #define DPRINTK(stuff...) 371da177e4SLinus Torvalds #endif 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static struct daisydev { 401da177e4SLinus Torvalds struct daisydev *next; 411da177e4SLinus Torvalds struct parport *port; 421da177e4SLinus Torvalds int daisy; 431da177e4SLinus Torvalds int devnum; 441da177e4SLinus Torvalds } *topology = NULL; 451da177e4SLinus Torvalds static DEFINE_SPINLOCK(topology_lock); 461da177e4SLinus Torvalds 47df4c756eSCarlos Palminha static int numdevs; 4860f8a59dSSudip Mukherjee static bool daisy_init_done; 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* Forward-declaration of lower-level functions. */ 511da177e4SLinus Torvalds static int mux_present(struct parport *port); 521da177e4SLinus Torvalds static int num_mux_ports(struct parport *port); 531da177e4SLinus Torvalds static int select_port(struct parport *port); 541da177e4SLinus Torvalds static int assign_addrs(struct parport *port); 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* Add a device to the discovered topology. */ 571da177e4SLinus Torvalds static void add_dev(int devnum, struct parport *port, int daisy) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds struct daisydev *newdev, **p; 601da177e4SLinus Torvalds newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL); 611da177e4SLinus Torvalds if (newdev) { 621da177e4SLinus Torvalds newdev->port = port; 631da177e4SLinus Torvalds newdev->daisy = daisy; 641da177e4SLinus Torvalds newdev->devnum = devnum; 651da177e4SLinus Torvalds spin_lock(&topology_lock); 661da177e4SLinus Torvalds for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next) 671da177e4SLinus Torvalds ; 681da177e4SLinus Torvalds newdev->next = *p; 691da177e4SLinus Torvalds *p = newdev; 701da177e4SLinus Torvalds spin_unlock(&topology_lock); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* Clone a parport (actually, make an alias). */ 751da177e4SLinus Torvalds static struct parport *clone_parport(struct parport *real, int muxport) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds struct parport *extra = parport_register_port(real->base, 781da177e4SLinus Torvalds real->irq, 791da177e4SLinus Torvalds real->dma, 801da177e4SLinus Torvalds real->ops); 811da177e4SLinus Torvalds if (extra) { 821da177e4SLinus Torvalds extra->portnum = real->portnum; 831da177e4SLinus Torvalds extra->physport = real; 841da177e4SLinus Torvalds extra->muxport = muxport; 851da177e4SLinus Torvalds real->slaves[muxport-1] = extra; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds return extra; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 9160f8a59dSSudip Mukherjee static int daisy_drv_probe(struct pardevice *par_dev) 9260f8a59dSSudip Mukherjee { 9360f8a59dSSudip Mukherjee struct device_driver *drv = par_dev->dev.driver; 9460f8a59dSSudip Mukherjee 9560f8a59dSSudip Mukherjee if (strcmp(drv->name, "daisy_drv")) 9660f8a59dSSudip Mukherjee return -ENODEV; 9760f8a59dSSudip Mukherjee if (strcmp(par_dev->name, daisy_dev_name)) 9860f8a59dSSudip Mukherjee return -ENODEV; 9960f8a59dSSudip Mukherjee 10060f8a59dSSudip Mukherjee return 0; 10160f8a59dSSudip Mukherjee } 10260f8a59dSSudip Mukherjee 10360f8a59dSSudip Mukherjee static struct parport_driver daisy_driver = { 10460f8a59dSSudip Mukherjee .name = "daisy_drv", 10560f8a59dSSudip Mukherjee .probe = daisy_drv_probe, 10660f8a59dSSudip Mukherjee .devmodel = true, 10760f8a59dSSudip Mukherjee }; 10860f8a59dSSudip Mukherjee 1091da177e4SLinus Torvalds /* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. 1101da177e4SLinus Torvalds * Return value is number of devices actually detected. */ 1111da177e4SLinus Torvalds int parport_daisy_init(struct parport *port) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds int detected = 0; 1141da177e4SLinus Torvalds char *deviceid; 1151da177e4SLinus Torvalds static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; 1161da177e4SLinus Torvalds int num_ports; 1171da177e4SLinus Torvalds int i; 1181da177e4SLinus Torvalds int last_try = 0; 1191da177e4SLinus Torvalds 12060f8a59dSSudip Mukherjee if (!daisy_init_done) { 12160f8a59dSSudip Mukherjee /* 12260f8a59dSSudip Mukherjee * flag should be marked true first as 12360f8a59dSSudip Mukherjee * parport_register_driver() might try to load the low 12460f8a59dSSudip Mukherjee * level driver which will lead to announcing new ports 12560f8a59dSSudip Mukherjee * and which will again come back here at 12660f8a59dSSudip Mukherjee * parport_daisy_init() 12760f8a59dSSudip Mukherjee */ 12860f8a59dSSudip Mukherjee daisy_init_done = true; 12960f8a59dSSudip Mukherjee i = parport_register_driver(&daisy_driver); 13060f8a59dSSudip Mukherjee if (i) { 13160f8a59dSSudip Mukherjee pr_err("daisy registration failed\n"); 13260f8a59dSSudip Mukherjee daisy_init_done = false; 13360f8a59dSSudip Mukherjee return i; 13460f8a59dSSudip Mukherjee } 13560f8a59dSSudip Mukherjee } 13660f8a59dSSudip Mukherjee 1371da177e4SLinus Torvalds again: 1381da177e4SLinus Torvalds /* Because this is called before any other devices exist, 1391da177e4SLinus Torvalds * we don't have to claim exclusive access. */ 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* If mux present on normal port, need to create new 1421da177e4SLinus Torvalds * parports for each extra port. */ 1431da177e4SLinus Torvalds if (port->muxport < 0 && mux_present(port) && 1441da177e4SLinus Torvalds /* don't be fooled: a mux must have 2 or 4 ports. */ 1451da177e4SLinus Torvalds ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) { 1461da177e4SLinus Torvalds /* Leave original as port zero. */ 1471da177e4SLinus Torvalds port->muxport = 0; 148decf26f6SJoe Perches pr_info("%s: 1st (default) port of %d-way multiplexor\n", 1491da177e4SLinus Torvalds port->name, num_ports); 1501da177e4SLinus Torvalds for (i = 1; i < num_ports; i++) { 1511da177e4SLinus Torvalds /* Clone the port. */ 1521da177e4SLinus Torvalds struct parport *extra = clone_parport(port, i); 1531da177e4SLinus Torvalds if (!extra) { 1541da177e4SLinus Torvalds if (signal_pending(current)) 1551da177e4SLinus Torvalds break; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds schedule(); 1581da177e4SLinus Torvalds continue; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 161decf26f6SJoe Perches pr_info("%s: %d%s port of %d-way multiplexor on %s\n", 1621da177e4SLinus Torvalds extra->name, i + 1, th[i + 1], num_ports, 1631da177e4SLinus Torvalds port->name); 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /* Analyse that port too. We won't recurse 1661da177e4SLinus Torvalds forever because of the 'port->muxport < 0' 1671da177e4SLinus Torvalds test above. */ 1681da177e4SLinus Torvalds parport_daisy_init(extra); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds if (port->muxport >= 0) 1731da177e4SLinus Torvalds select_port(port); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds parport_daisy_deselect_all(port); 1761da177e4SLinus Torvalds detected += assign_addrs(port); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds /* Count the potential legacy device at the end. */ 1791da177e4SLinus Torvalds add_dev(numdevs++, port, -1); 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* Find out the legacy device's IEEE 1284 device ID. */ 182b44d3bddSMarko Kohtala deviceid = kmalloc(1024, GFP_KERNEL); 1831da177e4SLinus Torvalds if (deviceid) { 184b44d3bddSMarko Kohtala if (parport_device_id(numdevs - 1, deviceid, 1024) > 2) 1851da177e4SLinus Torvalds detected++; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds kfree(deviceid); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds if (!detected && !last_try) { 1911da177e4SLinus Torvalds /* No devices were detected. Perhaps they are in some 1921da177e4SLinus Torvalds funny state; let's try to reset them and see if 1931da177e4SLinus Torvalds they wake up. */ 1941da177e4SLinus Torvalds parport_daisy_fini(port); 1951da177e4SLinus Torvalds parport_write_control(port, PARPORT_CONTROL_SELECT); 1961da177e4SLinus Torvalds udelay(50); 1971da177e4SLinus Torvalds parport_write_control(port, 1981da177e4SLinus Torvalds PARPORT_CONTROL_SELECT | 1991da177e4SLinus Torvalds PARPORT_CONTROL_INIT); 2001da177e4SLinus Torvalds udelay(50); 2011da177e4SLinus Torvalds last_try = 1; 2021da177e4SLinus Torvalds goto again; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds return detected; 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Forget about devices on a physical port. */ 2091da177e4SLinus Torvalds void parport_daisy_fini(struct parport *port) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds struct daisydev **p; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds spin_lock(&topology_lock); 2141da177e4SLinus Torvalds p = &topology; 2151da177e4SLinus Torvalds while (*p) { 2161da177e4SLinus Torvalds struct daisydev *dev = *p; 2171da177e4SLinus Torvalds if (dev->port != port) { 2181da177e4SLinus Torvalds p = &dev->next; 2191da177e4SLinus Torvalds continue; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds *p = dev->next; 2221da177e4SLinus Torvalds kfree(dev); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /* Gaps in the numbering could be handled better. How should 2261da177e4SLinus Torvalds someone enumerate through all IEEE1284.3 devices in the 2271da177e4SLinus Torvalds topology?. */ 2281da177e4SLinus Torvalds if (!topology) numdevs = 0; 2291da177e4SLinus Torvalds spin_unlock(&topology_lock); 2301da177e4SLinus Torvalds return; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /** 2341da177e4SLinus Torvalds * parport_open - find a device by canonical device number 2351da177e4SLinus Torvalds * @devnum: canonical device number 2361da177e4SLinus Torvalds * @name: name to associate with the device 2371da177e4SLinus Torvalds * 2381da177e4SLinus Torvalds * This function is similar to parport_register_device(), except 2391da177e4SLinus Torvalds * that it locates a device by its number rather than by the port 2401da177e4SLinus Torvalds * it is attached to. 2411da177e4SLinus Torvalds * 2421da177e4SLinus Torvalds * All parameters except for @devnum are the same as for 2431da177e4SLinus Torvalds * parport_register_device(). The return value is the same as 2441da177e4SLinus Torvalds * for parport_register_device(). 2451da177e4SLinus Torvalds **/ 2461da177e4SLinus Torvalds 2475712cb3dSJeff Garzik struct pardevice *parport_open(int devnum, const char *name) 2481da177e4SLinus Torvalds { 2491da177e4SLinus Torvalds struct daisydev *p = topology; 25060f8a59dSSudip Mukherjee struct pardev_cb par_cb; 2511da177e4SLinus Torvalds struct parport *port; 2521da177e4SLinus Torvalds struct pardevice *dev; 2531da177e4SLinus Torvalds int daisy; 2541da177e4SLinus Torvalds 25560f8a59dSSudip Mukherjee memset(&par_cb, 0, sizeof(par_cb)); 2561da177e4SLinus Torvalds spin_lock(&topology_lock); 2571da177e4SLinus Torvalds while (p && p->devnum != devnum) 2581da177e4SLinus Torvalds p = p->next; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (!p) { 2611da177e4SLinus Torvalds spin_unlock(&topology_lock); 2621da177e4SLinus Torvalds return NULL; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds daisy = p->daisy; 2661da177e4SLinus Torvalds port = parport_get_port(p->port); 2671da177e4SLinus Torvalds spin_unlock(&topology_lock); 2681da177e4SLinus Torvalds 26960f8a59dSSudip Mukherjee dev = parport_register_dev_model(port, name, &par_cb, devnum); 2701da177e4SLinus Torvalds parport_put_port(port); 2711da177e4SLinus Torvalds if (!dev) 2721da177e4SLinus Torvalds return NULL; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds dev->daisy = daisy; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* Check that there really is a device to select. */ 2771da177e4SLinus Torvalds if (daisy >= 0) { 2781da177e4SLinus Torvalds int selected; 2791da177e4SLinus Torvalds parport_claim_or_block(dev); 2801da177e4SLinus Torvalds selected = port->daisy; 2811da177e4SLinus Torvalds parport_release(dev); 2821da177e4SLinus Torvalds 283c29a75edSMarko Kohtala if (selected != daisy) { 2841da177e4SLinus Torvalds /* No corresponding device. */ 2851da177e4SLinus Torvalds parport_unregister_device(dev); 2861da177e4SLinus Torvalds return NULL; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds return dev; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds /** 2941da177e4SLinus Torvalds * parport_close - close a device opened with parport_open() 2951da177e4SLinus Torvalds * @dev: device to close 2961da177e4SLinus Torvalds * 2971da177e4SLinus Torvalds * This is to parport_open() as parport_unregister_device() is to 2981da177e4SLinus Torvalds * parport_register_device(). 2991da177e4SLinus Torvalds **/ 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds void parport_close(struct pardevice *dev) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds parport_unregister_device(dev); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds /* Send a daisy-chain-style CPP command packet. */ 3071da177e4SLinus Torvalds static int cpp_daisy(struct parport *port, int cmd) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds unsigned char s; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds parport_data_forward(port); 3121da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2); 3131da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2); 3141da177e4SLinus Torvalds parport_write_data(port, 0x00); udelay(2); 3151da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2); 3161da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY 3171da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 3181da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 3191da177e4SLinus Torvalds | PARPORT_STATUS_ERROR); 3201da177e4SLinus Torvalds if (s != (PARPORT_STATUS_BUSY 3211da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 3221da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 3231da177e4SLinus Torvalds | PARPORT_STATUS_ERROR)) { 3241da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n", 3251da177e4SLinus Torvalds port->name, s); 3261da177e4SLinus Torvalds return -ENXIO; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds parport_write_data(port, 0x87); udelay(2); 3301da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY 3311da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 3321da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 3331da177e4SLinus Torvalds | PARPORT_STATUS_ERROR); 3341da177e4SLinus Torvalds if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { 3351da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n", 3361da177e4SLinus Torvalds port->name, s); 3371da177e4SLinus Torvalds return -ENXIO; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds parport_write_data(port, 0x78); udelay(2); 3411da177e4SLinus Torvalds parport_write_data(port, cmd); udelay(2); 3421da177e4SLinus Torvalds parport_frob_control(port, 3431da177e4SLinus Torvalds PARPORT_CONTROL_STROBE, 3441da177e4SLinus Torvalds PARPORT_CONTROL_STROBE); 3451da177e4SLinus Torvalds udelay(1); 3467c9cc3beSMarko Kohtala s = parport_read_status(port); 3471da177e4SLinus Torvalds parport_frob_control(port, PARPORT_CONTROL_STROBE, 0); 3481da177e4SLinus Torvalds udelay(1); 3491da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds return s; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds /* Send a mux-style CPP command packet. */ 3551da177e4SLinus Torvalds static int cpp_mux(struct parport *port, int cmd) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds unsigned char s; 3581da177e4SLinus Torvalds int rc; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds parport_data_forward(port); 3611da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2); 3621da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2); 3631da177e4SLinus Torvalds parport_write_data(port, 0xf0); udelay(2); 3641da177e4SLinus Torvalds parport_write_data(port, 0x0f); udelay(2); 3651da177e4SLinus Torvalds parport_write_data(port, 0x52); udelay(2); 3661da177e4SLinus Torvalds parport_write_data(port, 0xad); udelay(2); 3671da177e4SLinus Torvalds parport_write_data(port, cmd); udelay(2); 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds s = parport_read_status(port); 3701da177e4SLinus Torvalds if (!(s & PARPORT_STATUS_ACK)) { 3711da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n", 3721da177e4SLinus Torvalds port->name, cmd, s); 3731da177e4SLinus Torvalds return -EIO; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) | 3771da177e4SLinus Torvalds ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) | 3781da177e4SLinus Torvalds ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) | 3791da177e4SLinus Torvalds ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3)); 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds return rc; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds void parport_daisy_deselect_all(struct parport *port) 3851da177e4SLinus Torvalds { 3861da177e4SLinus Torvalds cpp_daisy(port, 0x30); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds int parport_daisy_select(struct parport *port, int daisy, int mode) 3901da177e4SLinus Torvalds { 3911da177e4SLinus Torvalds switch (mode) 3921da177e4SLinus Torvalds { 3931da177e4SLinus Torvalds // For these modes we should switch to EPP mode: 3941da177e4SLinus Torvalds case IEEE1284_MODE_EPP: 3951da177e4SLinus Torvalds case IEEE1284_MODE_EPPSL: 3961da177e4SLinus Torvalds case IEEE1284_MODE_EPPSWE: 3977c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0x20 + daisy) & 3981da177e4SLinus Torvalds PARPORT_STATUS_ERROR); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds // For these modes we should switch to ECP mode: 4011da177e4SLinus Torvalds case IEEE1284_MODE_ECP: 4021da177e4SLinus Torvalds case IEEE1284_MODE_ECPRLE: 4031da177e4SLinus Torvalds case IEEE1284_MODE_ECPSWE: 4047c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0xd0 + daisy) & 4051da177e4SLinus Torvalds PARPORT_STATUS_ERROR); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds // Nothing was told for BECP in Daisy chain specification. 4081da177e4SLinus Torvalds // May be it's wise to use ECP? 4091da177e4SLinus Torvalds case IEEE1284_MODE_BECP: 4101da177e4SLinus Torvalds // Others use compat mode 4111da177e4SLinus Torvalds case IEEE1284_MODE_NIBBLE: 4121da177e4SLinus Torvalds case IEEE1284_MODE_BYTE: 4131da177e4SLinus Torvalds case IEEE1284_MODE_COMPAT: 4141da177e4SLinus Torvalds default: 4157c9cc3beSMarko Kohtala return !(cpp_daisy(port, 0xe0 + daisy) & 4161da177e4SLinus Torvalds PARPORT_STATUS_ERROR); 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds static int mux_present(struct parport *port) 4211da177e4SLinus Torvalds { 4221da177e4SLinus Torvalds return cpp_mux(port, 0x51) == 3; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds static int num_mux_ports(struct parport *port) 4261da177e4SLinus Torvalds { 4271da177e4SLinus Torvalds return cpp_mux(port, 0x58); 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds static int select_port(struct parport *port) 4311da177e4SLinus Torvalds { 4321da177e4SLinus Torvalds int muxport = port->muxport; 4331da177e4SLinus Torvalds return cpp_mux(port, 0x60 + muxport) == muxport; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static int assign_addrs(struct parport *port) 4371da177e4SLinus Torvalds { 438310c8c32SMarko Kohtala unsigned char s; 4391da177e4SLinus Torvalds unsigned char daisy; 4401da177e4SLinus Torvalds int thisdev = numdevs; 4411da177e4SLinus Torvalds int detected; 4421da177e4SLinus Torvalds char *deviceid; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds parport_data_forward(port); 4451da177e4SLinus Torvalds parport_write_data(port, 0xaa); udelay(2); 4461da177e4SLinus Torvalds parport_write_data(port, 0x55); udelay(2); 4471da177e4SLinus Torvalds parport_write_data(port, 0x00); udelay(2); 4481da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2); 4491da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY 4501da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 4511da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 4521da177e4SLinus Torvalds | PARPORT_STATUS_ERROR); 4531da177e4SLinus Torvalds if (s != (PARPORT_STATUS_BUSY 4541da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 4551da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 4561da177e4SLinus Torvalds | PARPORT_STATUS_ERROR)) { 4571da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", 4581da177e4SLinus Torvalds port->name, s); 4591da177e4SLinus Torvalds return 0; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds parport_write_data(port, 0x87); udelay(2); 4631da177e4SLinus Torvalds s = parport_read_status(port) & (PARPORT_STATUS_BUSY 4641da177e4SLinus Torvalds | PARPORT_STATUS_PAPEROUT 4651da177e4SLinus Torvalds | PARPORT_STATUS_SELECT 4661da177e4SLinus Torvalds | PARPORT_STATUS_ERROR); 4671da177e4SLinus Torvalds if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { 4681da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", 4691da177e4SLinus Torvalds port->name, s); 4701da177e4SLinus Torvalds return 0; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds parport_write_data(port, 0x78); udelay(2); 474310c8c32SMarko Kohtala s = parport_read_status(port); 4751da177e4SLinus Torvalds 476310c8c32SMarko Kohtala for (daisy = 0; 477310c8c32SMarko Kohtala (s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)) 478310c8c32SMarko Kohtala == (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT) 479310c8c32SMarko Kohtala && daisy < 4; 480310c8c32SMarko Kohtala ++daisy) { 4811da177e4SLinus Torvalds parport_write_data(port, daisy); 4821da177e4SLinus Torvalds udelay(2); 4831da177e4SLinus Torvalds parport_frob_control(port, 4841da177e4SLinus Torvalds PARPORT_CONTROL_STROBE, 4851da177e4SLinus Torvalds PARPORT_CONTROL_STROBE); 4861da177e4SLinus Torvalds udelay(1); 4871da177e4SLinus Torvalds parport_frob_control(port, PARPORT_CONTROL_STROBE, 0); 4881da177e4SLinus Torvalds udelay(1); 4891da177e4SLinus Torvalds 490310c8c32SMarko Kohtala add_dev(numdevs++, port, daisy); 491310c8c32SMarko Kohtala 492310c8c32SMarko Kohtala /* See if this device thought it was the last in the 493310c8c32SMarko Kohtala * chain. */ 494310c8c32SMarko Kohtala if (!(s & PARPORT_STATUS_BUSY)) 4951da177e4SLinus Torvalds break; 4961da177e4SLinus Torvalds 497310c8c32SMarko Kohtala /* We are seeing pass through status now. We see 498310c8c32SMarko Kohtala last_dev from next device or if last_dev does not 499310c8c32SMarko Kohtala work status lines from some non-daisy chain 500310c8c32SMarko Kohtala device. */ 501310c8c32SMarko Kohtala s = parport_read_status(port); 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds parport_write_data(port, 0xff); udelay(2); 5051da177e4SLinus Torvalds detected = numdevs - thisdev; 5061da177e4SLinus Torvalds DPRINTK(KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name, 5071da177e4SLinus Torvalds detected); 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* Ask the new devices to introduce themselves. */ 510b44d3bddSMarko Kohtala deviceid = kmalloc(1024, GFP_KERNEL); 5111da177e4SLinus Torvalds if (!deviceid) return 0; 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds for (daisy = 0; thisdev < numdevs; thisdev++, daisy++) 514b44d3bddSMarko Kohtala parport_device_id(thisdev, deviceid, 1024); 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds kfree(deviceid); 5171da177e4SLinus Torvalds return detected; 5181da177e4SLinus Torvalds } 519