root/tags/0.10.0/drv_generic_parport.c

Revision 547, 14.6 kB (checked in by reinelt, 4 years ago)

[lcd4linux @ 2005-05-08 04:32:43 by reinelt]
CodingStyle? added and applied

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