~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to drv_generic_parport.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:24:15 UTC
  • mto: This revision was merged to the branch mainline in revision 750.
  • Revision ID: siretart@tauware.de-20110427172415-6n4aptmvmz0eztvm
Tags: upstream-0.11.0~svn1143
ImportĀ upstreamĀ versionĀ 0.11.0~svn1143

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: drv_generic_parport.c 905 2008-12-23 13:37:07Z michael $
 
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_generic_parport.c $
 
3
 *
 
4
 * generic driver helper for serial and parport access
 
5
 *
 
6
 * Copyright (C) 1999, 2000 Michael Reinelt <michael@reinelt.co.at>
 
7
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 
8
 *
 
9
 * This file is part of LCD4Linux.
 
10
 *
 
11
 * LCD4Linux is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2, or (at your option)
 
14
 * any later version.
 
15
 *
 
16
 * LCD4Linux is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
24
 *
 
25
 */
 
26
 
 
27
#include "config.h"
 
28
 
 
29
#include <stdlib.h>
 
30
#include <stdio.h>
 
31
#include <string.h>
 
32
#include <errno.h>
 
33
#include <unistd.h>
 
34
#include <termios.h>
 
35
#include <fcntl.h>
 
36
#include <time.h>
 
37
#include <signal.h>
 
38
#include <sys/types.h>
 
39
#include <sys/stat.h>
 
40
#include <sys/ioctl.h>
 
41
 
 
42
#ifdef HAVE_SYS_IO_H
 
43
#include <sys/io.h>
 
44
#define WITH_OUTB
 
45
#else
 
46
#ifdef HAVE_ASM_IO_H
 
47
#include <asm/io.h>
 
48
#define WITH_OUTB
 
49
#endif
 
50
#endif
 
51
 
 
52
#if defined (HAVE_LINUX_PARPORT_H) && defined (HAVE_LINUX_PPDEV_H)
 
53
#define WITH_PPDEV
 
54
#include <linux/parport.h>
 
55
#include <linux/ppdev.h>
 
56
#else
 
57
#define PARPORT_CONTROL_STROBE    0x1
 
58
#define PARPORT_CONTROL_AUTOFD    0x2
 
59
#define PARPORT_CONTROL_INIT      0x4
 
60
#define PARPORT_CONTROL_SELECT    0x8
 
61
#define PARPORT_STATUS_ERROR      0x8
 
62
#define PARPORT_STATUS_SELECT     0x10
 
63
#define PARPORT_STATUS_PAPEROUT   0x20
 
64
#define PARPORT_STATUS_ACK        0x40
 
65
#define PARPORT_STATUS_BUSY       0x80
 
66
#endif
 
67
 
 
68
/* these signals are inverted by hardware on the parallel port */
 
69
#define PARPORT_CONTROL_INVERTED (PARPORT_CONTROL_STROBE | PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD)
 
70
 
 
71
#if !defined(WITH_OUTB) && !defined(WITH_PPDEV)
 
72
#error neither outb() nor ppdev() possible
 
73
#error cannot compile parallel port driver
 
74
#endif
 
75
 
 
76
#include "debug.h"
 
77
#include "qprintf.h"
 
78
#include "cfg.h"
 
79
#include "udelay.h"
 
80
#include "drv_generic_parport.h"
 
81
 
 
82
 
 
83
static char *Driver = "";
 
84
static char *Section = "";
 
85
static unsigned short Port = 0;
 
86
static char *PPdev = NULL;
 
87
 
 
88
/* Any bits set here will have their logic inverted at the parallel port */
 
89
static unsigned char inverted_control_bits = 0;
 
90
 
 
91
/* initial value taken from linux/parport_pc.c */
 
92
static unsigned char ctr = 0xc;
 
93
 
 
94
#ifdef WITH_PPDEV
 
95
static int PPfd = -1;
 
96
#endif
 
97
 
 
98
 
 
99
int drv_generic_parport_open(const char *section, const char *driver)
 
