cd64io.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. /*
  2. *
  3. * cd64io.c
  4. *
  5. * I/O routines for CD64 device
  6. *
  7. * (c) 2004 Ryan Underwood
  8. * Portions (c) 2004 Daniel Horchner (OpenBSD, FreeBSD, BeOS, Win32, DOS)
  9. *
  10. * May be distributed under the terms of the GNU Lesser/Library General Public
  11. * License, or any later version of the same, as published by the Free Software
  12. * Foundation.
  13. */
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <fcntl.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #if defined __unix__ || defined __BEOS__ /* ioctl() */
  23. #include <unistd.h>
  24. #endif
  25. #include <ultra64/host/cd64lib.h>
  26. #include "cd64io.h"
  27. #define DEBUG_LOWLEVEL 0
  28. #define BUSY_THRESHOLD 10000
  29. #define MAX_TRIES 5
  30. #ifdef CD64_USE_RAWIO
  31. #if defined _WIN32 || defined __CYGWIN__
  32. #ifdef __CYGWIN__
  33. #define FILE_SEPARATOR_S "/"
  34. #else
  35. #define snprintf _snprintf
  36. #define FILE_SEPARATOR_S "\\"
  37. #endif
  38. static void *io_driver = NULL;
  39. static int io_driver_found = 0;
  40. /* io.dll */
  41. static char (WINAPI *PortIn)(short int) = NULL;
  42. static void (WINAPI *PortOut)(short int, char) = NULL;
  43. static short int (WINAPI *IsDriverInstalled)() = NULL;
  44. /* DlPortIO.dll */
  45. static unsigned char (__stdcall *DlPortReadPortUchar)(unsigned long) = NULL;
  46. static void (__stdcall *DlPortWritePortUchar)(unsigned long, unsigned char) = NULL;
  47. INLINE uint8_t inb(uint16_t);
  48. INLINE void outb(uint8_t, uint16_t);
  49. static uint8_t (*input_byte)(uint16_t) = inb;
  50. static void (*output_byte)(uint8_t, uint16_t) = outb;
  51. #endif
  52. #ifdef __BEOS__
  53. static int io_portfd;
  54. typedef struct st_ioport {
  55. unsigned int port;
  56. unsigned char data8;
  57. unsigned short data16;
  58. } st_ioport_t;
  59. #endif
  60. #endif /* CD64_USE_RAWIO */
  61. int cd64_send_byte(struct cd64_t *cd64, uint8_t what) {
  62. return cd64->xfer(cd64, &what, NULL, 0);
  63. }
  64. int cd64_send_dword(struct cd64_t *cd64, uint32_t what) {
  65. int ret = 1;
  66. ret &= cd64_send_byte(cd64, (uint8_t) (what>>24));
  67. ret &= cd64_send_byte(cd64, (uint8_t) (what>>16));
  68. ret &= cd64_send_byte(cd64, (uint8_t) (what>>8));
  69. ret &= cd64_send_byte(cd64, (uint8_t) what);
  70. return ret;
  71. }
  72. int cd64_grab_byte(struct cd64_t *cd64, uint8_t *val) {
  73. return cd64->xfer(cd64, NULL, val, 0);
  74. }
  75. int cd64_grab_dword(struct cd64_t *cd64, uint32_t *val) {
  76. int ret = 1;
  77. uint8_t grab;
  78. if (val == NULL) return 0;
  79. *val = 0;
  80. ret &= cd64_grab_byte(cd64, &grab);
  81. *val |= grab << 24;
  82. ret &= cd64_grab_byte(cd64, &grab);
  83. *val |= grab << 16;
  84. ret &= cd64_grab_byte(cd64, &grab);
  85. *val |= grab << 8;
  86. ret &= cd64_grab_byte(cd64, &grab);
  87. *val |= grab;
  88. return ret;
  89. }
  90. int cd64_trade_bytes(struct cd64_t *cd64, uint8_t give, uint8_t *recv) {
  91. return cd64->xfer(cd64, &give, recv, 0);
  92. }
  93. /* Backend-specific defs go down here. */
  94. #ifdef CD64_USE_LIBIEEE1284
  95. int cd64_open_ieee1284(struct cd64_t *cd64) {
  96. struct parport_list pplist;
  97. int ppflags = F1284_EXCL;
  98. int ppcaps = 0;
  99. int i;
  100. int opened = 0;
  101. if (cd64->ppdev || !cd64->using_ppa) return 0;
  102. if (ieee1284_find_ports(&pplist, 0) < 0) {
  103. cd64->notice_callback2("couldn't get port list\n");
  104. return 0;
  105. }
  106. if (cd64->port < pplist.portc) {
  107. /* Just use it as an index. */
  108. cd64->ppdev = pplist.portv[cd64->port];
  109. }
  110. else {
  111. /* Search for the ppdev matching its base address. */
  112. for (i = 0; i < pplist.portc; i++) {
  113. if (cd64->port == (int) pplist.portv[i]->base_addr) {
  114. cd64->ppdev = pplist.portv[i];
  115. }
  116. }
  117. }
  118. if (cd64->ppdev) {
  119. if (ieee1284_open(cd64->ppdev, ppflags, &ppcaps) < 0) {
  120. cd64->notice_callback2("failed opening ieee1284 port %d\n", cd64->port);
  121. cd64->ppdev = NULL;
  122. }
  123. else {
  124. opened = 1;
  125. }
  126. }
  127. ieee1284_free_ports(&pplist);
  128. if (opened && ieee1284_claim(cd64->ppdev) < 0) return 0;
  129. else return opened;
  130. }
  131. int cd64_close_ieee1284(struct cd64_t *cd64) {
  132. int ret;
  133. if (cd64->ppdev == NULL) return 1;
  134. ieee1284_release(cd64->ppdev);
  135. ret = ieee1284_close(cd64->ppdev);
  136. if (ret < 0) ret = 0;
  137. else {
  138. cd64->ppdev = NULL;
  139. ret = 1;
  140. }
  141. return ret;
  142. }
  143. static INLINE int cd64_wait_ieee(struct cd64_t *cd64) {
  144. /* With ppdev, could we use an interrupt instead? The PPA
  145. * could be modified... */
  146. int i = 0;
  147. int reset_tries = 0;
  148. while (i < 10000) i++; /* FIXME is this necessary? */
  149. i = 0;
  150. while((ieee1284_read_status(cd64->ppdev)^S1284_INVERTED) & S1284_BUSY) {
  151. i++;
  152. if (i >= BUSY_THRESHOLD) {
  153. /* The PPA is in a weird state.
  154. * Try to knock some sense into it. */
  155. ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NAUTOFD)^C1284_INVERTED);
  156. ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
  157. ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NSTROBE)^C1284_INVERTED);
  158. ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
  159. reset_tries++;
  160. i = 0;
  161. USLEEP(1);
  162. }
  163. if (reset_tries > MAX_TRIES) break;
  164. if (cd64->abort) return 0;
  165. }
  166. return (reset_tries < MAX_TRIES);
  167. }
  168. int cd64_xfer_ieee1284(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
  169. if (!cd64_wait_ieee(cd64)) { return 0; }
  170. if (delayms) USLEEP(delayms);
  171. ieee1284_data_dir(cd64->ppdev, 1);
  172. if (delayms) USLEEP(delayms);
  173. ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NAUTOFD)^C1284_INVERTED);
  174. if (delayms) USLEEP(delayms);
  175. if (rd) {
  176. *rd = ieee1284_read_data(cd64->ppdev);
  177. #if DEBUG_LOWLEVEL
  178. printf("got %xh", *rd);
  179. if (*rd > 0x20) printf(" (%c)", *rd);
  180. printf("\n");
  181. #endif
  182. }
  183. if (delayms) USLEEP(delayms);
  184. ieee1284_data_dir(cd64->ppdev, 0);
  185. if (delayms) USLEEP(delayms);
  186. ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
  187. if (delayms) USLEEP(delayms);
  188. if (wr) {
  189. ieee1284_write_data(cd64->ppdev, *wr);
  190. #if DEBUG_LOWLEVEL
  191. printf("put %xh", *wr);
  192. if (*wr > 0x20) printf(" (%c)", *wr);
  193. printf("\n");
  194. #endif
  195. }
  196. if (delayms) USLEEP(delayms);
  197. ieee1284_write_control(cd64->ppdev, (C1284_NINIT|C1284_NSTROBE)^C1284_INVERTED);
  198. if (delayms) USLEEP(delayms);
  199. ieee1284_write_control(cd64->ppdev, C1284_NINIT^C1284_INVERTED);
  200. return 1;
  201. }
  202. #endif /* CD64_USE_LIBIEEE1284 */
  203. #ifdef CD64_USE_PPDEV
  204. int cd64_open_ppdev(struct cd64_t *cd64) {
  205. char *device = "/dev/parport%d";
  206. char realdev[128+1];
  207. if (cd64->ppdevfd || !cd64->using_ppa) return 0;
  208. /* This should be a port number only, not an address */
  209. if (cd64->port > PARPORT_MAX) return 0;
  210. snprintf(realdev, 128, device, cd64->port);
  211. if ((cd64->ppdevfd = open(realdev, O_RDWR)) == -1) {
  212. cd64->notice_callback2("open: %s", strerror(errno));
  213. cd64->ppdevfd = 0;
  214. return 0;
  215. }
  216. if (ioctl(cd64->ppdevfd, PPEXCL) != 0) {
  217. cd64->notice_callback2("PPEXCL: %s", strerror(errno));
  218. close(cd64->ppdevfd);
  219. cd64->ppdevfd = 0;
  220. return 0;
  221. }
  222. if (ioctl(cd64->ppdevfd, PPCLAIM) != 0) {
  223. cd64->notice_callback2("PPCLAIM: %s", strerror(errno));
  224. close(cd64->ppdevfd);
  225. cd64->ppdevfd = 0;
  226. return 0;
  227. }
  228. return 1;
  229. }
  230. int cd64_close_ppdev(struct cd64_t *cd64) {
  231. int ret = 1;
  232. if (cd64->ppdevfd == 0) return 1;
  233. if (ioctl(cd64->ppdevfd, PPRELEASE) != 0) {
  234. cd64->notice_callback2("PPRELEASE: %s", strerror(errno));
  235. ret = 0;
  236. }
  237. close(cd64->ppdevfd);
  238. cd64->ppdevfd = 0;
  239. return ret;
  240. }
  241. static INLINE int cd64_wait_ppdev(struct cd64_t *cd64) {
  242. /* With ppdev, could we use an interrupt instead? The PPA
  243. * could be modified... */
  244. int i = 0;
  245. int reset_tries = 0;
  246. uint8_t status;
  247. int dir;
  248. i = 0;
  249. if (ioctl(cd64->ppdevfd, PPRSTATUS, &status) != 0) cd64->notice_callback2("PPRSTATUS: %s", strerror(errno));
  250. while(status & 0x80) {
  251. i++;
  252. if (i >= BUSY_THRESHOLD) {
  253. /* The PPA is in a weird state.
  254. * Try to knock some sense into it. */
  255. dir = 1;
  256. if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
  257. status = PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD; /* 0x26 */
  258. if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  259. dir = 0;
  260. if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
  261. status = PARPORT_CONTROL_INIT; /* 0x04 */
  262. if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  263. status = PARPORT_CONTROL_INIT | PARPORT_CONTROL_STROBE; /* 0x05 */
  264. if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  265. status = PARPORT_CONTROL_INIT; /* 0x04 */
  266. if (ioctl(cd64->ppdevfd, PPWCONTROL, &status) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  267. reset_tries++;
  268. i = 0;
  269. USLEEP(1);
  270. }
  271. if (cd64->abort) return 0;
  272. if (reset_tries > MAX_TRIES) break;
  273. if (ioctl(cd64->ppdevfd, PPRSTATUS, &status) != 0) cd64->notice_callback2("PPRSTATUS: %s", strerror(errno));
  274. }
  275. return (reset_tries < MAX_TRIES);
  276. }
  277. int cd64_xfer_ppdev(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
  278. uint8_t ctl;
  279. int dir;
  280. if (!cd64_wait_ppdev(cd64)) { return 0; }
  281. if (delayms) USLEEP(delayms);
  282. dir = 1;
  283. if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
  284. if (delayms) USLEEP(delayms);
  285. ctl = PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD;
  286. if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  287. if (delayms) USLEEP(delayms);
  288. if (rd) {
  289. if (ioctl(cd64->ppdevfd, PPRDATA, rd) != 0) cd64->notice_callback2("PPRDATA: %s", strerror(errno));
  290. #if DEBUG_LOWLEVEL
  291. printf("got %xh", *rd);
  292. if (*rd > 0x20) printf(" (%c)", *rd);
  293. printf("\n");
  294. #endif
  295. }
  296. if (delayms) USLEEP(delayms);
  297. dir = 0;
  298. if (ioctl(cd64->ppdevfd, PPDATADIR, &dir) != 0) cd64->notice_callback2("PPDATADIR: %s", strerror(errno));
  299. if (delayms) USLEEP(delayms);
  300. ctl = PARPORT_CONTROL_INIT;
  301. if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  302. if (delayms) USLEEP(delayms);
  303. if (wr) {
  304. if (ioctl(cd64->ppdevfd, PPWDATA, wr) != 0) cd64->notice_callback2("PPWDATA: %s", strerror(errno));
  305. #if DEBUG_LOWLEVEL
  306. printf("put %xh", *wr);
  307. if (*wr > 0x20) printf(" (%c)", *wr);
  308. printf("\n");
  309. #endif
  310. }
  311. if (delayms) USLEEP(delayms);
  312. ctl = PARPORT_CONTROL_INIT | PARPORT_CONTROL_STROBE;
  313. if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  314. if (delayms) USLEEP(delayms);
  315. ctl = PARPORT_CONTROL_INIT;
  316. if (ioctl(cd64->ppdevfd, PPWCONTROL, &ctl) != 0) cd64->notice_callback2("PPWCONTROL: %s", strerror(errno));
  317. return 1;
  318. }
  319. #endif
  320. #ifdef CD64_USE_PORTDEV
  321. int cd64_open_portdev(struct cd64_t *cd64) {
  322. if (cd64->portdevfd || cd64->port == 0) return 0;
  323. if ((cd64->portdevfd = open("/dev/port", O_RDWR)) == -1) {
  324. cd64->notice_callback2("open: %s", strerror(errno));
  325. cd64->notice_callback2("portdev requires CAP_SYS_RAWIO capability");
  326. cd64->portdevfd = 0;
  327. return 0;
  328. }
  329. return 1;
  330. }
  331. int cd64_close_portdev(struct cd64_t *cd64) {
  332. if (cd64->portdevfd == 0) return 1;
  333. if (close(cd64->portdevfd) == -1) {
  334. cd64->notice_callback2("close: %s", strerror(errno));
  335. return 0;
  336. }
  337. cd64->portdevfd = 0;
  338. return 1;
  339. }
  340. static INLINE int cd64_wait_portdev(struct cd64_t *cd64) {
  341. int i = 0;
  342. int reset_tries = 0;
  343. uint8_t status;
  344. int dir;
  345. i = 0;
  346. if (cd64->using_ppa) {
  347. lseek(cd64->portdevfd, cd64->port+1, SEEK_SET);
  348. read(cd64->portdevfd, &status, 1);
  349. while(status & 0x80) {
  350. i++;
  351. if (i >= BUSY_THRESHOLD) {
  352. /* The PPA is in a weird state.
  353. * Try to knock some sense into it. */
  354. dir = 1;
  355. status = 0x06 | (dir << 5);
  356. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  357. write(cd64->portdevfd, &status, 1);
  358. dir = 0;
  359. status = 0x04 | (dir << 5);
  360. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  361. write(cd64->portdevfd, &status, 1);
  362. status = 0x05 | (dir << 5);
  363. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  364. write(cd64->portdevfd, &status, 1);
  365. status = 0x04 | (dir << 5);
  366. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  367. write(cd64->portdevfd, &status, 1);
  368. reset_tries++;
  369. i = 0;
  370. USLEEP(1);
  371. }
  372. if (cd64->abort) return 0;
  373. if (reset_tries > MAX_TRIES) {
  374. break;
  375. }
  376. lseek(cd64->portdevfd, cd64->port+1, SEEK_SET);
  377. read(cd64->portdevfd, &status, 1);
  378. }
  379. }
  380. else { /* Comms link */
  381. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  382. read(cd64->portdevfd, &status, 1);
  383. while (status & 1) {
  384. /* Do we need to handle a stuck situation here? */
  385. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  386. read(cd64->portdevfd, &status, 1);
  387. }
  388. }
  389. return (reset_tries < MAX_TRIES);
  390. }
  391. int cd64_xfer_portdev(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
  392. uint8_t ctl;
  393. int dir;
  394. if (cd64->using_ppa) {
  395. if (!cd64_wait_portdev(cd64)) { return 0; }
  396. if (delayms) USLEEP(delayms);
  397. dir = 1;
  398. ctl = 0x06 | (dir << 5);
  399. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  400. write(cd64->portdevfd, &ctl, 1);
  401. if (delayms) USLEEP(delayms);
  402. if (rd) {
  403. lseek(cd64->portdevfd, cd64->port, SEEK_SET);
  404. read(cd64->portdevfd, rd, 1);
  405. #if DEBUG_LOWLEVEL
  406. printf("got %xh", *rd);
  407. if (*rd > 0x20) printf(" (%c)", *rd);
  408. printf("\n");
  409. #endif
  410. }
  411. if (delayms) USLEEP(delayms);
  412. dir = 0;
  413. ctl = 0x04 | (dir << 5);
  414. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  415. write(cd64->portdevfd, &ctl, 1);
  416. if (delayms) USLEEP(delayms);
  417. if (wr) {
  418. lseek(cd64->portdevfd, cd64->port, SEEK_SET);
  419. write(cd64->portdevfd, wr, 1);
  420. #if DEBUG_LOWLEVEL
  421. printf("put %xh", *wr);
  422. if (*wr > 0x20) printf(" (%c)", *wr);
  423. printf("\n");
  424. #endif
  425. }
  426. if (delayms) USLEEP(delayms);
  427. ctl = 0x05 | (dir << 5);
  428. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  429. write(cd64->portdevfd, &ctl, 1);
  430. if (delayms) USLEEP(delayms);
  431. ctl = 0x04 | (dir << 5);
  432. lseek(cd64->portdevfd, cd64->port+2, SEEK_SET);
  433. write(cd64->portdevfd, &ctl, 1);
  434. }
  435. else { /* Comms link */
  436. lseek(cd64->portdevfd, cd64->port, SEEK_SET);
  437. write(cd64->portdevfd, wr, 1);
  438. if (!cd64_wait_portdev(cd64)) { return 0; }
  439. lseek(cd64->portdevfd, cd64->port, SEEK_SET);
  440. read(cd64->portdevfd, rd, 1);
  441. }
  442. return 1;
  443. }
  444. #endif
  445. #ifdef CD64_USE_RAWIO
  446. #if defined _WIN32 || defined __CYGWIN__
  447. static void *open_module(char *module_name, struct cd64_t *cd64) {
  448. void *handle = LoadLibrary(module_name);
  449. if (handle == NULL) {
  450. LPTSTR strptr;
  451. cd64->notice_callback2("LoadLibrary: %s", strerror(errno));
  452. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  453. FORMAT_MESSAGE_FROM_SYSTEM |
  454. FORMAT_MESSAGE_IGNORE_INSERTS,
  455. NULL, GetLastError(),
  456. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  457. (LPTSTR) &strptr, 0, NULL);
  458. cd64->notice_callback2(strptr);
  459. LocalFree(strptr);
  460. exit(1);
  461. }
  462. return handle;
  463. }
  464. static void close_module(void *handle, struct cd64_t *cd64) {
  465. if (!FreeLibrary((HINSTANCE) handle)) {
  466. LPTSTR strptr;
  467. cd64->notice_callback2("FreeLibrary: %s", strerror(errno));
  468. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  469. FORMAT_MESSAGE_FROM_SYSTEM |
  470. FORMAT_MESSAGE_IGNORE_INSERTS,
  471. NULL, GetLastError(),
  472. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  473. (LPTSTR) &strptr, 0, NULL);
  474. cd64->notice_callback2(strptr);
  475. LocalFree(strptr);
  476. exit(1);
  477. }
  478. }
  479. static void *get_symbol(void *handle, char *symbol_name, struct cd64_t *cd64) {
  480. void *symptr = (void *) GetProcAddress((HINSTANCE) handle, symbol_name);
  481. if (symptr == NULL) {
  482. LPTSTR strptr;
  483. cd64->notice_callback2("GetProcAddress: %s", strerror(errno));
  484. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  485. FORMAT_MESSAGE_FROM_SYSTEM |
  486. FORMAT_MESSAGE_IGNORE_INSERTS,
  487. NULL, GetLastError(),
  488. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  489. (LPTSTR) &strptr, 0, NULL);
  490. cd64->notice_callback2(strptr);
  491. LocalFree(strptr);
  492. exit(1);
  493. }
  494. return symptr;
  495. }
  496. /* io.dll */
  497. static uint8_t io_input_byte(uint16_t port) {
  498. return PortIn(port);
  499. }
  500. static void io_output_byte(uint8_t byte, uint16_t port) {
  501. PortOut(port, byte);
  502. }
  503. /* DlPortIO.dll */
  504. static uint8_t dlportio_input_byte(uint16_t port) {
  505. return DlPortReadPortUchar(port);
  506. }
  507. static void dlportio_output_byte(uint8_t byte, uint16_t port) {
  508. DlPortWritePortUchar(port, byte);
  509. }
  510. #define NODRIVER_MSG "ERROR: No (working) I/O port driver\n"
  511. #ifdef __CYGWIN__
  512. static int new_exception_handler(PEXCEPTION_RECORD exception_record,
  513. void *establisher_frame, PCONTEXT context_record,
  514. void *dispatcher_context) {
  515. (void) establisher_frame;
  516. (void) context_record;
  517. (void) dispatcher_context;
  518. if (exception_record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) {
  519. fputs(NODRIVER_MSG, stderr);
  520. exit(1);
  521. }
  522. return EXCEPTION_CONTINUE_SEARCH;
  523. }
  524. #elif defined _WIN32
  525. static LONG new_exception_filter(LPEXCEPTION_POINTERS exception_pointers) {
  526. if (exception_pointers->ExceptionRecord->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) {
  527. fputs(NODRIVER_MSG, stderr);
  528. exit(1);
  529. }
  530. return EXCEPTION_CONTINUE_SEARCH;
  531. }
  532. #endif
  533. #endif /* _WIN32 || __CYGWIN__ */
  534. #if ((defined _WIN32 || defined __CYGWIN__ || defined __BEOS__ || \
  535. defined __MSDOS__) && \
  536. (defined __i386__ || defined __x86_64__)) || defined _MSC_VER
  537. INLINE uint8_t inb(uint16_t port) {
  538. #ifdef __MSDOS__
  539. return inportb(port);
  540. #elif defined __BEOS__
  541. st_ioport_t temp;
  542. temp.port = port;
  543. ioctl(io_portfd, 'r', &temp, 0);
  544. return temp.data8;
  545. #else /* Win32 */
  546. if (io_driver_found) {
  547. return input_byte(port);
  548. }
  549. else {
  550. #ifdef _MSC_VER
  551. return (unsigned char) inp(port);
  552. #else
  553. unsigned char byte;
  554. __asm__ __volatile__
  555. ("inb %1, %0"
  556. : "=a" (byte)
  557. : "d" (port)
  558. );
  559. return byte;
  560. #endif
  561. }
  562. #endif
  563. }
  564. INLINE void outb(uint8_t byte, uint16_t port) {
  565. #ifdef __MSDOS__
  566. outportb(port, byte);
  567. #elif defined __BEOS__
  568. st_ioport_t temp;
  569. temp.port = port;
  570. temp.data8 = byte;
  571. ioctl(io_portfd, 'w', &temp, 0);
  572. #else /* Win32 */
  573. if (io_driver_found) {
  574. output_byte(byte, port);
  575. }
  576. else {
  577. #ifdef _MSC_VER
  578. outp(port, byte);
  579. #else
  580. __asm__ __volatile__
  581. ("outb %1, %0"
  582. :
  583. : "d" (port), "a" (byte)
  584. );
  585. #endif
  586. }
  587. #endif
  588. }
  589. #endif /* inb/outb defs */
  590. int cd64_open_rawio(struct cd64_t *cd64) {
  591. int ret;
  592. (void) ret;
  593. /* NOTE: we will soon be able to use ioperm on the entire
  594. * 16-bit port range. Find out what Linux kernels support it. */
  595. if (cd64->port < 0x200) {
  596. cd64->notice_callback2("Erroneous port %xh", cd64->port);
  597. return 0;
  598. }
  599. #ifdef __linux__
  600. if (cd64->port < 0x3fd) {
  601. if (cd64->using_ppa) {
  602. ret = ioperm(cd64->port, 3, 1);
  603. }
  604. else {
  605. ret = ioperm(cd64->port, 1, 1);
  606. ret |= ioperm(cd64->port+2, 1, 1);
  607. }
  608. if (ret == -1) {
  609. cd64->notice_callback2("ioperm: %s", strerror(errno));
  610. cd64->notice_callback2("rawio requires CAP_SYS_RAWIO capability");
  611. return 0;
  612. }
  613. }
  614. else {
  615. ret = iopl(3);
  616. if (ret == -1) {
  617. cd64->notice_callback2("iopl: %s", strerror(errno));
  618. cd64->notice_callback2("rawio requires CAP_SYS_RAWIO capability");
  619. return 0;
  620. }
  621. }
  622. #elif defined __OpenBSD__
  623. /* I cannot test i386_set_ioperm(), so I only use i386_iopl() */
  624. ret = i386_iopl(3);
  625. if (ret == -1) {
  626. cd64->notice_callback2("i386_iopl: %s", strerror(errno));
  627. return 0;
  628. }
  629. #elif defined __FreeBSD__
  630. cd64->portdevfd = open("/dev/io", O_RDWR);
  631. if (cd64->portdevfd == -1) {
  632. cd64->portdevfd = 0;
  633. cd64->notice_callback2("open: %s", strerror(errno));
  634. cd64->notice_callback2("Could not open I/O port device (/dev/io)");
  635. return 0;
  636. }
  637. #elif defined __BEOS__
  638. io_portfd = open("/dev/misc/ioport", O_RDWR | O_NONBLOCK);
  639. if (io_portfd == -1) {
  640. io_portfd = 0;
  641. cd64->notice_callback2("open: %s", strerror(errno));
  642. cd64->notice_callback2("Could not open I/O port device (no driver)");
  643. exit(1);
  644. }
  645. #elif defined _WIN32 || defined __CYGWIN__
  646. {
  647. char fname[FILENAME_MAX];
  648. io_driver_found = 0;
  649. if (!cd64->io_driver_dir[0]) strcpy(cd64->io_driver_dir, ".");
  650. snprintf (fname, FILENAME_MAX, "%s" FILE_SEPARATOR_S "%s",
  651. cd64->io_driver_dir, "dlportio.dll");
  652. if (access(fname, F_OK) == 0) {
  653. io_driver = open_module(fname, cd64);
  654. io_driver_found = 1;
  655. DlPortReadPortUchar = (unsigned char (__stdcall *) (unsigned long))
  656. get_symbol(io_driver, "DlPortReadPortUchar", cd64);
  657. DlPortWritePortUchar = (void (__stdcall *) (unsigned long, unsigned char))
  658. get_symbol(io_driver, "DlPortWritePortUchar", cd64);
  659. input_byte = dlportio_input_byte;
  660. output_byte = dlportio_output_byte;
  661. }
  662. if (!io_driver_found) {
  663. snprintf (fname, FILENAME_MAX, "%s" FILE_SEPARATOR_S "%s",
  664. cd64->io_driver_dir, "io.dll");
  665. if (access(fname, F_OK) == 0) {
  666. io_driver = open_module(fname, cd64);
  667. IsDriverInstalled = (short int (WINAPI *) ())
  668. get_symbol(io_driver, "IsDriverInstalled", cd64);
  669. if (IsDriverInstalled()) {
  670. io_driver_found = 1;
  671. PortIn = (char (WINAPI *) (short int))
  672. get_symbol(io_driver, "PortIn", cd64);
  673. PortOut = (void (WINAPI *) (short int, char))
  674. get_symbol(io_driver, "PortOut", cd64);
  675. input_byte = io_input_byte;
  676. output_byte = io_output_byte;
  677. }
  678. }
  679. }
  680. }
  681. {
  682. /* __try and __except are not supported by MinGW and Cygwin. MinGW has
  683. * __try1 and __except1, but using them requires more code than we
  684. * currently have. Cygwin does something stupid which breaks
  685. * SetUnhandledExceptionFilter()... */
  686. #ifdef __CYGWIN__ /* Cygwin */
  687. exception_list list;
  688. exception_handler *org_handler;
  689. cygwin_internal(CW_INIT_EXCEPTIONS, &list);
  690. org_handler = list.handler;
  691. list.handler = new_exception_handler;
  692. input_byte(0x378);
  693. list.handler = org_handler;
  694. #elif defined _WIN32 /* MinGW & Visual C++ */
  695. LPTOP_LEVEL_EXCEPTION_FILTER org_exception_filter =
  696. SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) new_exception_filter);
  697. input_byte(0x378); /* 0x378 is okay */
  698. /* if we get here accessing I/O port 0x378 did not cause an exception */
  699. SetUnhandledExceptionFilter(org_exception_filter);
  700. #endif
  701. }
  702. #endif /* _WIN32 || __CYGWIN__ */
  703. return 1;
  704. }
  705. int cd64_close_rawio(struct cd64_t *cd64) {
  706. int ret;
  707. (void) ret;
  708. (void) cd64;
  709. #ifdef __linux__
  710. if (cd64->port < 0x3fd) {
  711. if (cd64->using_ppa) {
  712. ret = ioperm(cd64->port, 3, 0);
  713. }
  714. else {
  715. ret = ioperm(cd64->port, 1, 0);
  716. ret |= ioperm(cd64->port+2, 1, 0);
  717. }
  718. if (ret == -1) {
  719. cd64->notice_callback2("ioperm: %s", strerror(errno));
  720. return 0;
  721. }
  722. }
  723. else {
  724. ret = iopl(0);
  725. if (ret == -1) {
  726. cd64->notice_callback2("iopl: %s", strerror(errno));
  727. return 0;
  728. }
  729. }
  730. #elif defined __OpenBSD__
  731. /* I cannot test i386_set_ioperm(), so I only use i386_iopl() */
  732. ret = i386_iopl(0);
  733. if (ret == -1) {
  734. cd64->notice_callback2("i386_iopl: %s", strerror(errno));
  735. return 0;
  736. }
  737. #elif defined __FreeBSD__
  738. if (close(cd64->portdevfd) == -1) {
  739. cd64->notice_callback2("close: %s", strerror(errno));
  740. return 0;
  741. }
  742. cd64->portdevfd = 0;
  743. #elif defined __BEOS__
  744. if (close(io_portfd) == -1) {
  745. cd64->notice_callback2("close: %s", strerror(errno));
  746. return 0;
  747. }
  748. io_portfd = 0;
  749. #elif defined _WIN32 || defined __CYGWIN__
  750. close_module(io_driver, cd64);
  751. io_driver = NULL;
  752. io_driver_found = 0;
  753. input_byte = inb;
  754. output_byte = outb;
  755. #endif
  756. return 1;
  757. }
  758. static INLINE int cd64_wait_rawio(struct cd64_t *cd64) {
  759. int i = 0;
  760. int reset_tries = 0;
  761. uint8_t status;
  762. int dir;
  763. i = 0;
  764. if (cd64->using_ppa) {
  765. status = inb((uint16_t) (cd64->port+1));
  766. while(status & 0x80) {
  767. i++;
  768. if (i >= BUSY_THRESHOLD) {
  769. /* The PPA is in a weird state.
  770. * Try to knock some sense into it. */
  771. dir = 1;
  772. status = 0x06 | (dir << 5);
  773. outb(status, (uint16_t) (cd64->port+2));
  774. dir = 0;
  775. status = 0x04 | (dir << 5);
  776. outb(status, (uint16_t) (cd64->port+2));
  777. status = 0x05 | (dir << 5);
  778. outb(status, (uint16_t) (cd64->port+2));
  779. status = 0x04 | (dir << 5);
  780. outb(status, (uint16_t) (cd64->port+2));
  781. reset_tries++;
  782. i = 0;
  783. USLEEP(1);
  784. }
  785. if (cd64->abort) return 0;
  786. if (reset_tries > MAX_TRIES) {
  787. break;
  788. }
  789. status = inb((uint16_t) (cd64->port+1));
  790. }
  791. }
  792. else { /* Comms link */
  793. status = inb((uint16_t) (cd64->port+2));
  794. while (status & 1) {
  795. /* Do we need to handle a stuck situation here? */
  796. status = inb((uint16_t) (cd64->port+2));
  797. }
  798. }
  799. return (reset_tries < MAX_TRIES);
  800. }
  801. int cd64_xfer_rawio(struct cd64_t *cd64, uint8_t *wr, uint8_t *rd, int delayms) {
  802. uint8_t ctl;
  803. int dir;
  804. if (cd64->using_ppa) {
  805. if (!cd64_wait_rawio(cd64)) { return 0; }
  806. if (delayms) USLEEP(delayms);
  807. dir = 1;
  808. ctl = 0x06 | (dir << 5);
  809. outb(ctl, (uint16_t) (cd64->port+2));
  810. if (delayms) USLEEP(delayms);
  811. if (rd) {
  812. *rd = inb((uint16_t) cd64->port);
  813. #if DEBUG_LOWLEVEL
  814. printf("got %xh", *rd);
  815. if (*rd > 0x20) printf(" (%c)", *rd);
  816. printf("\n");
  817. #endif
  818. }
  819. if (delayms) USLEEP(delayms);
  820. dir = 0;
  821. ctl = 0x04 | (dir << 5);
  822. outb(ctl, (uint16_t) (cd64->port+2));
  823. if (delayms) USLEEP(delayms);
  824. if (wr) {
  825. outb(*wr, (uint16_t) cd64->port);
  826. #if DEBUG_LOWLEVEL
  827. printf("put %xh", *wr);
  828. if (*wr > 0x20) printf(" (%c)", *wr);
  829. printf("\n");
  830. #endif
  831. }
  832. if (delayms) USLEEP(delayms);
  833. ctl = 0x05 | (dir << 5);
  834. outb(ctl, (uint16_t) (cd64->port+2));
  835. if (delayms) USLEEP(delayms);
  836. ctl = 0x04 | (dir << 5);
  837. outb(ctl, (uint16_t) (cd64->port+2));
  838. }
  839. else { /* Comms link */
  840. outb(*wr, (uint16_t) cd64->port);
  841. if (!cd64_wait_rawio(cd64)) { return 0; }
  842. *rd = inb((uint16_t) cd64->port);
  843. }
  844. return 1;
  845. }
  846. #endif