fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
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}