1 /*
2 * avrdude - A Downloader/Uploader for AVR device programmers
3 * Copyright (C) 2003, 2004, 2006
4 * Eric B. Weddington <eweddington@cso.atmel.com>
5 * Copyright 2008, Joerg Wunsch
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /* $Id: ppiwin.c 1321 2014-06-13 20:07:40Z awachtler $ */
22
23 /*
24 This is the parallel port interface for Windows built using Cygwin.
25
26 In the ppi_* functions that access the parallel port registers,
27 fd = parallel port address
28 reg = register as defined in an enum in ppi.h. This must be converted
29 to a proper offset of the base address.
30 */
31
32
33 #include "ac_cfg.h"
34
35 #if defined (WIN32NATIVE)
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <windows.h>
44 #include <sys/time.h>
45 #include <windows.h>
46
47 #include "avrdude.h"
48 #include "libavrdude.h"
49
50 #include "ppi.h"
51
52 #define DEVICE_LPT1 "lpt1"
53 #define DEVICE_LPT2 "lpt2"
54 #define DEVICE_LPT3 "lpt3"
55
56 #define DEVICE_MAX 3
57
58 typedef struct
59 {
60 const char *name;
61 int base_address;
62 } winpp;
63
64 static const winpp winports[DEVICE_MAX] =
65 {
66 {DEVICE_LPT1, 0x378},
67 {DEVICE_LPT2, 0x278},
68 {DEVICE_LPT3, 0x3BC},
69 };
70
71
72
73
74
75 /* FUNCTION PROTOTYPES */
76 static int winnt_pp_open(void);
77 static unsigned short port_get(union filedescriptor *fdp, int reg);
78 static unsigned char reg2offset(int reg);
79 static unsigned char inb(unsigned short port);
80 static void outb(unsigned char value, unsigned short port);
81
82
83
84 /* FUNCTION DEFINITIONS */
85
ppi_open(char * port,union filedescriptor * fdp)86 void ppi_open(char *port, union filedescriptor *fdp)
87 {
88 unsigned char i;
89 int fd;
90
91 fd = winnt_pp_open();
92
93 if(fd < 0)
94 {
95 avrdude_message(MSG_INFO, "%s: can't open device \"giveio\"\n\n", progname);
96 fdp->ifd = -1;
97 return;
98 }
99
100 /* Search the windows port names for a match */
101 fd = -1;
102 for(i = 0; i < DEVICE_MAX; i++)
103 {
104 if(strcmp(winports[i].name, port) == 0)
105 {
106 /* Set the file descriptor with the Windows parallel port base address. */
107 fd = winports[i].base_address;
108 break;
109 }
110 }
111 if(fd == -1)
112 {
113 /*
114 * Supplied port name did not match any of the pre-defined
115 * names. Try interpreting it as a numeric
116 * (hexadecimal/decimal/octal) address.
117 */
118 char *cp;
119
120 fd = strtol(port, &cp, 0);
121 if(*port == '\0' || *cp != '\0')
122 {
123 avrdude_message(MSG_INFO, "%s: port name \"%s\" is neither lpt1/2/3 nor valid number\n",
124 progname, port);
125 fd = -1;
126 }
127 }
128 if(fd < 0)
129 {
130 avrdude_message(MSG_INFO, "%s: can't open device \"%s\"\n\n", progname, port);
131 fdp->ifd = -1;
132 return;
133 }
134
135 fdp->ifd = fd;
136 }
137
138
139 #define DRIVERNAME "\\\\.\\giveio"
winnt_pp_open(void)140 static int winnt_pp_open(void)
141 {
142 // Only try to use giveio under Windows NT/2000/XP.
143 OSVERSIONINFO ver_info;
144
145 memset(&ver_info, 0, sizeof(ver_info));
146
147 ver_info.dwOSVersionInfoSize = sizeof(ver_info);
148
149 if(!GetVersionEx(&ver_info))
150 {
151 return(-1);
152 }
153 else if(ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
154 {
155 HANDLE h = CreateFile(DRIVERNAME,
156 GENERIC_READ,
157 0,
158 NULL,
159 OPEN_EXISTING,
160 FILE_ATTRIBUTE_NORMAL,
161 NULL);
162
163 if(h == INVALID_HANDLE_VALUE)
164 {
165 return(-1);
166 }
167
168 /* Close immediately. The process now has the rights it needs. */
169 if(h != NULL)
170 {
171 CloseHandle(h);
172 }
173 }
174 return(0);
175 }
176
177
178
179
ppi_close(union filedescriptor * fdp)180 void ppi_close(union filedescriptor *fdp)
181 {
182 return;
183 }
184
185
186
187 /*
188 * set the indicated bit of the specified register.
189 */
ppi_set(union filedescriptor * fdp,int reg,int bit)190 int ppi_set(union filedescriptor *fdp, int reg, int bit)
191 {
192 unsigned char v;
193 unsigned short port;
194
195 port = port_get(fdp, reg);
196 v = inb(port);
197 v |= bit;
198 outb(v, port);
199 return 0;
200 }
201
202
203 /*
204 * clear the indicated bit of the specified register.
205 */
ppi_clr(union filedescriptor * fdp,int reg,int bit)206 int ppi_clr(union filedescriptor *fdp, int reg, int bit)
207 {
208 unsigned char v;
209 unsigned short port;
210
211 port = port_get(fdp, reg);
212 v = inb(port);
213 v &= ~bit;
214 outb(v, port);
215
216 return 0;
217 }
218
219
220 /*
221 * get the indicated bit of the specified register.
222 */
ppi_get(union filedescriptor * fdp,int reg,int bit)223 int ppi_get(union filedescriptor *fdp, int reg, int bit)
224 {
225 unsigned char v;
226
227 v = inb(port_get(fdp, reg));
228 v &= bit;
229
230 return(v);
231 }
232
233
234
235
236 /*
237 * toggle the indicated bit of the specified register.
238 */
ppi_toggle(union filedescriptor * fdp,int reg,int bit)239 int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
240 {
241 unsigned char v;
242 unsigned short port;
243
244 port = port_get(fdp, reg);
245
246 v = inb(port);
247 v ^= bit;
248 outb(v, port);
249
250 return 0;
251 }
252
253
254 /*
255 * get all bits of the specified register.
256 */
ppi_getall(union filedescriptor * fdp,int reg)257 int ppi_getall(union filedescriptor *fdp, int reg)
258 {
259 unsigned char v;
260
261 v = inb(port_get(fdp, reg));
262
263 return((int)v);
264 }
265
266
267
268
269 /*
270 * set all bits of the specified register to val.
271 */
ppi_setall(union filedescriptor * fdp,int reg,int val)272 int ppi_setall(union filedescriptor *fdp, int reg, int val)
273 {
274 outb((unsigned char)val, port_get(fdp, reg));
275 return 0;
276 }
277
278
279
280
281 /* Calculate port address to access. */
port_get(union filedescriptor * fdp,int reg)282 static unsigned short port_get(union filedescriptor *fdp, int reg)
283 {
284 return((unsigned short)(fdp->ifd + reg2offset(reg)));
285 }
286
287
288 /* Convert register enum to offset of base address. */
reg2offset(int reg)289 static unsigned char reg2offset(int reg)
290 {
291 unsigned char offset = 0;
292
293 switch(reg)
294 {
295 case PPIDATA:
296 {
297 offset = 0;
298 break;
299 }
300 case PPISTATUS:
301 {
302 offset = 1;
303 break;
304 }
305 case PPICTRL:
306 {
307 offset = 2;
308 break;
309 }
310 }
311
312 return(offset);
313 }
314
315
316 /* Read in value from port. */
inb(unsigned short port)317 static unsigned char inb(unsigned short port)
318 {
319 unsigned char t;
320
321 asm volatile ("in %1, %0"
322 : "=a" (t)
323 : "d" (port));
324
325 return t;
326 }
327
328
329 /* Write value to port. */
outb(unsigned char value,unsigned short port)330 static void outb(unsigned char value, unsigned short port)
331 {
332 asm volatile ("out %1, %0"
333 :
334 : "d" (port), "a" (value) );
335
336 return;
337 }
338
339 #if !defined(HAVE_GETTIMEOFDAY)
340 struct timezone;
gettimeofday(struct timeval * tv,struct timezone * unused)341 int gettimeofday(struct timeval *tv, struct timezone *unused){
342 // i've found only ms resolution, avrdude expects us
343
344 SYSTEMTIME st;
345 GetSystemTime(&st);
346
347 tv->tv_sec=(long)(st.wSecond+st.wMinute*60+st.wHour*3600);
348 tv->tv_usec=(long)(st.wMilliseconds*1000);
349
350 return 0;
351 }
352 #endif /* HAVE_GETTIMEOFDAY */
353
354 // #define W32USLEEPDBG
355
356 #ifdef W32USLEEPDBG
357
358 # define DEBUG_QueryPerformanceCounter(arg) QueryPerformanceCounter(arg)
359 # define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf) \
360 do { \
361 unsigned long dt; \
362 dt = (unsigned long)((stop.QuadPart - start.QuadPart) * 1000 * 1000 \
363 / freq.QuadPart); \
364 avrdude_message(MSG_INFO, \
365 "hpt:%i usleep usec:%lu sleep msec:%lu timed usec:%lu\n", \
366 has_highperf, us, ((us + 999) / 1000), dt); \
367 } while (0)
368
369 #else
370
371 # define DEBUG_QueryPerformanceCounter(arg)
372 # define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf)
373
374 #endif
375
376 #if !defined(HAVE_USLEEP)
usleep(unsigned int us)377 int usleep(unsigned int us)
378 {
379 int has_highperf;
380 LARGE_INTEGER freq,start,stop,loopend;
381
382 // workaround: although usleep is very precise if using
383 // high-performance-timers there are sometimes problems with
384 // verify - increasing the delay helps sometimes but not
385 // realiably. There must be some other problem. Maybe just
386 // with my test-hardware maybe in the code-base.
387 //// us=(unsigned long) (us*1.5);
388
389 has_highperf=QueryPerformanceFrequency(&freq);
390
391 //has_highperf=0; // debug
392
393 if (has_highperf) {
394 QueryPerformanceCounter(&start);
395 loopend.QuadPart=start.QuadPart+freq.QuadPart*us/(1000*1000);
396 do {
397 QueryPerformanceCounter(&stop);
398 } while (stop.QuadPart<=loopend.QuadPart);
399 }
400 else {
401 DEBUG_QueryPerformanceCounter(&start);
402
403 Sleep(1);
404 Sleep( (DWORD)((us+999)/1000) );
405
406 DEBUG_QueryPerformanceCounter(&stop);
407 }
408
409 DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf);
410
411 return 0;
412 }
413 #endif /* !HAVE_USLEEP */
414
415 #endif
416
417
418