fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 619 lines 11 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/drivers/char/char.c * 7 * Created: 2009-03-06 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2009-2020 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <config.h> 24 25#include <stdlib.h> 26#include <string.h> 27 28#include <drivers/options.h> 29#include <drivers/char/char.h> 30 31 32struct driver_list { 33 struct driver_list *next; 34 const char *name; 35 chr_open_f open; 36}; 37 38struct driver_tab { 39 const char *name; 40 chr_open_f open; 41}; 42 43 44char_drv_t *chr_mouse_open (const char *name); 45char_drv_t *chr_null_open (const char *name); 46char_drv_t *chr_posix_open (const char *name); 47char_drv_t *chr_ppp_open (const char *name); 48char_drv_t *chr_pty_open (const char *name); 49char_drv_t *chr_slip_open (const char *name); 50char_drv_t *chr_stdio_open (const char *name); 51char_drv_t *chr_tcp_open (const char *name); 52char_drv_t *chr_tios_open (const char *name); 53char_drv_t *chr_wincom_open (const char *name); 54 55 56static struct driver_list *drivers = NULL; 57 58 59static struct driver_tab default_drivers[] = { 60#ifdef PCE_ENABLE_CHAR_POSIX 61 { "posix", chr_posix_open }, 62 { "sercon", chr_posix_open }, 63#endif 64#ifdef PCE_ENABLE_CHAR_PPP 65 { "ppp", chr_ppp_open }, 66#endif 67#ifdef PCE_ENABLE_CHAR_PTY 68 { "pty", chr_pty_open }, 69#endif 70#ifdef PCE_ENABLE_CHAR_SLIP 71 { "slip", chr_slip_open }, 72#endif 73#ifdef PCE_ENABLE_CHAR_TCP 74 { "tcp", chr_tcp_open }, 75#endif 76#ifdef PCE_ENABLE_CHAR_TIOS 77 { "tios", chr_tios_open }, 78#endif 79#ifdef PCE_ENABLE_CHAR_WINCOM 80 { "wincom", chr_wincom_open }, 81#endif 82 { "stdio", chr_stdio_open }, 83 { "mouse", chr_mouse_open }, 84 { "null", chr_null_open } 85}; 86 87 88static 89void chr_log_bytes (char_drv_t *cdrv, int out, const unsigned char *buf, unsigned cnt) 90{ 91 int c; 92 unsigned i, n; 93 94 while (cnt > 0) { 95 n = (cnt < 16) ? cnt : 16; 96 97 fprintf (cdrv->log_fp, "%s %02X", out ? "->" : "<-", *buf); 98 99 for (i = 1; i < n; i++) { 100 fprintf (cdrv->log_fp, " %02X", buf[i]); 101 } 102 103 for (i = n; i < 16; i++) { 104 fputs (" ", cdrv->log_fp); 105 } 106 107 fputs (" ", cdrv->log_fp); 108 109 for (i = 0; i < n; i++) { 110 c = buf[i]; 111 112 if ((c < 0x20) || (c > 0x7e)) { 113 c = '.'; 114 } 115 116 fputc (c, cdrv->log_fp); 117 } 118 119 fputs ("\n", cdrv->log_fp); 120 121 buf += n; 122 cnt -= n; 123 } 124 125 fflush (cdrv->log_fp); 126} 127 128static 129void chr_log_flush (char_drv_t *cdrv) 130{ 131 if (cdrv->log_cnt > 0) { 132 chr_log_bytes (cdrv, cdrv->log_out, cdrv->log_buf, cdrv->log_cnt); 133 } 134 135 cdrv->log_cnt = 0; 136 cdrv->log_out = 0; 137} 138 139static 140void chr_log_data (char_drv_t *cdrv, int out, const unsigned char *buf, unsigned cnt) 141{ 142 unsigned n; 143 144 if (cdrv->log_fp == NULL) { 145 return; 146 } 147 148 if (cnt == 0) { 149 return; 150 } 151 152 if ((cdrv->log_cnt > 0) && (cdrv->log_out != out)) { 153 chr_log_flush (cdrv); 154 } 155 156 while (cnt > 0) { 157 n = 16 - cdrv->log_cnt; 158 159 if (cnt < n) { 160 n = cnt; 161 } 162 163 memcpy (cdrv->log_buf + cdrv->log_cnt, buf, n); 164 165 cdrv->log_cnt += n; 166 cdrv->log_out = out; 167 168 if (cdrv->log_cnt >= 16) { 169 chr_log_flush (cdrv); 170 } 171 172 buf += n; 173 cnt -= n; 174 } 175} 176 177static 178void chr_log_params (char_drv_t *cdrv) 179{ 180 const char *par; 181 182 if (cdrv->log_fp == NULL) { 183 return; 184 } 185 186 chr_log_flush (cdrv); 187 188 switch (cdrv->parity) { 189 case 0: 190 par = "N"; 191 break; 192 193 case 1: 194 par = "O"; 195 break; 196 197 case 2: 198 par = "E"; 199 break; 200 201 default: 202 par = "?"; 203 break; 204 } 205 206 fprintf (cdrv->log_fp, "-- %lu %u%s%u\n", 207 cdrv->bps, cdrv->bpc, par, cdrv->stop 208 ); 209 210 fflush (cdrv->log_fp); 211} 212 213static 214void chr_log_signal (char_drv_t *cdrv, const char *name, unsigned msk, unsigned old, unsigned new) 215{ 216 if ((old ^ new) & msk) { 217 fprintf (cdrv->log_fp, "-- %s=%d\n", name, (new & msk) != 0); 218 } 219} 220 221static 222void chr_log_ctl (char_drv_t *cdrv, unsigned old, unsigned new) 223{ 224 if ((cdrv->log_fp == NULL) || (old == new)) { 225 return; 226 } 227 228 chr_log_flush (cdrv); 229 230 chr_log_signal (cdrv, "CTS", PCE_CHAR_CTS, old, new); 231 chr_log_signal (cdrv, "DTR", PCE_CHAR_DTR, old, new); 232 chr_log_signal (cdrv, "RTS", PCE_CHAR_RTS, old, new); 233 chr_log_signal (cdrv, "DSR", PCE_CHAR_DSR, old, new); 234 chr_log_signal (cdrv, "CD", PCE_CHAR_CD, old, new); 235 chr_log_signal (cdrv, "RI", PCE_CHAR_RI, old, new); 236} 237 238static 239void chr_cap_data (char_drv_t *cdrv, const unsigned char *buf, unsigned cnt) 240{ 241 if (cdrv->cap_fp == NULL) { 242 return; 243 } 244 245 if (cnt == 0) { 246 return; 247 } 248 249 fwrite (buf, 1, cnt, cdrv->cap_fp); 250 fflush (cdrv->cap_fp); 251} 252 253void chr_init (char_drv_t *cdrv, void *ext) 254{ 255 cdrv->ext = ext; 256 257 cdrv->bps = 0; 258 cdrv->bpc = 0; 259 cdrv->parity = 0; 260 cdrv->stop = 0; 261 262 cdrv->ctl_inp = 0; 263 cdrv->ctl_out = 0; 264 265 cdrv->log_cnt = 0; 266 cdrv->log_out = 0; 267 cdrv->log_fp = NULL; 268 269 cdrv->cap_fp = NULL; 270 271 cdrv->close = NULL; 272 273 cdrv->read = NULL; 274 cdrv->write = NULL; 275 276 cdrv->get_ctl = NULL; 277 cdrv->set_ctl = NULL; 278 279 cdrv->set_params = NULL; 280} 281 282static 283int chr_match_name (struct driver_list *lst, const char *name) 284{ 285 const char *s, *d; 286 287 s = name; 288 d = lst->name; 289 290 while ((*d != 0) && (*d == *s)) { 291 d += 1; 292 s += 1; 293 } 294 295 if ((*d == 0) && ((*s == ':') || (*s == 0))) { 296 return (1); 297 } 298 299 return (0); 300} 301 302static 303char_drv_t *chr_open_cdrv (char_drv_t *cdrv, const char *name) 304{ 305 char *str; 306 307 if (cdrv == NULL) { 308 return (NULL); 309 } 310 311 str = drv_get_option (name, "log"); 312 313 if (str != NULL) { 314 chr_set_log (cdrv, str); 315 316 free (str); 317 } 318 319 str = drv_get_option (name, "cap"); 320 321 if (str != NULL) { 322 chr_set_cap (cdrv, str); 323 free (str); 324 } 325 326 return (cdrv); 327} 328 329char_drv_t *chr_open (const char *name) 330{ 331 struct driver_list *lst; 332 333 if (drivers == NULL) { 334 /* 335 * If no drivers have been registered yet, register the 336 * default set. 337 */ 338 chr_register_default(); 339 } 340 341 lst = drivers; 342 343 while (lst != NULL) { 344 if (chr_match_name (lst, name)) { 345 return (chr_open_cdrv (lst->open (name), name)); 346 } 347 348 lst = lst->next; 349 } 350 351 return (NULL); 352} 353 354void chr_close (char_drv_t *cdrv) 355{ 356 if (cdrv == NULL) { 357 return; 358 } 359 360 if (cdrv->cap_fp != NULL) { 361 fclose (cdrv->cap_fp); 362 } 363 364 if (cdrv->log_fp != NULL) { 365 chr_log_flush (cdrv); 366 fclose (cdrv->log_fp); 367 } 368 369 if (cdrv->close == NULL) { 370 return; 371 } 372 373 cdrv->close (cdrv); 374} 375 376int chr_register (const char *name, chr_open_f open) 377{ 378 struct driver_list *lst; 379 380 if ((lst = malloc (sizeof (struct driver_list))) == NULL) { 381 return (1); 382 } 383 384 lst->next = drivers; 385 lst->name = name; 386 lst->open = open; 387 388 drivers = lst; 389 390 return (0); 391} 392 393int chr_unregister (const char *name) 394{ 395 int r; 396 struct driver_list *src, *dst, *drv, *next; 397 398 r = 1; 399 400 src = drivers; 401 dst = NULL; 402 drv = NULL; 403 404 while (src != NULL) { 405 next = src->next; 406 407 if ((name == NULL) || (strcmp (src->name, name) == 0)) { 408 free (src); 409 r = 0; 410 } 411 else { 412 if (dst != NULL) { 413 dst->next = src; 414 } 415 else { 416 drv = src; 417 } 418 419 dst = src; 420 } 421 422 src = next; 423 } 424 425 if (dst != NULL) { 426 dst->next = NULL; 427 } 428 429 drivers = drv; 430 431 return (r); 432} 433 434int chr_register_default (void) 435{ 436 int r; 437 unsigned i, n; 438 439 r = 0; 440 n = sizeof (default_drivers) / sizeof (struct driver_tab); 441 442 for (i = 0; i < n; i++) { 443 r |= chr_register (default_drivers[i].name, default_drivers[i].open); 444 } 445 446 return (r); 447} 448 449unsigned chr_read (char_drv_t *cdrv, void *buf, unsigned cnt) 450{ 451 unsigned ret; 452 453 if ((cdrv == NULL) || (cdrv->read == NULL)) { 454 return (0); 455 } 456 457 ret = cdrv->read (cdrv, buf, cnt); 458 459 chr_log_data (cdrv, 0, buf, ret); 460 461 return (ret); 462} 463 464unsigned chr_write (char_drv_t *cdrv, const void *buf, unsigned cnt) 465{ 466 unsigned ret; 467 468 if ((cdrv == NULL) || (cdrv->write == NULL)) { 469 return (cnt); 470 } 471 472 ret = cdrv->write (cdrv, buf, cnt); 473 474 if (cdrv->cap_fp != NULL) { 475 chr_cap_data (cdrv, buf, ret); 476 } 477 478 chr_log_data (cdrv, 1, buf, ret); 479 480 return (ret); 481} 482 483int chr_get_ctl (char_drv_t *cdrv, unsigned *ctl) 484{ 485 if (cdrv == NULL) { 486 return (1); 487 } 488 489 if (cdrv->get_ctl == NULL) { 490 *ctl = PCE_CHAR_CD; 491 492 if (cdrv->ctl_out & PCE_CHAR_DTR) { 493 *ctl |= PCE_CHAR_DSR; 494 } 495 496 if (cdrv->ctl_out & PCE_CHAR_RTS) { 497 *ctl |= PCE_CHAR_CTS; 498 } 499 } 500 else { 501 if (cdrv->get_ctl (cdrv, ctl)) { 502 return (1); 503 } 504 } 505 506 chr_log_ctl (cdrv, cdrv->ctl_inp, *ctl); 507 508 cdrv->ctl_inp = *ctl; 509 510 return (0); 511} 512 513int chr_set_ctl (char_drv_t *cdrv, unsigned ctl) 514{ 515 if (cdrv == NULL) { 516 return (1); 517 } 518 519 if (cdrv->ctl_out == ctl) { 520 return (0); 521 } 522 523 chr_log_ctl (cdrv, cdrv->ctl_out, ctl); 524 525 cdrv->ctl_out = ctl; 526 527 if (cdrv->set_ctl == NULL) { 528 return (0); 529 } 530 531 return (cdrv->set_ctl (cdrv, ctl)); 532} 533 534static 535int chr_check_params (char_drv_t *cdrv, unsigned long bps, unsigned bpc, unsigned parity, unsigned stop) 536{ 537 if (cdrv->bps != bps) { 538 return (0); 539 } 540 541 if (cdrv->bpc != bpc) { 542 return (0); 543 } 544 545 if (cdrv->parity != parity) { 546 return (0); 547 } 548 549 if (cdrv->stop != stop) { 550 return (0); 551 } 552 553 return (1); 554} 555 556int chr_set_params (char_drv_t *cdrv, unsigned long bps, unsigned bpc, unsigned parity, unsigned stop) 557{ 558 if (cdrv == NULL) { 559 return (1); 560 } 561 562 if (chr_check_params (cdrv, bps, bpc, parity, stop)) { 563 return (0); 564 } 565 566 cdrv->bps = bps; 567 cdrv->bpc = bpc; 568 cdrv->parity = parity; 569 cdrv->stop = stop; 570 571 chr_log_params (cdrv); 572 573 if (cdrv->set_params == NULL) { 574 return (1); 575 } 576 577 return (cdrv->set_params (cdrv, bps, bpc, parity, stop)); 578} 579 580FILE *chr_open_file (const char *name, const char *mode, const char *modeapp) 581{ 582 if (name == NULL) { 583 return (NULL); 584 } 585 586 if (*name == '@') { 587 name += 1; 588 return (fopen (name, modeapp)); 589 } 590 591 return (fopen (name, mode)); 592} 593 594int chr_set_log (char_drv_t *cdrv, const char *fname) 595{ 596 if (cdrv->log_fp != NULL) { 597 chr_log_flush (cdrv); 598 fclose (cdrv->log_fp); 599 } 600 601 if ((cdrv->log_fp = chr_open_file (fname, "w", "a")) == NULL) { 602 return (1); 603 } 604 605 return (0); 606} 607 608int chr_set_cap (char_drv_t *cdrv, const char *fname) 609{ 610 if (cdrv->cap_fp != NULL) { 611 fclose (cdrv->cap_fp); 612 } 613 614 if ((cdrv->cap_fp = chr_open_file (fname, "wb", "ab")) == NULL) { 615 return (1); 616 } 617 618 return (0); 619}