linux/drivers/parport/daisy.c
<<
>>
Prefs
   1/*
   2 * IEEE 1284.3 Parallel port daisy chain and multiplexor code
   3 * 
   4 * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 *
  11 * ??-12-1998: Initial implementation.
  12 * 31-01-1999: Make port-cloning transparent.
  13 * 13-02-1999: Move DeviceID technique from parport_probe.
  14 * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
  15 * 22-02-2000: Count devices that are actually detected.
  16 *
  17 * Any part of this program may be used in documents licensed under
  18 * the GNU Free Documentation License, Version 1.1 or any later version
  19 * published by the Free Software Foundation.
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/parport.h>
  24#include <linux/delay.h>
  25#include <linux/sched.h>
  26
  27#include <asm/current.h>
  28#include <asm/uaccess.h>
  29
  30#undef DEBUG
  31
  32#ifdef DEBUG
  33#define DPRINTK(stuff...) printk(stuff)
  34#else
  35#define DPRINTK(stuff...)
  36#endif
  37
  38static struct daisydev {
  39        struct daisydev *next;
  40        struct parport *port;
  41        int daisy;
  42        int devnum;
  43} *topology = NULL;
  44static DEFINE_SPINLOCK(topology_lock);
  45
  46static int numdevs = 0;
  47
  48/* Forward-declaration of lower-level functions. */
  49static int mux_present(struct parport *port);
  50static int num_mux_ports(struct parport *port);
  51static int select_port(struct parport *port);
  52static int assign_addrs(struct parport *port);
  53
  54/* Add a device to the discovered topology. */
  55static void add_dev(int devnum, struct parport *port, int daisy)
  56{
  57        struct daisydev *newdev, **p;
  58        newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL);
  59        if (newdev) {
  60                newdev->port = port;
  61                newdev->daisy = daisy;
  62                newdev->devnum = devnum;
  63                spin_lock(&topology_lock);
  64                for (p = &topology; *p && (*p)->devnum<devnum; p = &(*p)->next)
  65                        ;
  66                newdev->next = *p;
  67                *p = newdev;
  68                spin_unlock(&topology_lock);
  69        }
  70}
  71
  72/* Clone a parport (actually, make an alias). */
  73static struct parport *clone_parport(struct parport *real, int muxport)
  74{
  75        struct parport *extra = parport_register_port(real->base,
  76                                                       real->irq,
  77                                                       real->dma,
  78                                                       real->ops);
  79        if (extra) {
  80                extra->portnum = real->portnum;
  81                extra->physport = real;
  82                extra->muxport = muxport;
  83                real->slaves[muxport-1] = extra;
  84        }
  85
  86        return extra;
  87}
  88
  89/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
  90 * Return value is number of devices actually detected. */
  91int parport_daisy_init(struct parport *port)
  92{
  93        int detected = 0;
  94        char *deviceid;
  95        static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
  96        int num_ports;
  97        int i;
  98        int last_try = 0;
  99
 100again:
 101        /* Because this is called before any other devices exist,
 102         * we don't have to claim exclusive access.  */
 103
 104        /* If mux present on normal port, need to create new
 105         * parports for each extra port. */
 106        if (port->muxport < 0 && mux_present(port) &&
 107            /* don't be fooled: a mux must have 2 or 4 ports. */
 108            ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) {
 109                /* Leave original as port zero. */
 110                port->muxport = 0;
 111                printk(KERN_INFO
 112                        "%s: 1st (default) port of %d-way multiplexor\n",
 113                        port->name, num_ports);
 114                for (i = 1; i < num_ports; i++) {
 115                        /* Clone the port. */
 116                        struct parport *extra = clone_parport(port, i);
 117                        if (!extra) {
 118                                if (signal_pending(current))
 119                                        break;
 120
 121                                schedule();
 122                                continue;
 123                        }
 124
 125                        printk(KERN_INFO
 126                                "%s: %d%s port of %d-way multiplexor on %s\n",
 127                                extra->name, i + 1, th[i + 1], num_ports,
 128                                port->name);
 129
 130                        /* Analyse that port too.  We won't recurse
 131                           forever because of the 'port->muxport < 0'
 132                           test above. */
 133                        parport_daisy_init(extra);
 134                }
 135        }
 136
 137        if (port->muxport >= 0)
 138                select_port(port);
 139
 140        parport_daisy_deselect_all(port);
 141        detected += assign_addrs(port);
 142
 143        /* Count the potential legacy device at the end. */
 144        add_dev(numdevs++, port, -1);
 145
 146        /* Find out the legacy device's IEEE 1284 device ID. */
 147        deviceid = kmalloc(1024, GFP_KERNEL);
 148        if (deviceid) {
 149                if (parport_device_id(numdevs - 1, deviceid, 1024) > 2)
 150                        detected++;
 151
 152                kfree(deviceid);
 153        }
 154
 155        if (!detected && !last_try) {
 156                /* No devices were detected.  Perhaps they are in some
 157                   funny state; let's try to reset them and see if
 158                   they wake up. */
 159                parport_daisy_fini(port);
 160                parport_write_control(port, PARPORT_CONTROL_SELECT);
 161                udelay(50);
 162                parport_write_control(port,
 163                                       PARPORT_CONTROL_SELECT |
 164                                       PARPORT_CONTROL_INIT);
 165                udelay(50);
 166                last_try = 1;
 167                goto again;
 168        }
 169
 170        return detected;
 171}
 172
 173/* Forget about devices on a physical port. */
 174void parport_daisy_fini(struct parport *port)
 175{
 176        struct daisydev **p;
 177
 178        spin_lock(&topology_lock);
 179        p = &topology;
 180        while (*p) {
 181                struct daisydev *dev = *p;
 182                if (dev->port != port) {
 183                        p = &dev->next;
 184                        continue;
 185                }
 186                *p = dev->next;
 187                kfree(dev);
 188        }
 189
 190        /* Gaps in the numbering could be handled better.  How should
 191           someone enumerate through all IEEE1284.3 devices in the
 192           topology?. */
 193        if (!topology) numdevs = 0;
 194        spin_unlock(&topology_lock);
 195        return;
 196}
 197
 198/**
 199 *      parport_open - find a device by canonical device number
 200 *      @devnum: canonical device number
 201 *      @name: name to associate with the device
 202 *
 203 *      This function is similar to parport_register_device(), except
 204 *      that it locates a device by its number rather than by the port
 205 *      it is attached to.
 206 *
 207 *      All parameters except for @devnum are the same as for
 208 *      parport_register_device().  The return value is the same as
 209 *      for parport_register_device().
 210 **/
 211
 212struct pardevice *parport_open(int devnum, const char *name)
 213{
 214        struct daisydev *p = topology;
 215        struct parport *port;
 216        struct pardevice *dev;
 217        int daisy;
 218
 219        spin_lock(&topology_lock);
 220        while (p && p->devnum != devnum)
 221                p = p->next;
 222
 223        if (!p) {
 224                spin_unlock(&topology_lock);
 225                return NULL;
 226        }
 227
 228        daisy = p->daisy;
 229        port = parport_get_port(p->port);
 230        spin_unlock(&topology_lock);
 231
 232        dev = parport_register_device(port, name, NULL, NULL, NULL, 0, NULL);
 233        parport_put_port(port);
 234        if (!dev)
 235                return NULL;
 236
 237        dev->daisy = daisy;
 238
 239        /* Check that there really is a device to select. */
 240        if (daisy >= 0) {
 241                int selected;
 242                parport_claim_or_block(dev);
 243                selected = port->daisy;
 244                parport_release(dev);
 245
 246                if (selected != daisy) {
 247                        /* No corresponding device. */
 248                        parport_unregister_device(dev);
 249                        return NULL;
 250                }
 251        }
 252
 253        return dev;
 254}
 255
 256/**
 257 *      parport_close - close a device opened with parport_open()
 258 *      @dev: device to close
 259 *
 260 *      This is to parport_open() as parport_unregister_device() is to
 261 *      parport_register_device().
 262 **/
 263
 264void parport_close(struct pardevice *dev)
 265{
 266        parport_unregister_device(dev);
 267}
 268
 269/* Send a daisy-chain-style CPP command packet. */
 270static int cpp_daisy(struct parport *port, int cmd)
 271{
 272        unsigned char s;
 273
 274        parport_data_forward(port);
 275        parport_write_data(port, 0xaa); udelay(2);
 276        parport_write_data(port, 0x55); udelay(2);
 277        parport_write_data(port, 0x00); udelay(2);
 278        parport_write_data(port, 0xff); udelay(2);
 279        s = parport_read_status(port) & (PARPORT_STATUS_BUSY
 280                                          | PARPORT_STATUS_PAPEROUT
 281                                          | PARPORT_STATUS_SELECT
 282                                          | PARPORT_STATUS_ERROR);
 283        if (s != (PARPORT_STATUS_BUSY
 284                  | PARPORT_STATUS_PAPEROUT
 285                  | PARPORT_STATUS_SELECT
 286                  | PARPORT_STATUS_ERROR)) {
 287                DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
 288                         port->name, s);
 289                return -ENXIO;
 290        }
 291
 292        parport_write_data(port, 0x87); udelay(2);
 293        s = parport_read_status(port) & (PARPORT_STATUS_BUSY
 294                                          | PARPORT_STATUS_PAPEROUT
 295                                          | PARPORT_STATUS_SELECT
 296                                          | PARPORT_STATUS_ERROR);
 297        if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
 298                DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
 299                         port->name, s);
 300                return -ENXIO;
 301        }
 302
 303        parport_write_data(port, 0x78); udelay(2);
 304        parport_write_data(port, cmd); udelay(2);
 305        parport_frob_control(port,
 306                              PARPORT_CONTROL_STROBE,
 307                              PARPORT_CONTROL_STROBE);
 308        udelay(1);
 309        s = parport_read_status(port);
 310        parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
 311        udelay(1);
 312        parport_write_data(port, 0xff); udelay(2);
 313
 314        return s;
 315}
 316
 317/* Send a mux-style CPP command packet. */
 318static int cpp_mux(struct parport *port, int cmd)
 319{
 320        unsigned char s;
 321        int rc;
 322
 323        parport_data_forward(port);
 324        parport_write_data(port, 0xaa); udelay(2);
 325        parport_write_data(port, 0x55); udelay(2);
 326        parport_write_data(port, 0xf0); udelay(2);
 327        parport_write_data(port, 0x0f); udelay(2);
 328        parport_write_data(port, 0x52); udelay(2);
 329        parport_write_data(port, 0xad); udelay(2);
 330        parport_write_data(port, cmd); udelay(2);
 331
 332        s = parport_read_status(port);
 333        if (!(s & PARPORT_STATUS_ACK)) {
 334                DPRINTK(KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
 335                         port->name, cmd, s);
 336                return -EIO;
 337        }
 338
 339        rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
 340              ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
 341              ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
 342              ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
 343
 344        return rc;
 345}
 346
 347void parport_daisy_deselect_all(struct parport *port)
 348{
 349        cpp_daisy(port, 0x30);
 350}
 351
 352int parport_daisy_select(struct parport *port, int daisy, int mode)
 353{
 354        switch (mode)
 355        {
 356                // For these modes we should switch to EPP mode:
 357                case IEEE1284_MODE_EPP:
 358                case IEEE1284_MODE_EPPSL:
 359                case IEEE1284_MODE_EPPSWE:
 360                        return !(cpp_daisy(port, 0x20 + daisy) &
 361                                 PARPORT_STATUS_ERROR);
 362
 363                // For these modes we should switch to ECP mode:
 364                case IEEE1284_MODE_ECP:
 365                case IEEE1284_MODE_ECPRLE:
 366                case IEEE1284_MODE_ECPSWE: 
 367                        return !(cpp_daisy(port, 0xd0 + daisy) &
 368                                 PARPORT_STATUS_ERROR);
 369
 370                // Nothing was told for BECP in Daisy chain specification.
 371                // May be it's wise to use ECP?
 372                case IEEE1284_MODE_BECP:
 373                // Others use compat mode
 374                case IEEE1284_MODE_NIBBLE:
 375                case IEEE1284_MODE_BYTE:
 376                case IEEE1284_MODE_COMPAT:
 377                default:
 378                        return !(cpp_daisy(port, 0xe0 + daisy) &
 379                                 PARPORT_STATUS_ERROR);
 380        }
 381}
 382
 383static int mux_present(struct parport *port)
 384{
 385        return cpp_mux(port, 0x51) == 3;
 386}
 387
 388static int num_mux_ports(struct parport *port)
 389{
 390        return cpp_mux(port, 0x58);
 391}
 392
 393static int select_port(struct parport *port)
 394{
 395        int muxport = port->muxport;
 396        return cpp_mux(port, 0x60 + muxport) == muxport;
 397}
 398
 399static int assign_addrs(struct parport *port)
 400{
 401        unsigned char s;
 402        unsigned char daisy;
 403        int thisdev = numdevs;
 404        int detected;
 405        char *deviceid;
 406
 407        parport_data_forward(port);
 408        parport_write_data(port, 0xaa); udelay(2);
 409        parport_write_data(port, 0x55); udelay(2);
 410        parport_write_data(port, 0x00); udelay(2);
 411        parport_write_data(port, 0xff); udelay(2);
 412        s = parport_read_status(port) & (PARPORT_STATUS_BUSY
 413                                          | PARPORT_STATUS_PAPEROUT
 414                                          | PARPORT_STATUS_SELECT
 415                                          | PARPORT_STATUS_ERROR);
 416        if (s != (PARPORT_STATUS_BUSY
 417                  | PARPORT_STATUS_PAPEROUT
 418                  | PARPORT_STATUS_SELECT
 419                  | PARPORT_STATUS_ERROR)) {
 420                DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
 421                         port->name, s);
 422                return 0;
 423        }
 424
 425        parport_write_data(port, 0x87); udelay(2);
 426        s = parport_read_status(port) & (PARPORT_STATUS_BUSY
 427                                          | PARPORT_STATUS_PAPEROUT
 428                                          | PARPORT_STATUS_SELECT
 429                                          | PARPORT_STATUS_ERROR);
 430        if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
 431                DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
 432                         port->name, s);
 433                return 0;
 434        }
 435
 436        parport_write_data(port, 0x78); udelay(2);
 437        s = parport_read_status(port);
 438
 439        for (daisy = 0;
 440             (s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT))
 441                     == (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)
 442                     && daisy < 4;
 443             ++daisy) {
 444                parport_write_data(port, daisy);
 445                udelay(2);
 446                parport_frob_control(port,
 447                                      PARPORT_CONTROL_STROBE,
 448                                      PARPORT_CONTROL_STROBE);
 449                udelay(1);
 450                parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
 451                udelay(1);
 452
 453                add_dev(numdevs++, port, daisy);
 454
 455                /* See if this device thought it was the last in the
 456                 * chain. */
 457                if (!(s & PARPORT_STATUS_BUSY))
 458                        break;
 459
 460                /* We are seeing pass through status now. We see
 461                   last_dev from next device or if last_dev does not
 462                   work status lines from some non-daisy chain
 463                   device. */
 464                s = parport_read_status(port);
 465        }
 466
 467        parport_write_data(port, 0xff); udelay(2);
 468        detected = numdevs - thisdev;
 469        DPRINTK(KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
 470                 detected);
 471
 472        /* Ask the new devices to introduce themselves. */
 473        deviceid = kmalloc(1024, GFP_KERNEL);
 474        if (!deviceid) return 0;
 475
 476        for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
 477                parport_device_id(thisdev, deviceid, 1024);
 478
 479        kfree(deviceid);
 480        return detected;
 481}
 482
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.