123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101 |
- /*
- *
- * cd64io.c
- *
- * I/O routines for CD64 device
- *
- * (c) 2004 Ryan Underwood
- * Portions (c) 2004, 2005, 2015 Daniel Horchner (OpenBSD, FreeBSD, BeOS, Win32, DOS)
- *
- * May be distributed under the terms of the GNU Lesser/Library General Public
- * License, or any later version of the same, as published by the Free Software
- * Foundation.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <stdarg.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/types.h>
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable: 4820) /* 'bytes' bytes padding added after construct 'member_name' */
- #endif
- #include <sys/stat.h>
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #if defined __unix__ || defined __BEOS__ /* ioctl() */
- #include <unistd.h>
- #endif
- #include <ultra64/host/cd64lib.h>
- #include "cd64io.h"
- #define DEBUG_LOWLEVEL 0
- #define BUSY_THRESHOLD 10000
- #define MAX_TRIES 5
- #ifdef CD64_USE_RAWIO
- #if defined _WIN32 || defined __CYGWIN__
- #ifdef __CYGWIN__
- #define DIR_SEPARATOR_S "/"
- #else
- #define snprintf _snprintf
- #define DIR_SEPARATOR_S "\\"
- #endif
- /* The next union is a portable means to convert between function and data
- * pointers and the only way to silence Visual C++ 2012 other than
- * #pragma warning(disable: 4152)
- * That is, with /W4. */
- typedef union u_func_ptr {
- void (*func_ptr)(void);
- void *void_ptr;
- } u_func_ptr_t;
- static void *io_driver = NULL;
- static int io_driver_found = 0;
- /* inpout32.dll */
- static short (__stdcall *Inp32)(short) = NULL;
- static void (__stdcall *Outp32)(short, short) = NULL;
- /* io.dll */
- static char (WINAPI *PortIn)(short int) = NULL;
- static void (WINAPI *PortOut)(short int, char) = NULL;
- static short int (WINAPI *IsDriverInstalled)(void) = NULL;
- /* DlPortIO.dll */
- static unsigned char (__stdcall *DlPortReadPortUchar)(unsigned short) = NULL;
- static void (__stdcall *DlPortWritePortUchar)(unsigned short, unsigned char) = NULL;
- static INLINE uint8_t inb(uint16_t);
- static INLINE void outb(uint8_t, uint16_t);
- static uint8_t (*input_byte)(uint16_t) = inb;
- static void (*output_byte)(uint8_t, uint16_t) = outb;
- #endif
- #ifdef __BEOS__
- static int io_portfd;
- typedef struct st_ioport {
- unsigned int port;
- unsigned char data8;
- unsigned short data16;
- } st_ioport_t;
- #endif
- #endif /* CD64_USE_RAWIO */
- int cd64_send_byte(struct cd64_t *cd64, uint8_t what) {
- return cd64->xfer(cd64, &what, NULL, 0);
- }
- int cd64_send_dword(struct cd64_t *cd64, uint32_t what) {
- int ret = 1;
- ret &= cd64_send_byte(cd64, (uint8_t) (what>>24));
- ret &= cd64_send_byte(cd64, (uint8_t) (what>>16));
- ret &= cd64_send_byte(cd64, (uint8_t) (what>>8));
- ret &= cd64_send_byte(cd64, (uint8_t) what);
- return ret;
- }
- int cd64_grab_byte(struct cd64_t *cd64, uint8_t *val) {
- return cd64->xfer(cd64, NULL, val, 0);
- }
- int cd64_grab_dword(struct cd64_t *cd64, uint32_t *val) {
- int ret = 1;
- uint8_t grab;
- if (val == NULL) return 0;
- *val = 0;
- ret &= cd64_grab_byte(cd64, &grab);
- *val |= grab << 24;
- ret &= cd64_grab_byte(cd64, &grab);
- *val |= grab << 16;
- ret &= cd64_grab_byte(cd64, &grab);
- *val |= grab << 8;
- ret &= cd64_grab_byte(cd64, &grab);
- *val |= grab;
- return ret;
- }
- int cd64_trade_bytes(struct cd64_t *cd64, uint8_t give, uint8_t *recv) {
- return cd64->xfer(cd64, &give, recv, 0);
- }
- /* Backend-specific defs go down here. */
- #ifdef CD64_USE_LIBIEEE1284
- int cd64_open_ieee1284(struct cd64_t *cd64) {
- struct parport_list pplist;
- int ppflags = F1284_EXCL;
- int ppcaps = 0;
- int i;
- int opened = 0;
- if (cd64->ppdev || !cd64->using_ppa) return 0;
- if (ieee1284_find_ports(&pplist, 0) < 0) {
- cd64->notice_callback2("could not get port list\n");
- return 0;
- }
- if (cd64->port < pplist.portc) {
- /* Just use it as an index. */
- cd64->ppdev = pplist.portv[cd64->port];
- }
- else {
- /* Search for the ppdev matching its base address. */
- for (i = 0; i < pplist.portc; i++) {
- if (cd64->port == (int) pplist.portv[i]->base_addr) {
- cd64->ppdev = pplist.portv[i];
- }
- }
- }
- if (cd64->ppdev) {
- if (ieee1284_open(cd64->ppdev, ppflags, &ppcaps) < 0) {
- cd64->notice_callback2("failed opening ieee1284 port %d\n", cd64->port);
- cd64->ppdev = NULL;
- }
- else {
- opened = 1;
- }
- }
- ieee1284_free_ports(&pplist);
- if (opened && ieee1284_claim(cd64->ppdev) < 0) return 0;
- else return opened;
- }
- int cd64_close_ieee1284(struct cd64_t *cd64) {
- int ret;
- if (cd64->ppdev == NULL) return 1;
- ieee1284_release(cd64->ppdev);
- ret = ieee1284_close(cd64->ppdev);
- if (ret < 0) ret = 0;
- else {
- cd64->ppdev = NULL;
- ret = 1;
- }
- return ret;
- }
- static INLINE int cd64_wait_ieee(struct cd64_t *cd64) {
- /* With ppdev, could we use an interrupt instead? The PPA
- * could be modified... */
- int i = 0;
- int reset_tries = 0;
- while (i < 10000) i++; /* FIXME is this necessary? */
- i = 0;
- while((ieee1284_read_status(cd64->ppdev)^S1284_INVERTED) & S1284_BUSY) {
- i++;
- if (i >= BUSY_THRESHOLD) {
- /* The PPA is in a weird state.
- * Try to knock some sense into it. */
- ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NAUTOFD)^C1284_INVERTED);
- ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
- ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NSTROBE)^C1284_INVERTED);
- ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
- reset_tries++;
- i = 0;
- MSLEEP(1);
- }
- if (reset_tries > MAX_TRIES) break;
- if (cd64->abort) return 0;
- }
- return (reset_tries < MAX_TRIES);
- }
- int cd64_xfer_ieee1284(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
- if (!cd64_wait_ieee(cd64)) { return 0; }
- if (delayms) MSLEEP(delayms);
- ieee1284_data_dir(cd64->ppdev, 1);
- if (delayms) MSLEEP(delayms);
- ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NAUTOFD)^C1284_INVERTED);
- if (delayms) MSLEEP(delayms);
- if (rd) {
- *rd = ieee1284_read_data(cd64->ppdev);
- #if DEBUG_LOWLEVEL
- printf("got %xh", *rd);
- if (*rd > 0x20) printf(" (%c)", *rd);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- ieee1284_data_dir(cd64->ppdev, 0);
- if (delayms) MSLEEP(delayms);
- ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
- if (delayms) MSLEEP(delayms);
- if (wr) {
- ieee1284_write_data(cd64->ppdev, *wr);
- #if DEBUG_LOWLEVEL
- printf("put %xh", *wr);
- if (*wr > 0x20) printf(" (%c)", *wr);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NSTROBE)^C1284_INVERTED);
- if (delayms) MSLEEP(delayms);
- ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
- return 1;
- }
- #endif /* CD64_USE_LIBIEEE1284 */
- #ifdef CD64_USE_PPDEV
- int cd64_open_ppdev(struct cd64_t *cd64) {
- char *device = "/dev/parport%d";
- char realdev[128+1];
- if (cd64->ppdevfd || !cd64->using_ppa) return 0;
- /* This should be a port number only, not an address */
- if (cd64->port > PARPORT_MAX) return 0;
- snprintf(realdev, 128+1, device, cd64->port);
- realdev[128] = 0;
- if ((cd64->ppdevfd = open(realdev, O_RDWR)) == -1) {
- cd64->notice_callback2("open: %s", strerror(errno));
- cd64->ppdevfd = 0;
- return 0;
- }
- if (ioctl(cd64->ppdevfd, PPEXCL) != 0) {
- cd64->notice_callback2("PPEXCL: %s", strerror(errno));
- close(cd64->ppdevfd);
- cd64->ppdevfd = 0;
- return 0;
- }
- if (ioctl(cd64->ppdevfd, PPCLAIM) != 0) {
- cd64->notice_callback2("PPCLAIM: %s", strerror(errno));
- close(cd64->ppdevfd);
- cd64->ppdevfd = 0;
- return 0;
- }
- return 1;
- }
- int cd64_close_ppdev(struct cd64_t *cd64) {
- int ret = 1;
- if (cd64->ppdevfd == 0) return 1;
- if (ioctl(cd64->ppdevfd, PPRELEASE) != 0) {
- cd64->notice_callback2("PPRELEASE: %s", strerror(errno));
- ret = 0;
- }
- close(cd64->ppdevfd);
- cd64->ppdevfd = 0;
- return ret;
- }
- static INLINE int cd64_wait_ppdev(struct cd64_t *cd64) {
- /* With ppdev, could we use an interrupt instead? The PPA
- * could be modified... */
- int i = 0;
- int reset_tries = 0;
- uint8_t status;
- int dir;
- i = 0;
- if (ioctl(cd64->ppdevfd, PPRSTATUS, &status) != 0) cd64->notice_callback2("PPRSTATUS: %s", strerror(errno));
- while(status & 0x80) {
- i++;
- if (i >= BUSY_THRESHOLD) {
- /* The PPA is in a weird state.
- * Try to knock some sense into it. */
- dir = 1;
- if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
- status = PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD; /* 0x26 */
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- dir = 0;
- if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
- status = PARPORT_CONTROL_INIT; /* 0x04 */
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- status = PARPORT_CONTROL_INIT | PARPORT_CONTROL_STROBE; /* 0x05 */
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- status = PARPORT_CONTROL_INIT; /* 0x04 */
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- reset_tries++;
- i = 0;
- MSLEEP(1);
- }
- if (cd64->abort) return 0;
- if (reset_tries > MAX_TRIES) break;
- if (ioctl(cd64->ppdevfd, PPRSTATUS, &status) != 0) cd64->notice_callback2("PPRSTATUS: %s", strerror(errno));
- }
- return (reset_tries < MAX_TRIES);
- }
- int cd64_xfer_ppdev(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
- uint8_t ctl;
- int dir;
- if (!cd64_wait_ppdev(cd64)) { return 0; }
- if (delayms) MSLEEP(delayms);
- dir = 1;
- if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
- if (delayms) MSLEEP(delayms);
- ctl = PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD;
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- if (delayms) MSLEEP(delayms);
- if (rd) {
- if (ioctl(cd64->ppdevfd, PPRDATA, rd) != 0) cd64->notice_callback2("PPRDATA: %s", strerror(errno));
- #if DEBUG_LOWLEVEL
- printf("got %xh", *rd);
- if (*rd > 0x20) printf(" (%c)", *rd);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- dir = 0;
- if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
- if (delayms) MSLEEP(delayms);
- ctl = PARPORT_CONTROL_INIT;
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- if (delayms) MSLEEP(delayms);
- if (wr) {
- if (ioctl(cd64->ppdevfd, PPWDATA, wr) != 0) cd64->notice_callback2("PPWDATA: %s", strerror(errno));
- #if DEBUG_LOWLEVEL
- printf("put %xh", *wr);
- if (*wr > 0x20) printf(" (%c)", *wr);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- ctl = PARPORT_CONTROL_INIT | PARPORT_CONTROL_STROBE;
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- if (delayms) MSLEEP(delayms);
- ctl = PARPORT_CONTROL_INIT;
- if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
- return 1;
- }
- #endif /* CD64_USE_PPDEV */
- #ifdef CD64_USE_PORTDEV
- int cd64_open_portdev(struct cd64_t *cd64) {
- if (cd64->portdevfd || cd64->port == 0) return 0;
- if ((cd64->portdevfd = open("/dev/port", O_RDWR)) == -1) {
- cd64->notice_callback2("open: %s", strerror(errno));
- cd64->notice_callback2("portdev requires CAP_SYS_RAWIO capability");
- cd64->portdevfd = 0;
- return 0;
- }
- return 1;
- }
- int cd64_close_portdev(struct cd64_t *cd64) {
- if (cd64->portdevfd == 0) return 1;
- if (close(cd64->portdevfd) == -1) {
- cd64->notice_callback2("close: %s", strerror(errno));
- return 0;
- }
- cd64->portdevfd = 0;
- return 1;
- }
- static INLINE int cd64_wait_portdev(struct cd64_t *cd64) {
- int i = 0;
- int reset_tries = 0;
- uint8_t status;
- int dir;
- i = 0;
- if (cd64->using_ppa) {
- lseek(cd64->portdevfd, cd64->port+1, SEEK_SET);
- read(cd64->portdevfd, &status, 1);
- while(status & 0x80) {
- i++;
- if (i >= BUSY_THRESHOLD) {
- /* The PPA is in a weird state.
- * Try to knock some sense into it. */
- dir = 1;
- status = 0x06 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &status, 1);
- dir = 0;
- status = 0x04 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &status, 1);
- status = 0x05 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &status, 1);
- status = 0x04 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &status, 1);
- reset_tries++;
- i = 0;
- MSLEEP(1);
- }
- if (cd64->abort) return 0;
- if (reset_tries > MAX_TRIES) {
- break;
- }
- lseek(cd64->portdevfd, cd64->port+1, SEEK_SET);
- read(cd64->portdevfd, &status, 1);
- }
- }
- else { /* Comms link */
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- read(cd64->portdevfd, &status, 1);
- while (status & 1) {
- /* Do we need to handle a stuck situation here? */
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- read(cd64->portdevfd, &status, 1);
- }
- }
- return (reset_tries < MAX_TRIES);
- }
- int cd64_xfer_portdev(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
- uint8_t ctl;
- int dir;
- if (cd64->using_ppa) {
- if (!cd64_wait_portdev(cd64)) { return 0; }
- if (delayms) MSLEEP(delayms);
- dir = 1;
- ctl = 0x06 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &ctl, 1);
- if (delayms) MSLEEP(delayms);
- if (rd) {
- lseek(cd64->portdevfd, cd64->port, SEEK_SET);
- read(cd64->portdevfd, rd, 1);
- #if DEBUG_LOWLEVEL
- printf("got %xh", *rd);
- if (*rd > 0x20) printf(" (%c)", *rd);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- dir = 0;
- ctl = 0x04 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &ctl, 1);
- if (delayms) MSLEEP(delayms);
- if (wr) {
- lseek(cd64->portdevfd, cd64->port, SEEK_SET);
- write(cd64->portdevfd, wr, 1);
- #if DEBUG_LOWLEVEL
- printf("put %xh", *wr);
- if (*wr > 0x20) printf(" (%c)", *wr);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- ctl = 0x05 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &ctl, 1);
- if (delayms) MSLEEP(delayms);
- ctl = 0x04 | (dir << 5);
- lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
- write(cd64->portdevfd, &ctl, 1);
- }
- else { /* Comms link */
- lseek(cd64->portdevfd, cd64->port, SEEK_SET);
- write(cd64->portdevfd, wr, 1);
- if (!cd64_wait_portdev(cd64)) { return 0; }
- lseek(cd64->portdevfd, cd64->port, SEEK_SET);
- read(cd64->portdevfd, rd, 1);
- }
- return 1;
- }
- #endif /* CD64_USE_PORTDEV */
- #ifdef CD64_USE_RAWIO
- #if defined _WIN32 || defined __CYGWIN__
- static void *open_module(char *module_name, struct cd64_t *cd64) {
- void *handle = LoadLibrary(module_name);
- if (handle == NULL) {
- LPTSTR strptr;
- cd64->notice_callback2("LoadLibrary: %s", strerror(errno));
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(),
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &strptr, 0, NULL);
- cd64->notice_callback2(strptr);
- LocalFree(strptr);
- exit(1);
- }
- return handle;
- }
- static void close_module(void *handle, struct cd64_t *cd64) {
- if (!FreeLibrary((HINSTANCE) handle)) {
- LPTSTR strptr;
- cd64->notice_callback2("FreeLibrary: %s", strerror(errno));
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(),
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &strptr, 0, NULL);
- cd64->notice_callback2(strptr);
- LocalFree(strptr);
- exit(1);
- }
- }
- static void *get_symbol(void *handle, char *symbol_name, struct cd64_t *cd64) {
- void *symptr;
- u_func_ptr_t sym;
- sym.func_ptr = (void (*)(void)) GetProcAddress((HINSTANCE) handle, symbol_name);
- symptr = sym.void_ptr;
- if (symptr == NULL) {
- LPTSTR strptr;
- cd64->notice_callback2("GetProcAddress: %s", strerror(errno));
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(),
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &strptr, 0, NULL);
- cd64->notice_callback2(strptr);
- LocalFree(strptr);
- exit(1);
- }
- return symptr;
- }
- static void *has_symbol(void *handle, char *symbol_name) {
- void *symptr;
- u_func_ptr_t sym;
- sym.func_ptr = (void (*)(void)) GetProcAddress((HINSTANCE) handle, symbol_name);
- symptr = sym.void_ptr;
- if (symptr == NULL) symptr = (void *) -1;
- return symptr;
- }
- /* inpout32.dll */
- static uint8_t inpout32_input_byte(uint16_t port) {
- return (uint8_t) Inp32((short) port);
- }
- static void inpout32_output_byte(uint8_t byte, uint16_t port) {
- Outp32((short) port, (short) byte);
- }
- /* io.dll */
- static uint8_t io_input_byte(uint16_t port) {
- return PortIn(port);
- }
- static void io_output_byte(uint8_t byte, uint16_t port) {
- PortOut(port, byte);
- }
- /* DlPortIO.dll */
- static uint8_t dlportio_input_byte(uint16_t port) {
- return DlPortReadPortUchar(port);
- }
- static void dlportio_output_byte(uint8_t byte, uint16_t port) {
- DlPortWritePortUchar(port, byte);
- }
- #define NODRIVER_MSG "ERROR: No (working) I/O port driver\n"
- #ifdef __CYGWIN__
- static EXCEPTION_DISPOSITION NTAPI new_exception_handler(PEXCEPTION_RECORD exception_record,
- void *establisher_frame, PCONTEXT context_record, void *dispatcher_context) {
- (void) establisher_frame;
- (void) context_record;
- (void) dispatcher_context;
- if (exception_record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) {
- fputs(NODRIVER_MSG, stderr);
- exit(1);
- }
- return EXCEPTION_CONTINUE_SEARCH;
- }
- #elif defined _WIN32
- static LONG new_exception_filter(LPEXCEPTION_POINTERS exception_pointers) {
- if (exception_pointers->ExceptionRecord->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) {
- fputs(NODRIVER_MSG, stderr);
- exit(1);
- }
- return EXCEPTION_CONTINUE_SEARCH;
- }
- #endif
- #endif /* _WIN32 || __CYGWIN__ */
- #if ((defined _WIN32 || defined __CYGWIN__ || defined __BEOS__ || \
- defined __MSDOS__) && \
- (defined __i386__ || defined __x86_64__)) || defined _MSC_VER
- static INLINE uint8_t inb(uint16_t port) {
- #ifdef __MSDOS__
- return inportb(port);
- #elif defined __BEOS__
- st_ioport_t temp;
- temp.port = port;
- ioctl(io_portfd, 'r', &temp, 0);
- return temp.data8;
- #else /* Win32 */
- if (io_driver_found) return input_byte(port);
- else {
- #ifdef _MSC_VER
- return (unsigned char) _inp(port);
- #else
- unsigned char byte;
- __asm__ __volatile__
- ("inb %1, %0"
- : "=a" (byte)
- : "d" (port)
- );
- return byte;
- #endif
- }
- #endif
- }
- static INLINE void outb(uint8_t byte, uint16_t port) {
- #ifdef __MSDOS__
- outportb(port, byte);
- #elif defined __BEOS__
- st_ioport_t temp;
- temp.port = port;
- temp.data8 = byte;
- ioctl(io_portfd, 'w', &temp, 0);
- #else /* Win32 */
- if (io_driver_found) output_byte(byte, port);
- else {
- #ifdef _MSC_VER
- _outp(port, byte);
- #else
- __asm__ __volatile__
- ("outb %1, %0"
- :
- : "d" (port), "a" (byte)
- );
- #endif
- }
- #endif
- }
- #endif /* inb/outb defs */
- int cd64_open_rawio(struct cd64_t *cd64) {
- int ret;
- (void) ret;
- /* NOTE: we will soon be able to use ioperm on the entire
- * 16-bit port range. Find out what Linux kernels support it. */
- if (cd64->port < 0x200) {
- cd64->notice_callback2("Erroneous port %xh", cd64->port);
- return 0;
- }
- #ifdef __linux__
- if (cd64->port < 0x3fd) {
- if (cd64->using_ppa) {
- ret = ioperm(cd64->port, 3, 1);
- }
- else {
- ret = ioperm(cd64->port, 1, 1);
- ret |= ioperm(cd64->port+2, 1, 1);
- }
- if (ret == -1) {
- cd64->notice_callback2("ioperm: %s", strerror(errno));
- cd64->notice_callback2("rawio requires CAP_SYS_RAWIO capability");
- return 0;
- }
- }
- else {
- ret = iopl(3);
- if (ret == -1) {
- cd64->notice_callback2("iopl: %s", strerror(errno));
- cd64->notice_callback2("rawio requires CAP_SYS_RAWIO capability");
- return 0;
- }
- }
- #elif defined __OpenBSD__
- /* I cannot test i386_set_ioperm(), so I only use i386_iopl() */
- ret = i386_iopl(3);
- if (ret == -1) {
- cd64->notice_callback2("i386_iopl: %s", strerror(errno));
- return 0;
- }
- #elif defined __FreeBSD__
- cd64->portdevfd = open("/dev/io", O_RDWR);
- if (cd64->portdevfd == -1) {
- cd64->portdevfd = 0;
- cd64->notice_callback2("open: %s", strerror(errno));
- cd64->notice_callback2("Could not open I/O port device (/dev/io)");
- return 0;
- }
- #elif defined __BEOS__
- io_portfd = open("/dev/misc/ioport", O_RDWR | O_NONBLOCK);
- if (io_portfd == -1) {
- io_portfd = 0;
- cd64->notice_callback2("open: %s", strerror(errno));
- cd64->notice_callback2("Could not open I/O port device (no driver)");
- exit(1);
- }
- #elif defined _WIN32 || defined __CYGWIN__
- #ifdef _MSC_VER
- #define access _access
- #endif
- {
- char fname[FILENAME_MAX+1];
- u_func_ptr_t sym;
- io_driver_found = 0;
- if (!cd64->io_driver_dir[0]) strcpy(cd64->io_driver_dir, ".");
- snprintf(fname, FILENAME_MAX+1, "%s" DIR_SEPARATOR_S "%s",
- cd64->io_driver_dir, "dlportio.dll");
- fname[FILENAME_MAX] = 0;
- if (access(fname, F_OK) == 0) {
- io_driver = open_module(fname, cd64);
- io_driver_found = 1;
- sym.void_ptr = get_symbol(io_driver, "DlPortReadPortUchar", cd64);
- DlPortReadPortUchar = (unsigned char (__stdcall *)(unsigned short)) sym.func_ptr;
- sym.void_ptr = get_symbol(io_driver, "DlPortWritePortUchar", cd64);
- DlPortWritePortUchar = (void (__stdcall *)(unsigned short, unsigned char)) sym.func_ptr;
- input_byte = dlportio_input_byte;
- output_byte = dlportio_output_byte;
- }
- if (!io_driver_found) {
- snprintf(fname, FILENAME_MAX+1, "%s" DIR_SEPARATOR_S "%s",
- cd64->io_driver_dir, "io.dll");
- fname[FILENAME_MAX] = 0;
- if (access(fname, F_OK) == 0) {
- io_driver = open_module(fname, cd64);
- sym.void_ptr = get_symbol(io_driver, "IsDriverInstalled", cd64);
- IsDriverInstalled = (short int (WINAPI *)(void)) sym.func_ptr;
- if (IsDriverInstalled()) {
- io_driver_found = 1;
- sym.void_ptr = get_symbol(io_driver, "PortIn", cd64);
- PortIn = (char (WINAPI *)(short int)) sym.func_ptr;
- sym.void_ptr = get_symbol(io_driver, "PortOut", cd64);
- PortOut = (void (WINAPI *)(short int, char)) sym.func_ptr;
- input_byte = io_input_byte;
- output_byte = io_output_byte;
- }
- }
- }
- if (!io_driver_found) {
- snprintf(fname, FILENAME_MAX+1, "%s" DIR_SEPARATOR_S "%s",
- cd64->io_driver_dir, "inpout32.dll");
- fname[FILENAME_MAX] = 0;
- if (access(fname, F_OK) == 0) {
- io_driver = open_module(fname, cd64);
- io_driver_found = 1;
- /* Newer ports of inpout32.dll also contain the API provided by
- * DlPortIO.dll. Since the API of DlPortIO.dll does not have
- * the flaws of inpout32.dll (*signed* short return value and
- * arguments), we prefer it if it is present. */
- sym.void_ptr = has_symbol(io_driver, "DlPortReadPortUchar");
- DlPortReadPortUchar = (unsigned char (__stdcall *)(unsigned short)) sym.func_ptr;
- if (DlPortReadPortUchar != (void *) -1) input_byte = dlportio_input_byte;
- else {
- sym.void_ptr = get_symbol(io_driver, "Inp32", cd64);
- Inp32 = (short (__stdcall *)(short)) sym.func_ptr;
- input_byte = inpout32_input_byte;
- }
- sym.void_ptr = has_symbol(io_driver, "DlPortWritePortUchar");
- DlPortWritePortUchar = (void (__stdcall *)(unsigned short, unsigned char)) sym.func_ptr;
- if (DlPortWritePortUchar != (void *) -1) output_byte = dlportio_output_byte;
- else {
- sym.void_ptr = get_symbol(io_driver, "Out32", cd64);
- Outp32 = (void (__stdcall *)(short, short)) sym.func_ptr;
- output_byte = inpout32_output_byte;
- }
- }
- }
- }
- {
- /* __try and __except are not supported by MinGW and Cygwin. MinGW has
- * __try1 and __except1, but using them requires more code than we
- * currently have. Cygwin does something stupid which breaks
- * SetUnhandledExceptionFilter()... */
- #ifdef __CYGWIN__ /* Cygwin */
- EXCEPTION_REGISTRATION exception_registration;
- exception_registration.handler = new_exception_handler;
- __asm__ __volatile__
- ("movl %%fs:0, %0\n"
- "movl %1, %%fs:0"
- : "=a" (exception_registration.prev)
- : "b" (&exception_registration)
- );
- input_byte(0x378); /* 0x378 is okay */
- /* if we get here accessing I/O port 0x378 did not cause an exception */
- __asm__ __volatile__
- ("movl %0, %%fs:0"
- :
- : "r" (exception_registration.prev)
- );
- #elif defined _WIN32 /* MinGW & Visual C++ */
- LPTOP_LEVEL_EXCEPTION_FILTER org_exception_filter =
- SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) new_exception_filter);
- input_byte(0x378); /* 0x378 is okay */
- /* if we get here accessing I/O port 0x378 did not cause an exception */
- SetUnhandledExceptionFilter(org_exception_filter);
- #endif
- }
- #ifdef _MSC_VER
- #undef access
- #endif
- #endif /* _WIN32 || __CYGWIN__ */
- return 1;
- }
- int cd64_close_rawio(struct cd64_t *cd64) {
- int ret;
- (void) ret;
- (void) cd64;
- #ifdef __linux__
- if (cd64->port < 0x3fd) {
- if (cd64->using_ppa) {
- ret = ioperm(cd64->port, 3, 0);
- }
- else {
- ret = ioperm(cd64->port, 1, 0);
- ret |= ioperm(cd64->port+2, 1, 0);
- }
- if (ret == -1) {
- cd64->notice_callback2("ioperm: %s", strerror(errno));
- return 0;
- }
- }
- else {
- ret = iopl(0);
- if (ret == -1) {
- cd64->notice_callback2("iopl: %s", strerror(errno));
- return 0;
- }
- }
- #elif defined __OpenBSD__
- /* I cannot test i386_set_ioperm(), so I only use i386_iopl() */
- ret = i386_iopl(0);
- if (ret == -1) {
- cd64->notice_callback2("i386_iopl: %s", strerror(errno));
- return 0;
- }
- #elif defined __FreeBSD__
- if (close(cd64->portdevfd) == -1) {
- cd64->notice_callback2("close: %s", strerror(errno));
- return 0;
- }
- cd64->portdevfd = 0;
- #elif defined __BEOS__
- if (close(io_portfd) == -1) {
- cd64->notice_callback2("close: %s", strerror(errno));
- return 0;
- }
- io_portfd = 0;
- #elif defined _WIN32 || defined __CYGWIN__
- close_module(io_driver, cd64);
- io_driver = NULL;
- io_driver_found = 0;
- input_byte = inb;
- output_byte = outb;
- #endif
- return 1;
- }
- static INLINE int cd64_wait_rawio(struct cd64_t *cd64) {
- int i = 0;
- int reset_tries = 0;
- uint8_t status;
- uint8_t dir;
- i = 0;
- if (cd64->using_ppa) {
- status = inb((uint16_t) (cd64->port+1));
- while(status & 0x80) {
- i++;
- if (i >= BUSY_THRESHOLD) {
- /* The PPA is in a weird state.
- * Try to knock some sense into it. */
- dir = 1;
- status = 0x06 | (dir << 5);
- outb(status, (uint16_t) (cd64->port+2));
- dir = 0;
- status = 0x04 | (dir << 5);
- outb(status, (uint16_t) (cd64->port+2));
- status = 0x05 | (dir << 5);
- outb(status, (uint16_t) (cd64->port+2));
- status = 0x04 | (dir << 5);
- outb(status, (uint16_t) (cd64->port+2));
- reset_tries++;
- i = 0;
- MSLEEP(1);
- }
- if (cd64->abort) return 0;
- if (reset_tries > MAX_TRIES) {
- break;
- }
- status = inb((uint16_t) (cd64->port+1));
- }
- }
- else { /* Comms link */
- status = inb((uint16_t) (cd64->port+2));
- while (status & 1) {
- /* Do we need to handle a stuck situation here? */
- status = inb((uint16_t) (cd64->port+2));
- }
- }
- return (reset_tries < MAX_TRIES);
- }
- int cd64_xfer_rawio(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
- uint8_t ctl;
- uint8_t dir;
- if (cd64->using_ppa) {
- if (!cd64_wait_rawio(cd64)) { return 0; }
- if (delayms) MSLEEP(delayms);
- dir = 1;
- ctl = 0x06 | (dir << 5);
- outb(ctl, (uint16_t) (cd64->port+2));
- if (delayms) MSLEEP(delayms);
- if (rd) {
- *rd = inb((uint16_t) cd64->port);
- #if DEBUG_LOWLEVEL
- printf("got %xh", *rd);
- if (*rd > 0x20) printf(" (%c)", *rd);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- dir = 0;
- ctl = 0x04 | (dir << 5);
- outb(ctl, (uint16_t) (cd64->port+2));
- if (delayms) MSLEEP(delayms);
- if (wr) {
- outb(*wr, (uint16_t) cd64->port);
- #if DEBUG_LOWLEVEL
- printf("put %xh", *wr);
- if (*wr > 0x20) printf(" (%c)", *wr);
- printf("\n");
- #endif
- }
- if (delayms) MSLEEP(delayms);
- ctl = 0x05 | (dir << 5);
- outb(ctl, (uint16_t) (cd64->port+2));
- if (delayms) MSLEEP(delayms);
- ctl = 0x04 | (dir << 5);
- outb(ctl, (uint16_t) (cd64->port+2));
- }
- else { /* Comms link */
- outb(*wr, (uint16_t) cd64->port);
- if (!cd64_wait_rawio(cd64)) { return 0; }
- *rd = inb((uint16_t) cd64->port);
- }
- return 1;
- }
- #endif /* CD64_USE_RAWIO */
|