100
{
 
101
    char *s, *e;
 
102
 
 
103
    Section = (char *) section;
 
104
    Driver = (char *) driver;
 
105
 
 
106
    udelay_init();
 
107
 
 
108
#ifndef WITH_PPDEV
 
109
    error("The files include/linux/parport.h and/or include/linux/ppdev.h");
 
110
    error("were missing at compile time. Even if your system supports");
 
111
    error("ppdev, it will not be used.");
 
112
    error("You *really* should install these files and recompile LCD4linux!");
 
113
#endif
 
114
 
 
115
    s = cfg_get(Section, "Port", NULL);
 
116
    if (s == NULL || *s == '\0') {
 
117
        error("%s: no '%s.Port' entry from %s", Driver, Section, cfg_source());
 
118
        return -1;
 
119
    }
 
120
 
 
121
    PPdev = NULL;
 
122
    if ((Port = strtol(s, &e, 0)) == 0 || *e != '\0') {
 
123
#ifdef WITH_PPDEV
 
124
        Port = 0;
 
125
        PPdev = s;
 
126
#else
 
127
        error("%s: bad %s.Port '%s' from %s", Driver, Section, s, cfg_source());
 
128
        free(s);
 
129
        return -1;
 
130
#endif
 
131
    }
 
132
#ifdef WITH_PPDEV
 
133
 
 
134
    if (PPdev) {
 
135
        info("%s: using ppdev %s", Driver, PPdev);
 
136
        PPfd = open(PPdev, O_RDWR);
 
137
        if (PPfd == -1) {
 
138
            error("%s: open(%s) failed: %s", Driver, PPdev, strerror(errno));
 
139
            return -1;
 
140
        }
 
141
#if 0
 
142
        /* PPEXCL fails if someone else uses the port (e.g. lp.ko) */
 
143
        if (ioctl(PPfd, PPEXCL)) {
 
144
            info("%s: ioctl(%s, PPEXCL) failed: %s", PPdev, Driver, strerror(errno));
 
145
            info("%s: could not get exclusive access to %s.", Driver, PPdev);
 
146
        } else {
 
147
            info("%s: got exclusive access to %s.", Driver, PPdev);
 
148
        }
 
149
#endif
 
150
 
 
151
        if (ioctl(PPfd, PPCLAIM)) {
 
152
            error("%s: ioctl(%s, PPCLAIM) failed: %d %s", Driver, PPdev, errno, strerror(errno));
 
153
            return -1;
 
154
        }
 
155
    } else
 
156
#endif
 
157
 
 
158
    {
 
159
        error("using raw port 0x%x (deprecated!)", Port);
 
160
        error("You *really* should change your setup and use ppdev!");
 
161
        if ((Port + 3) <= 0x3ff) {
 
162
            if (ioperm(Port, 3, 1) != 0) {
 
163
                error("%s: ioperm(0x%x) failed: %s", Driver, Port, strerror(errno));
 
164
                return -1;
 
165
            }
 
166
        } else {
 
167
            if (iopl(3) != 0) {
 
168
                error("%s: iopl(1) failed: %s", Driver, strerror(errno));
 
169
                return -1;
 
170
            }
 
171
        }
 
172
    }
 
173
    return 0;
 
174
}
 
175
 
 
176
 
 
177
int drv_generic_parport_close(void)
 
178
{
 
179
#ifdef WITH_PPDEV
 
180
    if (PPdev) {
 
181
        debug("closing ppdev %s", PPdev);
 
182
        if (ioctl(PPfd, PPRELEASE)) {
 
183
            error("%s: ioctl(%s, PPRELEASE) failed: %s", Driver, PPdev, strerror(errno));
 
184
        }
 
185
        if (close(PPfd) == -1) {
 
186
            error("%s: close(%s) failed: %s", Driver, PPdev, strerror(errno));
 
187
            return -1;
 
188
        }
 
189
        free(PPdev);
 
190
    } else
 
191
#endif
 
192
    {
 
193
        debug("closing raw port 0x%x", Port);
 
194
        if ((Port + 3) <= 0x3ff) {
 
195
            if (ioperm(Port, 3, 0) != 0) {
 
196
                error("%s: ioperm(0x%x) failed: %s", Driver, Port, strerror(errno));
 
197
                return -1;
 
198
            }
 
199
        } else {
 
200
            if (iopl(0) != 0) {
 
201
                error("%s: iopl(0) failed: %s", Driver, strerror(errno));
 
202
                return -1;
 
203
            }
 
204
        }
 
205
    }
 
206
 
 
207
    return 0;
 
208
}
 
209
 
 
210
 
 
211
static unsigned char drv_generic_parport_signal_ctrl(const char *name, const char *signal)
 
