162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * IEEE 1284.3 Parallel port daisy chain and multiplexor code 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 762306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License 862306a36Sopenharmony_ci * as published by the Free Software Foundation; either version 962306a36Sopenharmony_ci * 2 of the License, or (at your option) any later version. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * ??-12-1998: Initial implementation. 1262306a36Sopenharmony_ci * 31-01-1999: Make port-cloning transparent. 1362306a36Sopenharmony_ci * 13-02-1999: Move DeviceID technique from parport_probe. 1462306a36Sopenharmony_ci * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. 1562306a36Sopenharmony_ci * 22-02-2000: Count devices that are actually detected. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Any part of this program may be used in documents licensed under 1862306a36Sopenharmony_ci * the GNU Free Documentation License, Version 1.1 or any later version 1962306a36Sopenharmony_ci * published by the Free Software Foundation. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/parport.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/sched/signal.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <asm/current.h> 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#undef DEBUG 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct daisydev { 3462306a36Sopenharmony_ci struct daisydev *next; 3562306a36Sopenharmony_ci struct parport *port; 3662306a36Sopenharmony_ci int daisy; 3762306a36Sopenharmony_ci int devnum; 3862306a36Sopenharmony_ci} *topology = NULL; 3962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(topology_lock); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int numdevs; 4262306a36Sopenharmony_cistatic bool daisy_init_done; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Forward-declaration of lower-level functions. */ 4562306a36Sopenharmony_cistatic int mux_present(struct parport *port); 4662306a36Sopenharmony_cistatic int num_mux_ports(struct parport *port); 4762306a36Sopenharmony_cistatic int select_port(struct parport *port); 4862306a36Sopenharmony_cistatic int assign_addrs(struct parport *port); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Add a device to the discovered topology. */ 5162306a36Sopenharmony_cistatic void add_dev(int devnum, struct parport *port, int daisy) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct daisydev *newdev, **p; 5462306a36Sopenharmony_ci newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL); 5562306a36Sopenharmony_ci if (newdev) { 5662306a36Sopenharmony_ci newdev->port = port; 5762306a36Sopenharmony_ci newdev->daisy = daisy; 5862306a36Sopenharmony_ci newdev->devnum = devnum; 5962306a36Sopenharmony_ci spin_lock(&topology_lock); 6062306a36Sopenharmony_ci for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next) 6162306a36Sopenharmony_ci ; 6262306a36Sopenharmony_ci newdev->next = *p; 6362306a36Sopenharmony_ci *p = newdev; 6462306a36Sopenharmony_ci spin_unlock(&topology_lock); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Clone a parport (actually, make an alias). */ 6962306a36Sopenharmony_cistatic struct parport *clone_parport(struct parport *real, int muxport) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct parport *extra = parport_register_port(real->base, 7262306a36Sopenharmony_ci real->irq, 7362306a36Sopenharmony_ci real->dma, 7462306a36Sopenharmony_ci real->ops); 7562306a36Sopenharmony_ci if (extra) { 7662306a36Sopenharmony_ci extra->portnum = real->portnum; 7762306a36Sopenharmony_ci extra->physport = real; 7862306a36Sopenharmony_ci extra->muxport = muxport; 7962306a36Sopenharmony_ci real->slaves[muxport-1] = extra; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return extra; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int daisy_drv_probe(struct pardevice *par_dev) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct device_driver *drv = par_dev->dev.driver; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (strcmp(drv->name, "daisy_drv")) 9062306a36Sopenharmony_ci return -ENODEV; 9162306a36Sopenharmony_ci if (strcmp(par_dev->name, daisy_dev_name)) 9262306a36Sopenharmony_ci return -ENODEV; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct parport_driver daisy_driver = { 9862306a36Sopenharmony_ci .name = "daisy_drv", 9962306a36Sopenharmony_ci .probe = daisy_drv_probe, 10062306a36Sopenharmony_ci .devmodel = true, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. 10462306a36Sopenharmony_ci * Return value is number of devices actually detected. */ 10562306a36Sopenharmony_ciint parport_daisy_init(struct parport *port) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int detected = 0; 10862306a36Sopenharmony_ci char *deviceid; 10962306a36Sopenharmony_ci static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; 11062306a36Sopenharmony_ci int num_ports; 11162306a36Sopenharmony_ci int i; 11262306a36Sopenharmony_ci int last_try = 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!daisy_init_done) { 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * flag should be marked true first as 11762306a36Sopenharmony_ci * parport_register_driver() might try to load the low 11862306a36Sopenharmony_ci * level driver which will lead to announcing new ports 11962306a36Sopenharmony_ci * and which will again come back here at 12062306a36Sopenharmony_ci * parport_daisy_init() 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci daisy_init_done = true; 12362306a36Sopenharmony_ci i = parport_register_driver(&daisy_driver); 12462306a36Sopenharmony_ci if (i) { 12562306a36Sopenharmony_ci pr_err("daisy registration failed\n"); 12662306a36Sopenharmony_ci daisy_init_done = false; 12762306a36Sopenharmony_ci return i; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciagain: 13262306a36Sopenharmony_ci /* Because this is called before any other devices exist, 13362306a36Sopenharmony_ci * we don't have to claim exclusive access. */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* If mux present on normal port, need to create new 13662306a36Sopenharmony_ci * parports for each extra port. */ 13762306a36Sopenharmony_ci if (port->muxport < 0 && mux_present(port) && 13862306a36Sopenharmony_ci /* don't be fooled: a mux must have 2 or 4 ports. */ 13962306a36Sopenharmony_ci ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) { 14062306a36Sopenharmony_ci /* Leave original as port zero. */ 14162306a36Sopenharmony_ci port->muxport = 0; 14262306a36Sopenharmony_ci pr_info("%s: 1st (default) port of %d-way multiplexor\n", 14362306a36Sopenharmony_ci port->name, num_ports); 14462306a36Sopenharmony_ci for (i = 1; i < num_ports; i++) { 14562306a36Sopenharmony_ci /* Clone the port. */ 14662306a36Sopenharmony_ci struct parport *extra = clone_parport(port, i); 14762306a36Sopenharmony_ci if (!extra) { 14862306a36Sopenharmony_ci if (signal_pending(current)) 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci schedule(); 15262306a36Sopenharmony_ci continue; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci pr_info("%s: %d%s port of %d-way multiplexor on %s\n", 15662306a36Sopenharmony_ci extra->name, i + 1, th[i + 1], num_ports, 15762306a36Sopenharmony_ci port->name); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Analyse that port too. We won't recurse 16062306a36Sopenharmony_ci forever because of the 'port->muxport < 0' 16162306a36Sopenharmony_ci test above. */ 16262306a36Sopenharmony_ci parport_daisy_init(extra); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (port->muxport >= 0) 16762306a36Sopenharmony_ci select_port(port); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci parport_daisy_deselect_all(port); 17062306a36Sopenharmony_ci detected += assign_addrs(port); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Count the potential legacy device at the end. */ 17362306a36Sopenharmony_ci add_dev(numdevs++, port, -1); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Find out the legacy device's IEEE 1284 device ID. */ 17662306a36Sopenharmony_ci deviceid = kmalloc(1024, GFP_KERNEL); 17762306a36Sopenharmony_ci if (deviceid) { 17862306a36Sopenharmony_ci if (parport_device_id(numdevs - 1, deviceid, 1024) > 2) 17962306a36Sopenharmony_ci detected++; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci kfree(deviceid); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (!detected && !last_try) { 18562306a36Sopenharmony_ci /* No devices were detected. Perhaps they are in some 18662306a36Sopenharmony_ci funny state; let's try to reset them and see if 18762306a36Sopenharmony_ci they wake up. */ 18862306a36Sopenharmony_ci parport_daisy_fini(port); 18962306a36Sopenharmony_ci parport_write_control(port, PARPORT_CONTROL_SELECT); 19062306a36Sopenharmony_ci udelay(50); 19162306a36Sopenharmony_ci parport_write_control(port, 19262306a36Sopenharmony_ci PARPORT_CONTROL_SELECT | 19362306a36Sopenharmony_ci PARPORT_CONTROL_INIT); 19462306a36Sopenharmony_ci udelay(50); 19562306a36Sopenharmony_ci last_try = 1; 19662306a36Sopenharmony_ci goto again; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return detected; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* Forget about devices on a physical port. */ 20362306a36Sopenharmony_civoid parport_daisy_fini(struct parport *port) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct daisydev **p; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci spin_lock(&topology_lock); 20862306a36Sopenharmony_ci p = &topology; 20962306a36Sopenharmony_ci while (*p) { 21062306a36Sopenharmony_ci struct daisydev *dev = *p; 21162306a36Sopenharmony_ci if (dev->port != port) { 21262306a36Sopenharmony_ci p = &dev->next; 21362306a36Sopenharmony_ci continue; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci *p = dev->next; 21662306a36Sopenharmony_ci kfree(dev); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Gaps in the numbering could be handled better. How should 22062306a36Sopenharmony_ci someone enumerate through all IEEE1284.3 devices in the 22162306a36Sopenharmony_ci topology?. */ 22262306a36Sopenharmony_ci if (!topology) numdevs = 0; 22362306a36Sopenharmony_ci spin_unlock(&topology_lock); 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * parport_open - find a device by canonical device number 22962306a36Sopenharmony_ci * @devnum: canonical device number 23062306a36Sopenharmony_ci * @name: name to associate with the device 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * This function is similar to parport_register_device(), except 23362306a36Sopenharmony_ci * that it locates a device by its number rather than by the port 23462306a36Sopenharmony_ci * it is attached to. 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * All parameters except for @devnum are the same as for 23762306a36Sopenharmony_ci * parport_register_device(). The return value is the same as 23862306a36Sopenharmony_ci * for parport_register_device(). 23962306a36Sopenharmony_ci **/ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistruct pardevice *parport_open(int devnum, const char *name) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct daisydev *p = topology; 24462306a36Sopenharmony_ci struct pardev_cb par_cb; 24562306a36Sopenharmony_ci struct parport *port; 24662306a36Sopenharmony_ci struct pardevice *dev; 24762306a36Sopenharmony_ci int daisy; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci memset(&par_cb, 0, sizeof(par_cb)); 25062306a36Sopenharmony_ci spin_lock(&topology_lock); 25162306a36Sopenharmony_ci while (p && p->devnum != devnum) 25262306a36Sopenharmony_ci p = p->next; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!p) { 25562306a36Sopenharmony_ci spin_unlock(&topology_lock); 25662306a36Sopenharmony_ci return NULL; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci daisy = p->daisy; 26062306a36Sopenharmony_ci port = parport_get_port(p->port); 26162306a36Sopenharmony_ci spin_unlock(&topology_lock); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci dev = parport_register_dev_model(port, name, &par_cb, devnum); 26462306a36Sopenharmony_ci parport_put_port(port); 26562306a36Sopenharmony_ci if (!dev) 26662306a36Sopenharmony_ci return NULL; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci dev->daisy = daisy; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Check that there really is a device to select. */ 27162306a36Sopenharmony_ci if (daisy >= 0) { 27262306a36Sopenharmony_ci int selected; 27362306a36Sopenharmony_ci parport_claim_or_block(dev); 27462306a36Sopenharmony_ci selected = port->daisy; 27562306a36Sopenharmony_ci parport_release(dev); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (selected != daisy) { 27862306a36Sopenharmony_ci /* No corresponding device. */ 27962306a36Sopenharmony_ci parport_unregister_device(dev); 28062306a36Sopenharmony_ci return NULL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return dev; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/** 28862306a36Sopenharmony_ci * parport_close - close a device opened with parport_open() 28962306a36Sopenharmony_ci * @dev: device to close 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * This is to parport_open() as parport_unregister_device() is to 29262306a36Sopenharmony_ci * parport_register_device(). 29362306a36Sopenharmony_ci **/ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_civoid parport_close(struct pardevice *dev) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci parport_unregister_device(dev); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Send a daisy-chain-style CPP command packet. */ 30162306a36Sopenharmony_cistatic int cpp_daisy(struct parport *port, int cmd) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci unsigned char s; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci parport_data_forward(port); 30662306a36Sopenharmony_ci parport_write_data(port, 0xaa); udelay(2); 30762306a36Sopenharmony_ci parport_write_data(port, 0x55); udelay(2); 30862306a36Sopenharmony_ci parport_write_data(port, 0x00); udelay(2); 30962306a36Sopenharmony_ci parport_write_data(port, 0xff); udelay(2); 31062306a36Sopenharmony_ci s = parport_read_status(port) & (PARPORT_STATUS_BUSY 31162306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 31262306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 31362306a36Sopenharmony_ci | PARPORT_STATUS_ERROR); 31462306a36Sopenharmony_ci if (s != (PARPORT_STATUS_BUSY 31562306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 31662306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 31762306a36Sopenharmony_ci | PARPORT_STATUS_ERROR)) { 31862306a36Sopenharmony_ci pr_debug("%s: cpp_daisy: aa5500ff(%02x)\n", port->name, s); 31962306a36Sopenharmony_ci return -ENXIO; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci parport_write_data(port, 0x87); udelay(2); 32362306a36Sopenharmony_ci s = parport_read_status(port) & (PARPORT_STATUS_BUSY 32462306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 32562306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 32662306a36Sopenharmony_ci | PARPORT_STATUS_ERROR); 32762306a36Sopenharmony_ci if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { 32862306a36Sopenharmony_ci pr_debug("%s: cpp_daisy: aa5500ff87(%02x)\n", port->name, s); 32962306a36Sopenharmony_ci return -ENXIO; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci parport_write_data(port, 0x78); udelay(2); 33362306a36Sopenharmony_ci parport_write_data(port, cmd); udelay(2); 33462306a36Sopenharmony_ci parport_frob_control(port, 33562306a36Sopenharmony_ci PARPORT_CONTROL_STROBE, 33662306a36Sopenharmony_ci PARPORT_CONTROL_STROBE); 33762306a36Sopenharmony_ci udelay(1); 33862306a36Sopenharmony_ci s = parport_read_status(port); 33962306a36Sopenharmony_ci parport_frob_control(port, PARPORT_CONTROL_STROBE, 0); 34062306a36Sopenharmony_ci udelay(1); 34162306a36Sopenharmony_ci parport_write_data(port, 0xff); udelay(2); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return s; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* Send a mux-style CPP command packet. */ 34762306a36Sopenharmony_cistatic int cpp_mux(struct parport *port, int cmd) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci unsigned char s; 35062306a36Sopenharmony_ci int rc; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci parport_data_forward(port); 35362306a36Sopenharmony_ci parport_write_data(port, 0xaa); udelay(2); 35462306a36Sopenharmony_ci parport_write_data(port, 0x55); udelay(2); 35562306a36Sopenharmony_ci parport_write_data(port, 0xf0); udelay(2); 35662306a36Sopenharmony_ci parport_write_data(port, 0x0f); udelay(2); 35762306a36Sopenharmony_ci parport_write_data(port, 0x52); udelay(2); 35862306a36Sopenharmony_ci parport_write_data(port, 0xad); udelay(2); 35962306a36Sopenharmony_ci parport_write_data(port, cmd); udelay(2); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci s = parport_read_status(port); 36262306a36Sopenharmony_ci if (!(s & PARPORT_STATUS_ACK)) { 36362306a36Sopenharmony_ci pr_debug("%s: cpp_mux: aa55f00f52ad%02x(%02x)\n", 36462306a36Sopenharmony_ci port->name, cmd, s); 36562306a36Sopenharmony_ci return -EIO; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) | 36962306a36Sopenharmony_ci ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) | 37062306a36Sopenharmony_ci ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) | 37162306a36Sopenharmony_ci ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3)); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return rc; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_civoid parport_daisy_deselect_all(struct parport *port) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci cpp_daisy(port, 0x30); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciint parport_daisy_select(struct parport *port, int daisy, int mode) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci switch (mode) 38462306a36Sopenharmony_ci { 38562306a36Sopenharmony_ci // For these modes we should switch to EPP mode: 38662306a36Sopenharmony_ci case IEEE1284_MODE_EPP: 38762306a36Sopenharmony_ci case IEEE1284_MODE_EPPSL: 38862306a36Sopenharmony_ci case IEEE1284_MODE_EPPSWE: 38962306a36Sopenharmony_ci return !(cpp_daisy(port, 0x20 + daisy) & 39062306a36Sopenharmony_ci PARPORT_STATUS_ERROR); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci // For these modes we should switch to ECP mode: 39362306a36Sopenharmony_ci case IEEE1284_MODE_ECP: 39462306a36Sopenharmony_ci case IEEE1284_MODE_ECPRLE: 39562306a36Sopenharmony_ci case IEEE1284_MODE_ECPSWE: 39662306a36Sopenharmony_ci return !(cpp_daisy(port, 0xd0 + daisy) & 39762306a36Sopenharmony_ci PARPORT_STATUS_ERROR); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci // Nothing was told for BECP in Daisy chain specification. 40062306a36Sopenharmony_ci // May be it's wise to use ECP? 40162306a36Sopenharmony_ci case IEEE1284_MODE_BECP: 40262306a36Sopenharmony_ci // Others use compat mode 40362306a36Sopenharmony_ci case IEEE1284_MODE_NIBBLE: 40462306a36Sopenharmony_ci case IEEE1284_MODE_BYTE: 40562306a36Sopenharmony_ci case IEEE1284_MODE_COMPAT: 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci return !(cpp_daisy(port, 0xe0 + daisy) & 40862306a36Sopenharmony_ci PARPORT_STATUS_ERROR); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int mux_present(struct parport *port) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci return cpp_mux(port, 0x51) == 3; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int num_mux_ports(struct parport *port) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci return cpp_mux(port, 0x58); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int select_port(struct parport *port) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci int muxport = port->muxport; 42562306a36Sopenharmony_ci return cpp_mux(port, 0x60 + muxport) == muxport; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int assign_addrs(struct parport *port) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci unsigned char s; 43162306a36Sopenharmony_ci unsigned char daisy; 43262306a36Sopenharmony_ci int thisdev = numdevs; 43362306a36Sopenharmony_ci int detected; 43462306a36Sopenharmony_ci char *deviceid; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci parport_data_forward(port); 43762306a36Sopenharmony_ci parport_write_data(port, 0xaa); udelay(2); 43862306a36Sopenharmony_ci parport_write_data(port, 0x55); udelay(2); 43962306a36Sopenharmony_ci parport_write_data(port, 0x00); udelay(2); 44062306a36Sopenharmony_ci parport_write_data(port, 0xff); udelay(2); 44162306a36Sopenharmony_ci s = parport_read_status(port) & (PARPORT_STATUS_BUSY 44262306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 44362306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 44462306a36Sopenharmony_ci | PARPORT_STATUS_ERROR); 44562306a36Sopenharmony_ci if (s != (PARPORT_STATUS_BUSY 44662306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 44762306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 44862306a36Sopenharmony_ci | PARPORT_STATUS_ERROR)) { 44962306a36Sopenharmony_ci pr_debug("%s: assign_addrs: aa5500ff(%02x)\n", port->name, s); 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci parport_write_data(port, 0x87); udelay(2); 45462306a36Sopenharmony_ci s = parport_read_status(port) & (PARPORT_STATUS_BUSY 45562306a36Sopenharmony_ci | PARPORT_STATUS_PAPEROUT 45662306a36Sopenharmony_ci | PARPORT_STATUS_SELECT 45762306a36Sopenharmony_ci | PARPORT_STATUS_ERROR); 45862306a36Sopenharmony_ci if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { 45962306a36Sopenharmony_ci pr_debug("%s: assign_addrs: aa5500ff87(%02x)\n", port->name, s); 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci parport_write_data(port, 0x78); udelay(2); 46462306a36Sopenharmony_ci s = parport_read_status(port); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci for (daisy = 0; 46762306a36Sopenharmony_ci (s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)) 46862306a36Sopenharmony_ci == (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT) 46962306a36Sopenharmony_ci && daisy < 4; 47062306a36Sopenharmony_ci ++daisy) { 47162306a36Sopenharmony_ci parport_write_data(port, daisy); 47262306a36Sopenharmony_ci udelay(2); 47362306a36Sopenharmony_ci parport_frob_control(port, 47462306a36Sopenharmony_ci PARPORT_CONTROL_STROBE, 47562306a36Sopenharmony_ci PARPORT_CONTROL_STROBE); 47662306a36Sopenharmony_ci udelay(1); 47762306a36Sopenharmony_ci parport_frob_control(port, PARPORT_CONTROL_STROBE, 0); 47862306a36Sopenharmony_ci udelay(1); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci add_dev(numdevs++, port, daisy); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* See if this device thought it was the last in the 48362306a36Sopenharmony_ci * chain. */ 48462306a36Sopenharmony_ci if (!(s & PARPORT_STATUS_BUSY)) 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* We are seeing pass through status now. We see 48862306a36Sopenharmony_ci last_dev from next device or if last_dev does not 48962306a36Sopenharmony_ci work status lines from some non-daisy chain 49062306a36Sopenharmony_ci device. */ 49162306a36Sopenharmony_ci s = parport_read_status(port); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci parport_write_data(port, 0xff); udelay(2); 49562306a36Sopenharmony_ci detected = numdevs - thisdev; 49662306a36Sopenharmony_ci pr_debug("%s: Found %d daisy-chained devices\n", port->name, detected); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* Ask the new devices to introduce themselves. */ 49962306a36Sopenharmony_ci deviceid = kmalloc(1024, GFP_KERNEL); 50062306a36Sopenharmony_ci if (!deviceid) return 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci for (daisy = 0; thisdev < numdevs; thisdev++, daisy++) 50362306a36Sopenharmony_ci parport_device_id(thisdev, deviceid, 1024); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci kfree(deviceid); 50662306a36Sopenharmony_ci return detected; 50762306a36Sopenharmony_ci} 508