OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [parport/] [daisy.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 
38
static struct daisydev {
39
        struct daisydev *next;
40
        struct parport *port;
41
        int daisy;
42
        int devnum;
43
} *topology = NULL;
44
static DEFINE_SPINLOCK(topology_lock);
45
 
46
static int numdevs = 0;
47
 
48
/* Forward-declaration of lower-level functions. */
49
static int mux_present(struct parport *port);
50
static int num_mux_ports(struct parport *port);
51
static int select_port(struct parport *port);
52
static int assign_addrs(struct parport *port);
53
 
54
/* Add a device to the discovered topology. */
55
static 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). */
73
static 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. */
91
int 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
 
100
again:
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. */
174
void 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
 
212
struct 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
 
264
void parport_close(struct pardevice *dev)
265
{
266
        parport_unregister_device(dev);
267
}
268
 
269
/* Send a daisy-chain-style CPP command packet. */
270
static 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. */
318
static 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
 
347
void parport_daisy_deselect_all(struct parport *port)
348
{
349
        cpp_daisy(port, 0x30);
350
}
351
 
352
int 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
 
383
static int mux_present(struct parport *port)
384
{
385
        return cpp_mux(port, 0x51) == 3;
386
}
387
 
388
static int num_mux_ports(struct parport *port)
389
{
390
        return cpp_mux(port, 0x58);
391
}
392
 
393
static int select_port(struct parport *port)
394
{
395
        int muxport = port->muxport;
396
        return cpp_mux(port, 0x60 + muxport) == muxport;
397
}
398
 
399
static 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.