212
{
 
213
    unsigned char wire;
 
214
    int invert = 0;
 
215
 
 
216
    /* Prefixing a signal name with '-' inverts the logic */
 
217
    if (signal[0] == '-') {
 
218
        invert = 1;
 
219
        signal++;
 
220
    }
 
221
 
 
222
    if (strcasecmp(signal, "STROBE") == 0) {
 
223
        wire = PARPORT_CONTROL_STROBE;
 
224
        info("%s: wiring: DISPLAY:%-9s - PARPORT:STROBE (Pin  1)%s", Driver, name, invert ? " [inverted]" : "");
 
225
    } else if (strcasecmp(signal, "AUTOFD") == 0) {
 
226
        wire = PARPORT_CONTROL_AUTOFD;
 
227
        info("%s: wiring: DISPLAY:%-9s - PARPORT:AUTOFD (Pin 14)%s", Driver, name, invert ? " [inverted]" : "");
 
228
    } else if (strcasecmp(signal, "INIT") == 0) {
 
229
        wire = PARPORT_CONTROL_INIT;
 
230
        info("%s: wiring: DISPLAY:%-9s - PARPORT:INIT   (Pin 16)%s", Driver, name, invert ? " [inverted]" : "");
 
231
    } else if (strcasecmp(signal, "SLCTIN") == 0) {
 
232
        wire = PARPORT_CONTROL_SELECT;
 
233
        info("%s: wiring: DISPLAY:%-9s - PARPORT:SLCTIN (Pin 17)%s", Driver, name, invert ? " [inverted]" : "");
 
234
    } else if (strcasecmp(signal, "SELECT") == 0) {
 
235
        wire = PARPORT_CONTROL_SELECT;
 
236
        error("%s: SELECT is deprecated. Please use SLCTIN instead!", Driver);
 
237
        info("%s: wiring: DISPLAY:%-9s - PARPORT:SLCTIN (Pin 17)%s", Driver, name, invert ? " [inverted]" : "");
 
238
    } else if (strcasecmp(signal, "GND") == 0) {
 
239
        wire = 0;
 
240
        info("%s: wiring: DISPLAY:%-9s - PARPORT:GND", Driver, name);
 
241
    } else {
 
242
        error("%s: unknown signal <%s> for control line <%s>", Driver, signal, name);
 
243
        error("%s: should be STROBE, AUTOFD, INIT, SLCTIN or GND", Driver);
 
244
        return 0xff;
 
245
    }
 
246
 
 
247
    if (invert) {
 
248
        inverted_control_bits |= wire;
 
249
    }
 
250
 
 
251
    return wire;
 
252
}
 
253
 
 
254
 
 
255
unsigned char drv_generic_parport_wire_ctrl(const char *name, const char *deflt)
 
256
{
 
257
    unsigned char wire;
 
258
    char key[256];
 
259
    char *val;
 
260
 
 
261
    qprintf(key, sizeof(key), "Wire.%s", name);
 
262
    val = cfg_get(Section, key, deflt);
 
263
 
 
264
    wire = drv_generic_parport_signal_ctrl(name, val);
 
265
 
 
266
    free(val);
 
267
 
 
268
    return wire;
 
269
}
 
270
 
 
271
 
 
272
unsigned char drv_generic_parport_hardwire_ctrl(const char *name, const char *signal)
 
273
{
 
274
    unsigned char wire;
 
275
    char key[256];
 
276
    char *val;
 
277
 
 
278
    qprintf(key, sizeof(key), "Wire.%s", name);
 
279
    val = cfg_get(Section, key, "");
 
280
 
 
281
    /* maybe warn the user */
 
282
    if (*val != '\0' && strcasecmp(signal, val) != 0) {
 
283
        error("%s: ignoring configured signal <%s> for control line <%s>", Driver, val, name);
 
284
    }
 
285
    free(val);
 
286
 
 
287
    wire = drv_generic_parport_signal_ctrl(name, signal);
 
288
 
 
289
    return wire;
 
290
}
 
291
 
 
292
 
 
293
static unsigned char drv_generic_parport_signal_status(const char *name, const char *signal)
 
