1 /*
2  * avrdude - A Downloader/Uploader for AVR device programmers
3  * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /* $Id: ppi.c 1321 2014-06-13 20:07:40Z awachtler $ */
20 
21 
22 #if !defined(WIN32NATIVE)
23 
24 #include "ac_cfg.h"
25 
26 #if HAVE_PARPORT
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 
35 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
36 # include "freebsd_ppi.h"
37 #elif defined(__linux__)
38 # include "linux_ppdev.h"
39 #elif defined(__sun__) || defined(__sun) /* Solaris */
40 # include "solaris_ecpp.h"
41 #endif
42 
43 #include "avrdude.h"
44 #include "libavrdude.h"
45 
46 #include "ppi.h"
47 
48 enum {
49   PPI_READ,
50   PPI_WRITE,
51   PPI_SHADOWREAD
52 };
53 
ppi_shadow_access(union filedescriptor * fdp,int reg,unsigned char * v,unsigned char action)54 static int ppi_shadow_access(union filedescriptor *fdp, int reg,
55 			     unsigned char *v, unsigned char action)
56 {
57   static unsigned char shadow[3];
58   int shadow_num;
59 
60   switch (reg) {
61     case PPIDATA:
62       shadow_num = 0;
63       break;
64     case PPICTRL:
65       shadow_num = 1;
66       break;
67     case PPISTATUS:
68       shadow_num = 2;
69       break;
70     default:
71       avrdude_message(MSG_INFO, "%s: avr_set(): invalid register=%d\n",
72               progname, reg);
73       return -1;
74       break;
75   }
76 
77   switch (action) {
78     case PPI_SHADOWREAD:
79       *v = shadow[shadow_num];
80       break;
81     case PPI_READ:
82       DO_PPI_READ(fdp->ifd, reg, v);
83       shadow[shadow_num]=*v;
84       break;
85     case PPI_WRITE:
86       shadow[shadow_num]=*v;
87       DO_PPI_WRITE(fdp->ifd, reg, v);
88       break;
89   }
90   return 0;
91 }
92 
93 /*
94  * set the indicated bit of the specified register.
95  */
ppi_set(union filedescriptor * fdp,int reg,int bit)96 int ppi_set(union filedescriptor *fdp, int reg, int bit)
97 {
98   unsigned char v;
99   int rc;
100 
101   rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
102   v |= bit;
103   rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
104 
105   if (rc)
106     return -1;
107 
108   return 0;
109 }
110 
111 
112 /*
113  * clear the indicated bit of the specified register.
114  */
ppi_clr(union filedescriptor * fdp,int reg,int bit)115 int ppi_clr(union filedescriptor *fdp, int reg, int bit)
116 {
117   unsigned char v;
118   int rc;
119 
120   rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
121   v &= ~bit;
122   rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
123 
124   if (rc)
125     return -1;
126 
127   return 0;
128 }
129 
130 
131 /*
132  * get the indicated bit of the specified register.
133  */
ppi_get(union filedescriptor * fdp,int reg,int bit)134 int ppi_get(union filedescriptor *fdp, int reg, int bit)
135 {
136   unsigned char v;
137   int rc;
138 
139   rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
140   v &= bit;
141 
142   if (rc)
143     return -1;
144 
145   return v; /* v == bit */
146 }
147 
148 /*
149  * toggle the indicated bit of the specified register.
150  */
ppi_toggle(union filedescriptor * fdp,int reg,int bit)151 int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
152 {
153   unsigned char v;
154   int rc;
155 
156   rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
157   v ^= bit;
158   rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
159 
160   if (rc)
161     return -1;
162 
163   return 0;
164 }
165 
166 
167 /*
168  * get all bits of the specified register.
169  */
ppi_getall(union filedescriptor * fdp,int reg)170 int ppi_getall(union filedescriptor *fdp, int reg)
171 {
172   unsigned char v;
173   int rc;
174 
175   rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
176 
177   if (rc)
178     return -1;
179 
180   return v; /* v == bit */
181 }
182 
183 /*
184  * set all bits of the specified register to val.
185  */
ppi_setall(union filedescriptor * fdp,int reg,int val)186 int ppi_setall(union filedescriptor *fdp, int reg, int val)
187 {
188   unsigned char v;
189   int rc;
190 
191   v = val;
192   rc = ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
193 
194   if (rc)
195     return -1;
196 
197   return 0;
198 }
199 
200 
ppi_open(char * port,union filedescriptor * fdp)201 void ppi_open(char * port, union filedescriptor *fdp)
202 {
203   int fd;
204   unsigned char v;
205 
206   fd = open(port, O_RDWR);
207   if (fd < 0) {
208     avrdude_message(MSG_INFO, "%s: can't open device \"%s\": %s\n",
209               progname, port, strerror(errno));
210     fdp->ifd = -1;
211     return;
212   }
213 
214   ppi_claim (fd);
215 
216   /*
217    * Initialize shadow registers
218    */
219 
220   ppi_shadow_access (fdp, PPIDATA, &v, PPI_READ);
221   ppi_shadow_access (fdp, PPICTRL, &v, PPI_READ);
222   ppi_shadow_access (fdp, PPISTATUS, &v, PPI_READ);
223 
224   fdp->ifd = fd;
225 }
226 
227 
ppi_close(union filedescriptor * fdp)228 void ppi_close(union filedescriptor *fdp)
229 {
230   ppi_release (fdp->ifd);
231   close(fdp->ifd);
232 }
233 
234 #endif /* HAVE_PARPORT */
235 
236 #endif /* !WIN32NATIVE */
237