diff options
author | bubnikv <bubnikv@gmail.com> | 2018-09-19 12:02:24 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2018-09-19 12:02:24 +0300 |
commit | 0558b53493a77bae44831cf87bb0f59359828ef5 (patch) | |
tree | c3e8dbdf7d91a051c12d9ebbf7606d41047fea96 /src/avrdude/ppiwin.c | |
parent | 3ddaccb6410478ad02d8c0e02d6d8e6eb1785b9f (diff) |
WIP: Moved sources int src/, separated most of the source code from Perl.
The XS was left only for the unit / integration tests, and it links
libslic3r only. No wxWidgets are allowed to be used from Perl starting
from now.
Diffstat (limited to 'src/avrdude/ppiwin.c')
-rw-r--r-- | src/avrdude/ppiwin.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/src/avrdude/ppiwin.c b/src/avrdude/ppiwin.c new file mode 100644 index 000000000..7811288c0 --- /dev/null +++ b/src/avrdude/ppiwin.c @@ -0,0 +1,417 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2003, 2004, 2006 + * Eric B. Weddington <eweddington@cso.atmel.com> + * Copyright 2008, Joerg Wunsch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* $Id$ */ + +/* +This is the parallel port interface for Windows built using Cygwin. + +In the ppi_* functions that access the parallel port registers, +fd = parallel port address +reg = register as defined in an enum in ppi.h. This must be converted + to a proper offset of the base address. +*/ + + +#include "ac_cfg.h" + +#if defined (WIN32NATIVE) + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <windows.h> +#include <sys/time.h> +#include <windows.h> + +#include "avrdude.h" +#include "libavrdude.h" + +#include "ppi.h" + +#define DEVICE_LPT1 "lpt1" +#define DEVICE_LPT2 "lpt2" +#define DEVICE_LPT3 "lpt3" + +#define DEVICE_MAX 3 + +typedef struct +{ + const char *name; + int base_address; +} winpp; + +static const winpp winports[DEVICE_MAX] = +{ + {DEVICE_LPT1, 0x378}, + {DEVICE_LPT2, 0x278}, + {DEVICE_LPT3, 0x3BC}, +}; + + + + + +/* FUNCTION PROTOTYPES */ +static int winnt_pp_open(void); +static unsigned short port_get(union filedescriptor *fdp, int reg); +static unsigned char reg2offset(int reg); +static unsigned char inb(unsigned short port); +static void outb(unsigned char value, unsigned short port); + + + +/* FUNCTION DEFINITIONS */ + +void ppi_open(char *port, union filedescriptor *fdp) +{ + unsigned char i; + int fd; + + fd = winnt_pp_open(); + + if(fd < 0) + { + avrdude_message(MSG_INFO, "%s: can't open device \"giveio\"\n\n", progname); + fdp->ifd = -1; + return; + } + + /* Search the windows port names for a match */ + fd = -1; + for(i = 0; i < DEVICE_MAX; i++) + { + if(strcmp(winports[i].name, port) == 0) + { + /* Set the file descriptor with the Windows parallel port base address. */ + fd = winports[i].base_address; + break; + } + } + if(fd == -1) + { + /* + * Supplied port name did not match any of the pre-defined + * names. Try interpreting it as a numeric + * (hexadecimal/decimal/octal) address. + */ + char *cp; + + fd = strtol(port, &cp, 0); + if(*port == '\0' || *cp != '\0') + { + avrdude_message(MSG_INFO, "%s: port name \"%s\" is neither lpt1/2/3 nor valid number\n", + progname, port); + fd = -1; + } + } + if(fd < 0) + { + avrdude_message(MSG_INFO, "%s: can't open device \"%s\"\n\n", progname, port); + fdp->ifd = -1; + return; + } + + fdp->ifd = fd; +} + + +#define DRIVERNAME "\\\\.\\giveio" +static int winnt_pp_open(void) +{ + // Only try to use giveio under Windows NT/2000/XP. + OSVERSIONINFO ver_info; + + memset(&ver_info, 0, sizeof(ver_info)); + + ver_info.dwOSVersionInfoSize = sizeof(ver_info); + + if(!GetVersionEx(&ver_info)) + { + return(-1); + } + else if(ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + HANDLE h = CreateFileA(DRIVERNAME, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if(h == INVALID_HANDLE_VALUE) + { + return(-1); + } + + /* Close immediately. The process now has the rights it needs. */ + if(h != NULL) + { + CloseHandle(h); + } + } + return(0); +} + + + + +void ppi_close(union filedescriptor *fdp) +{ + return; +} + + + +/* + * set the indicated bit of the specified register. + */ +int ppi_set(union filedescriptor *fdp, int reg, int bit) +{ + unsigned char v; + unsigned short port; + + port = port_get(fdp, reg); + v = inb(port); + v |= bit; + outb(v, port); + return 0; +} + + +/* + * clear the indicated bit of the specified register. + */ +int ppi_clr(union filedescriptor *fdp, int reg, int bit) +{ + unsigned char v; + unsigned short port; + + port = port_get(fdp, reg); + v = inb(port); + v &= ~bit; + outb(v, port); + + return 0; +} + + +/* + * get the indicated bit of the specified register. + */ +int ppi_get(union filedescriptor *fdp, int reg, int bit) +{ + unsigned char v; + + v = inb(port_get(fdp, reg)); + v &= bit; + + return(v); +} + + + + +/* + * toggle the indicated bit of the specified register. + */ +int ppi_toggle(union filedescriptor *fdp, int reg, int bit) +{ + unsigned char v; + unsigned short port; + + port = port_get(fdp, reg); + + v = inb(port); + v ^= bit; + outb(v, port); + + return 0; +} + + +/* + * get all bits of the specified register. + */ +int ppi_getall(union filedescriptor *fdp, int reg) +{ + unsigned char v; + + v = inb(port_get(fdp, reg)); + + return((int)v); +} + + + + +/* + * set all bits of the specified register to val. + */ +int ppi_setall(union filedescriptor *fdp, int reg, int val) +{ + outb((unsigned char)val, port_get(fdp, reg)); + return 0; +} + + + + +/* Calculate port address to access. */ +static unsigned short port_get(union filedescriptor *fdp, int reg) +{ + return((unsigned short)(fdp->ifd + reg2offset(reg))); +} + + +/* Convert register enum to offset of base address. */ +static unsigned char reg2offset(int reg) +{ + unsigned char offset = 0; + + switch(reg) + { + case PPIDATA: + { + offset = 0; + break; + } + case PPISTATUS: + { + offset = 1; + break; + } + case PPICTRL: + { + offset = 2; + break; + } + } + + return(offset); +} + + +/* Read in value from port. */ +static unsigned char inb(unsigned short port) +{ + unsigned char t; + + asm volatile ("in %1, %0" + : "=a" (t) + : "d" (port)); + + return t; +} + + +/* Write value to port. */ +static void outb(unsigned char value, unsigned short port) +{ + asm volatile ("out %1, %0" + : + : "d" (port), "a" (value) ); + + return; +} + +#if !defined(HAVE_GETTIMEOFDAY) +struct timezone; +int gettimeofday(struct timeval *tv, struct timezone *unused){ +// i've found only ms resolution, avrdude expects us + + SYSTEMTIME st; + GetSystemTime(&st); + + tv->tv_sec=(long)(st.wSecond+st.wMinute*60+st.wHour*3600); + tv->tv_usec=(long)(st.wMilliseconds*1000); + + return 0; +} +#endif /* HAVE_GETTIMEOFDAY */ + +// #define W32USLEEPDBG + +#ifdef W32USLEEPDBG + +# define DEBUG_QueryPerformanceCounter(arg) QueryPerformanceCounter(arg) +# define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf) \ + do { \ + unsigned long dt; \ + dt = (unsigned long)((stop.QuadPart - start.QuadPart) * 1000 * 1000 \ + / freq.QuadPart); \ + avrdude_message(MSG_INFO, \ + "hpt:%i usleep usec:%lu sleep msec:%lu timed usec:%lu\n", \ + has_highperf, us, ((us + 999) / 1000), dt); \ + } while (0) + +#else + +# define DEBUG_QueryPerformanceCounter(arg) +# define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf) + +#endif + +#if !defined(HAVE_USLEEP) +int usleep(unsigned int us) +{ + int has_highperf; + LARGE_INTEGER freq,start,stop,loopend; + + // workaround: although usleep is very precise if using + // high-performance-timers there are sometimes problems with + // verify - increasing the delay helps sometimes but not + // realiably. There must be some other problem. Maybe just + // with my test-hardware maybe in the code-base. + //// us=(unsigned long) (us*1.5); + + has_highperf=QueryPerformanceFrequency(&freq); + + //has_highperf=0; // debug + + if (has_highperf) { + QueryPerformanceCounter(&start); + loopend.QuadPart=start.QuadPart+freq.QuadPart*us/(1000*1000); + do { + QueryPerformanceCounter(&stop); + } while (stop.QuadPart<=loopend.QuadPart); + } + else { + DEBUG_QueryPerformanceCounter(&start); + + Sleep(1); + Sleep( (DWORD)((us+999)/1000) ); + + DEBUG_QueryPerformanceCounter(&stop); + } + + DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf); + + return 0; +} +#endif /* !HAVE_USLEEP */ + +#endif + + |