294
{
 
295
    unsigned char wire;
 
296
 
 
297
    if (strcasecmp(signal, "ERROR") == 0) {
 
298
        wire = PARPORT_STATUS_ERROR;
 
299
        info("%s: wiring: DISPLAY:%-9s - PARPORT:ERROR    (Pin 15)", Driver, name);
 
300
    } else if (strcasecmp(signal, "SELECT") == 0) {
 
301
        wire = PARPORT_STATUS_SELECT;
 
302
        info("%s: wiring: DISPLAY:%-9s - PARPORT:SELECT   (Pin 13)", Driver, name);
 
303
    } else if (strcasecmp(signal, "PAPEROUT") == 0) {
 
304
        wire = PARPORT_STATUS_PAPEROUT;
 
305
        info("%s: wiring: DISPLAY:%-9s - PARPORT:PAPEROUT (Pin 12)", Driver, name);
 
306
    } else if (strcasecmp(signal, "ACK") == 0) {
 
307
        wire = PARPORT_STATUS_ACK;
 
308
        info("%s: wiring: DISPLAY:%-9s - PARPORT:ACK      (Pin 10)", Driver, name);
 
309
    } else if (strcasecmp(signal, "BUSY") == 0) {
 
310
        wire = PARPORT_STATUS_BUSY;
 
311
        info("%s: wiring: DISPLAY:%-9s - PARPORT:BUSY     (Pin 11)", Driver, name);
 
312
    } else if (strcasecmp(signal, "GND") == 0) {
 
313
        wire = 0;
 
314
        info("%s: wiring: DISPLAY:%-9s - PARPORT:GND", Driver, name);
 
315
    } else {
 
316
        error("%s: unknown signal <%s> for status line <%s>", Driver, signal, name);
 
317
        error("%s: should be ERROR, SELECT, PAPEROUT, ACK, BUSY or GND", Driver);
 
318
        return 0xff;
 
319
    }
 
320
 
 
321
    return wire;
 
322
}
 
323
 
 
324
 
 
325
unsigned char drv_generic_parport_wire_status(const char *name, const char *deflt)
 
326
{
 
327
    unsigned char wire;
 
328
    char key[256];
 
329
    char *val;
 
330
 
 
331
    qprintf(key, sizeof(key), "Wire.%s", name);
 
332
    val = cfg_get(Section, key, deflt);
 
333
 
 
334
    wire = drv_generic_parport_signal_status(name, val);
 
335
 
 
336
    free(val);
 
337
 
 
338
    return wire;
 
339
}
 
340
 
 
341
 
 
342
unsigned char drv_generic_parport_wire_data(const char *name, const char *deflt)
 
343
{
 
344
    unsigned char w;
 
345
    char wire[256];
 
346
    char *s;
 
347
 
 
348
    qprintf(wire, sizeof(wire), "Wire.%s", name);
 
349
    s = cfg_get(Section, wire, deflt);
 
350
    if (strlen(s) == 3 && strncasecmp(s, "DB", 2) == 0 && s[2] >= '0' && s[2] <= '7') {
 
351
        w = s[2] - '0';
 
352
    } else if (strcasecmp(s, "GND") == 0) {
 
353
        w = 0;
 
354
    } else {
 
355
        error("%s: unknown signal <%s> for data line <%s>", Driver, s, name);
 
356
        error("%s: should be DB0..7 or GND", Driver);
 
357
        return 0xff;
 
358
    }
 
359
    free(s);
 
360
    if (w == 0) {
 
361
        info("%s: wiring: DISPLAY:%-9s - PARPORT:GND", Driver, name);
 
362
    } else {
 
363
        info("%s: wiring: DISPLAY:%-9s - PARPORT:DB%d (Pin %2d)", Driver, name, w, w + 2);
 
364
    }
 
365
 
 
366
    w = 1 << w;
 
367
 
 
368
    return w;
 
369
}
 
370
 
 
371
 
 
372
void drv_generic_parport_direction(const int direction)
 
373
{
 
374
#ifdef WITH_PPDEV
 
375
    if (PPdev) {
 
376
        ioctl(PPfd, PPDATADIR, &direction);
 
377
    } else
 
378
#endif
 
379
    {
 
380
        /* code stolen from linux/parport_pc.h */
 
381
        ctr = (ctr & ~0x20) ^ (direction ? 0x20 : 0x00);
 
382
        outb(ctr, Port + 2);
 
383
    }
 
384
}
 
385
 
 
386
 
 
387
unsigned char drv_generic_parport_status(void)
 
388
{
 
389
    unsigned char mask =
 
390
        PARPORT_STATUS_ERROR | PARPORT_STATUS_SELECT | PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_ACK |
 
391
        PARPORT_STATUS_BUSY;
 
392
 
 
393
    unsigned char data;
 
394
 
 
395
#ifdef WITH_PPDEV
 
396
    if (PPdev) {
 
397
        ioctl(PPfd, PPRSTATUS, &data);
 
398
    } else
 
399
#endif
 
400
    {
 
401
        data = inb(Port + 1);
 
402
    }
 
403
 
 
404
    /* clear unused bits */
 
405
    data &= mask;
 
406
 
 
407
    return data;
 
408
}
 
409
 
 
410
 
 
411
void drv_generic_parport_control(const unsigned char mask, const unsigned char value)
 
