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