fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 262 lines 5.2 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/macplus/serial.c * 7 * Created: 2007-12-19 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2007-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 "main.h" 24#include "serial.h" 25 26#include <stdlib.h> 27 28#include <chipset/e8530.h> 29#include <drivers/char/char.h> 30 31#include <lib/string.h> 32 33 34void mac_ser_init (mac_ser_t *ser) 35{ 36 ser->scc = NULL; 37 ser->chn = 0; 38 39 ser->bps = 0; 40 ser->bpc = 0; 41 ser->stop = 0; 42 ser->parity = 0; 43 44 ser->dtr = 0; 45 ser->rts = 0; 46 47 ser->inp_idx = 0; 48 ser->inp_cnt = 0; 49 50 ser->out_idx = 0; 51 ser->out_cnt = 0; 52 53 ser->cdrv = NULL; 54} 55 56void mac_ser_free (mac_ser_t *ser) 57{ 58 chr_close (ser->cdrv); 59} 60 61static 62void mac_ser_flush_output (mac_ser_t *ser) 63{ 64 unsigned cnt; 65 66 if (ser->out_cnt == 0) { 67 return; 68 } 69 70 cnt = chr_write (ser->cdrv, ser->out_buf + ser->out_idx, ser->out_cnt); 71 72 ser->out_idx += cnt; 73 ser->out_cnt -= cnt; 74 75 if (ser->out_cnt == 0) { 76 ser->out_idx = 0; 77 } 78} 79 80static 81void mac_ser_process_output (mac_ser_t *ser) 82{ 83 mac_ser_flush_output (ser); 84 85 if (ser->out_cnt > 0) { 86 return; 87 } 88 89 while (1) { 90 if (e8530_out_empty (ser->scc, ser->chn)) { 91 mac_ser_flush_output (ser); 92 break; 93 } 94 95 ser->out_buf[ser->out_idx + ser->out_cnt] = e8530_send (ser->scc, ser->chn); 96 ser->out_cnt += 1; 97 98 if ((ser->out_idx + ser->out_cnt) >= MAC_SER_BUF) { 99 mac_ser_flush_output (ser); 100 101 if (ser->out_cnt > 0) { 102 break; 103 } 104 } 105 } 106} 107 108static 109void mac_ser_fill_input (mac_ser_t *ser) 110{ 111 unsigned idx, cnt; 112 113 if (ser->inp_cnt == 0) { 114 ser->inp_idx = 0; 115 } 116 117 idx = ser->inp_idx + ser->inp_cnt; 118 cnt = MAC_SER_BUF - idx; 119 120 if (cnt == 0) { 121 return; 122 } 123 124 cnt = chr_read (ser->cdrv, ser->inp_buf + idx, cnt); 125 126 ser->inp_cnt += cnt; 127} 128 129static 130void mac_ser_process_input (mac_ser_t *ser) 131{ 132 while (e8530_inp_full (ser->scc, ser->chn) == 0) { 133 if (ser->inp_cnt == 0) { 134 mac_ser_fill_input (ser); 135 136 } 137 138 if (ser->inp_cnt == 0) { 139 break; 140 } 141 142 e8530_receive (ser->scc, ser->chn, ser->inp_buf[ser->inp_idx]); 143 144 ser->inp_idx += 1; 145 ser->inp_cnt -= 1; 146 } 147} 148 149static 150void mac_ser_status_check (mac_ser_t *ser) 151{ 152 e8530_set_cts (ser->scc, ser->chn, 1); 153} 154 155static 156void mac_ser_set_rts (void *ext, unsigned char val) 157{ 158 unsigned ctl; 159 mac_ser_t *ser; 160 161 ser = ext; 162 163 if (ser->rts == val) { 164 return; 165 } 166 167#ifdef DEBUG_SERIAL 168 mac_log_deb ("serial %u: RTS=%d\n", ser->chn, val); 169#endif 170 171 ser->rts = (val != 0); 172 173 ctl = PCE_CHAR_DTR; 174 ctl |= (ser->rts ? PCE_CHAR_RTS : 0); 175 176 chr_set_ctl (ser->cdrv, val); 177} 178 179static 180void mac_ser_set_comm (void *ext, unsigned long bps, unsigned parity, unsigned bpc, unsigned stop) 181{ 182 mac_ser_t *ser; 183 184 ser = ext; 185 186 stop = stop / 2; 187 188 ser->bps = bps; 189 ser->parity = parity; 190 ser->bpc = bpc; 191 ser->stop = stop; 192 193#ifdef DEBUG_SERIAL 194 mac_log_deb ("serial %u: setup (%lu/%u/%u%u)\n", ser->chn, 195 ser->bps, ser->bpc, ser->parity, ser->stop 196 ); 197#endif 198 199 chr_set_params (ser->cdrv, bps, bpc, parity, stop); 200} 201 202int mac_ser_set_driver (mac_ser_t *ser, const char *name) 203{ 204 if (ser->cdrv != NULL) { 205 chr_close (ser->cdrv); 206 } 207 208 ser->cdrv = chr_open (name); 209 210 if (ser->cdrv == NULL) { 211 return (1); 212 } 213 214 return (0); 215} 216 217int mac_ser_set_file (mac_ser_t *ser, const char *fname) 218{ 219 int r; 220 char *driver; 221 222 driver = str_cat_alloc ("stdio:file=", fname); 223 224 r = mac_ser_set_driver (ser, driver); 225 226 free (driver); 227 228 return (r); 229} 230 231static 232void mac_ser_set_inp (void *ext, unsigned char val) 233{ 234 mac_ser_process_input (ext); 235} 236 237static 238void mac_ser_set_out (void *ext, unsigned char val) 239{ 240 mac_ser_process_output (ext); 241} 242 243 244void mac_ser_set_scc (mac_ser_t *ser, e8530_t *scc, unsigned chn) 245{ 246 ser->scc = scc; 247 ser->chn = chn; 248 249 e8530_set_inp_fct (scc, chn, ser, mac_ser_set_inp); 250 e8530_set_out_fct (scc, chn, ser, mac_ser_set_out); 251 e8530_set_rts_fct (scc, chn, ser, mac_ser_set_rts); 252 e8530_set_comm_fct (scc, chn, ser, mac_ser_set_comm); 253 254 e8530_set_cts (ser->scc, ser->chn, 1); 255} 256 257void mac_ser_process (mac_ser_t *ser) 258{ 259 mac_ser_process_output (ser); 260 mac_ser_process_input (ser); 261 mac_ser_status_check (ser); 262}