412
{
 
413
    unsigned char val;
 
414
 
 
415
    /* any signal affected? */
 
416
    /* Note: this may happen in case a signal is hardwired to GND */
 
417
    if (mask == 0)
 
418
        return;
 
419
 
 
420
    /* Strobe, Select and AutoFeed are inverted! */
 
421
    val = mask & (value ^ PARPORT_CONTROL_INVERTED ^ inverted_control_bits);
 
422
 
 
423
#ifdef WITH_PPDEV
 
424
    if (PPdev) {
 
425
        struct ppdev_frob_struct frob;
 
426
        frob.mask = mask;
 
427
        frob.val = val;
 
428
        ioctl(PPfd, PPFCONTROL, &frob);
 
429
    } else
 
430
#endif
 
431
    {
 
432
        /* code stolen from linux/parport_pc.h */
 
433
        ctr = (ctr & ~mask) ^ val;
 
434
        outb(ctr, Port + 2);
 
435
    }
 
436
}
 
437
 
 
438
 
 
439
void drv_generic_parport_toggle(const unsigned char bits, const int level, const unsigned long delay)
 
440
{
 
441
    unsigned char value1, value2;
 
442
 
 
443
    /* any signal affected? */
 
444
    /* Note: this may happen in case a signal is hardwired to GND */
 
445
    if (bits == 0)
 
446
        return;
 
447
 
 
448
    /* prepare value */
 
449
    value1 = level ? bits : 0;
 
450
    value2 = level ? 0 : bits;
 
451
 
 
452
    /* Strobe, Select and AutoFeed are inverted! */
 
453
    value1 = bits & (value1 ^ PARPORT_CONTROL_INVERTED ^ inverted_control_bits);
 
454
    value2 = bits & (value2 ^ PARPORT_CONTROL_INVERTED ^ inverted_control_bits);
 
455
 
 
456
#ifdef WITH_PPDEV
 
457
    if (PPdev) {
 
458
        struct ppdev_frob_struct frob;
 
459
        frob.mask = bits;
 
460
 
 
461
        /* rise */
 
462
        frob.val = value1;
 
463
        ioctl(PPfd, PPFCONTROL, &frob);
 
464
 
 
465
        /* pulse width */
 
466
        ndelay(delay);
 
467
 
 
468
        /* lower */
 
469
        frob.val = value2;
 
470
        ioctl(PPfd, PPFCONTROL, &frob);
 
471
 
 
472
    } else
 
473
#endif
 
474
    {
 
475
        /* rise */
 
476
        ctr = (ctr & ~bits) ^ value1;
 
477
        outb(ctr, Port + 2);
 
478
 
 
479
        /* pulse width */
 
480
        ndelay(delay);
 
481
 
 
482
        /* lower */
 
483
        ctr = (ctr & ~bits) ^ value2;
 
484
        outb(ctr, Port + 2);
 
485
    }
 
486
}
 
487
 
 
488
 
 
489
void drv_generic_parport_data(const unsigned char data)
 
490
{
 
491
#ifdef WITH_PPDEV
 
492
    if (PPdev) {
 
493
        ioctl(PPfd, PPWDATA, &data);
 
494
    } else
 
495
#endif
 
496
    {
 
497
        outb(data, Port);
 
498
    }
 
499
}
 
500
 
 
501
unsigned char drv_generic_parport_read(void)
 
502
{
 
503
    unsigned char data;
 
504
 
 
505
#ifdef WITH_PPDEV
 
506
    if (PPdev) {
 
507
        ioctl(PPfd, PPRDATA, &data);
 
508
    } else
 
509
#endif
 
510
    {
 
511
        data = inb(Port);
 
512
    }
 
513
    return data;
 
514
}
 
515
 
 
516
 
 
517
void drv_generic_parport_debug(void)
 
518
{
 
519
    unsigned char control;
 
520
 
 
521
#ifdef WITH_PPDEV
 
522
    if (PPdev) {
 
523
        ioctl(PPfd, PPRCONTROL, &control);
 
524
    } else
 
525
#endif
 
526
    {
 
527
        control = ctr;
 
528
    }
 
529
 
 
530
    debug("%cSTROBE %cAUTOFD %cINIT %cSLCTIN",
 
531
          control & PARPORT_CONTROL_STROBE ? '-' : '+',
 
532
          control & PARPORT_CONTROL_AUTOFD ? '-' : '+', control & PARPORT_CONTROL_INIT ? '+' : '-',
 
533
          control & PARPORT_CONTROL_SELECT ? '-' : '+');
 
534
 
 
535
}