1 /* pro_com.c: communication port
2
3 Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4
5 This file is part of Xhomer.
6
7 Xhomer is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2
9 as published by the Free Software Foundation.
10
11 Xhomer is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Xhomer; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22 /* TBD:
23 -do global mask for odd byte writes
24 -receive character
25 check RIE
26 -int on modem line change
27 -finish implementing commands
28 -get line controls
29 break
30 parity error
31 -sync modes are not implemented
32 -assumes 16x clock
33 -transmitter character length is ignored and
34 assumed to be the same as for the receiver
35 -parity bit is not present as msb data for <8-bit formats
36 */
37
38 #ifdef PRO
39 #include "pdp11_defs.h"
40
41
42 LOCAL int pro_com_a_wr0; /* control register A WR0 */
43 LOCAL int pro_com_a_wr1; /* control register A WR1 */
44 LOCAL int pro_com_a_wr2; /* control register A WR2 */
45 LOCAL int pro_com_a_wr3; /* control register A WR3 */
46 LOCAL int pro_com_a_wr4; /* control register A WR4 */
47 LOCAL int pro_com_a_wr5; /* control register A WR5 */
48 LOCAL int pro_com_a_wr6; /* control register A WR6 */
49 LOCAL int pro_com_a_wr7; /* control register A WR7 */
50 LOCAL int pro_com_a_rr0; /* status register A RR0 */
51 LOCAL int pro_com_a_rr1; /* status register A RR1 */
52 LOCAL int pro_com_a_rr2; /* status register A RR2 */
53 LOCAL int pro_com_b_wr0; /* control register B WR0 */
54 LOCAL int pro_com_b_wr1; /* control register B WR1 */
55 LOCAL int pro_com_b_wr2; /* control register B WR2 */
56 LOCAL int pro_com_mcr0; /* modem control register 0 */
57 LOCAL int pro_com_mcr1; /* modem control register 1 */
58 LOCAL int pro_com_baud; /* baud rates */
59 LOCAL int pro_com_wdata; /* write data */
60
61 LOCAL int pro_com_dataq[PRO_COM_DATAQ_DEPTH+1]; /* read data queue */
62 LOCAL int pro_com_dataq_h; /* head of queue */
63 LOCAL int pro_com_dataq_t; /* tail of queue */
64
65 LOCAL int pro_com_intq[PRO_COM_INTQ_DEPTH+1]; /* pending interrupt queue */
66 LOCAL int pro_com_intq_h; /* head of queue */
67 LOCAL int pro_com_intq_t; /* tail of queue */
68
69 struct serctrl pro_com_ctrl; /* Stores line control parameters */
70
71
pro_com_ctrl_get()72 LOCAL void pro_com_ctrl_get ()
73 {
74 pro_com->ctrl_get(PRO_SER_COM, &pro_com_ctrl);
75
76 pro_com_mcr1 &= ~(PRO_COM_DSR | PRO_COM_RI | PRO_COM_CTS | PRO_COM_CD);
77 pro_com_mcr1 |= pro_com_ctrl.dsr ? PRO_COM_DSR : 0;
78 pro_com_mcr1 |= pro_com_ctrl.ri ? PRO_COM_RI : 0;
79 pro_com_mcr1 |= pro_com_ctrl.cts ? PRO_COM_CTS : 0;
80 pro_com_mcr1 |= pro_com_ctrl.cd ? PRO_COM_CD : 0;
81 }
82
83
pro_com_ctrl_put()84 LOCAL void pro_com_ctrl_put ()
85 {
86 pro_com_ctrl.cs = (pro_com_a_wr3 & PRO_COM_RCL1) >> 7
87 | (pro_com_a_wr3 & PRO_COM_RCL0) >> 5;
88 pro_com_ctrl.stop = (pro_com_a_wr4 & PRO_COM_SB) >> 2;
89 pro_com_ctrl.parity = (pro_com_a_wr4 & PRO_COM_EO) >> 1;
90 pro_com_ctrl.penable = pro_com_a_wr4 & PRO_COM_PEN;
91 pro_com_ctrl.ibaud = pro_com_baud & PRO_COM_RBR;
92 pro_com_ctrl.obaud = (pro_com_baud & PRO_COM_TBR) >> 4;
93 pro_com_ctrl.dtr = (pro_com_mcr0 & PRO_COM_DTR) >> 4;
94 pro_com_ctrl.rts = (pro_com_mcr0 & PRO_COM_RTS) >> 3;
95 pro_com_ctrl.obrk = (pro_com_a_wr5 & PRO_COM_SBRK) >> 4;
96
97 /* XXX Update serial line parameters only if they changed */
98
99 pro_com->ctrl_put(PRO_SER_COM, &pro_com_ctrl);
100 }
101
102
103 /* Queue new received character */
104
pro_com_qdata(int data)105 LOCAL void pro_com_qdata (int data)
106 {
107 /* Add character at tail of queue */
108
109 pro_com_dataq[pro_com_dataq_t] = data;
110 pro_com_dataq_t++;
111 if (pro_com_dataq_t == (PRO_COM_DATAQ_DEPTH + 1))
112 pro_com_dataq_t = 0;
113
114 /* Set "receive character available" bit */
115
116 pro_com_a_rr0 |= PRO_COM_RXCA;
117 }
118
119
120 /* Queue new interrupt */
121
pro_com_qint(int intnum)122 LOCAL void pro_com_qint (int intnum)
123 {
124 /* Add interrupt at tail of queue */
125
126 pro_com_intq[pro_com_intq_t] = intnum;
127 pro_com_intq_t++;
128 if (pro_com_intq_t == (PRO_COM_INTQ_DEPTH + 1))
129 pro_com_intq_t = 0;
130 }
131
132
133 /* Read poll event handler */
134
pro_com_poll_eq()135 void pro_com_poll_eq ()
136 {
137 int schar;
138
139 /* Only poll if RXCA is cleared, the receiver is enabled,
140 and the communication port is not in maintenance mode */
141
142 if (((pro_com_mcr0 & PRO_COM_MM) == 0)
143 && ((pro_com_a_wr3 & PRO_COM_RXEN) != 0)
144 && ((pro_com_a_rr0 & PRO_COM_RXCA) == 0))
145 {
146 schar = pro_com->get(PRO_SER_COM);
147
148 if (schar != PRO_NOCHAR)
149 {
150 pro_com_qdata(schar);
151
152 /* Set receiver interrupt */
153 /* XXX check if enabled */
154
155 pro_com_qint(PRO_COM_IR_RCV);
156 pro_int_set(PRO_INT_COM);
157 }
158 }
159
160 /* Schedule next polling event */
161
162 pro_eq_sched(PRO_EVENT_COM_POLL, PRO_EQ_COM_POLL);
163 }
164
165
166 /* Write data event handler */
167
pro_com_eq()168 void pro_com_eq ()
169 {
170 /* Queue another write data event if not in maintenance mode
171 and character send failed. Otherwise, complete write
172 data event */
173
174 if ((pro_com_mcr0 & PRO_COM_MM) == 0)
175 {
176 if (pro_com->put(PRO_SER_COM, pro_com_wdata) == PRO_FAIL)
177 {
178 pro_eq_sched(PRO_EVENT_COM, PRO_EQ_COM_RETRY);
179 return;
180 }
181 }
182
183 /* Set "transmit buffer empty" and "all sent bits" */
184
185 pro_com_a_rr0 |= PRO_COM_TBMT;
186 pro_com_a_rr1 |= PRO_COM_AS;
187
188 /* Check if transmitter is enabled */
189
190 if ((pro_com_a_wr5 & PRO_COM_TXEN) != 0)
191 {
192 /* Set transmitter interrupt, if enabled */
193
194 if ((pro_com_a_wr1 & PRO_COM_TIE) != 0)
195 {
196 pro_com_qint(PRO_COM_IR_XMIT);
197 pro_int_set(PRO_INT_COM);
198 }
199
200 /* Check if in maintenance mode */
201
202 if ((pro_com_mcr0 & PRO_COM_MM) != 0)
203 {
204 /* Loop data back to received character queue,
205 if receiver enabled */
206
207 if ((pro_com_a_wr3 & PRO_COM_RXEN) != 0)
208 {
209 pro_com_qdata(pro_com_wdata);
210
211 /* Set receiver interrupt */
212 /* XXX check if enabled */
213
214 pro_com_qint(PRO_COM_IR_RCV);
215 pro_int_set(PRO_INT_COM);
216 }
217 }
218 }
219 }
220
221
222 /* Communication port registers */
223
pro_com_rd(int pa)224 int pro_com_rd (int pa)
225 {
226 int data;
227
228 switch (pa & 017777776)
229 {
230 case 017773300:
231 data = pro_com_dataq[pro_com_dataq_h];
232
233 /* Remove read character from data queue */
234
235 if (pro_com_dataq_h != pro_com_dataq_t)
236 {
237 pro_com_dataq_h++;
238
239 if (pro_com_dataq_h == (PRO_COM_DATAQ_DEPTH + 1))
240 pro_com_dataq_h = 0;
241 }
242
243 /* Clear "receive character available" bit if
244 receiver buffer is empty */
245
246 if (pro_com_dataq_h == pro_com_dataq_t)
247 pro_com_a_rr0 &= ~PRO_COM_RXCA;
248
249 break;
250
251 case 017773302:
252 switch (pro_com_a_wr0 & PRO_COM_RP)
253 {
254 case 00:
255 data = pro_com_a_rr0;
256 break;
257
258 case 01:
259 data = pro_com_a_rr1;
260 break;
261
262 case 02:
263 data = pro_com_a_rr2;
264 break;
265
266 default:
267 data = 0;
268 break;
269 }
270
271 /* Reset register pointer to wr0 */
272
273 pro_com_a_wr0 = pro_com_a_wr0 & ~PRO_COM_RP;
274
275 break;
276
277 case 017773306:
278 if ((pro_com_b_wr0 & PRO_COM_RP) == 02)
279 {
280 /* Report pending interrupt if queue not empty */
281
282 if (pro_com_intq_h != pro_com_intq_t)
283 {
284 data = pro_com_intq[pro_com_intq_h];
285
286 /* Set interrupt pending bit */
287
288 pro_com_a_rr0 |= PRO_COM_INTP;
289 }
290 else
291 data = PRO_COM_IR_NONE;
292
293 /* Or in vector from wr2 */
294
295 data |= (pro_com_b_wr2 & PRO_COM_VEC);
296 }
297 else
298 data = 0;
299
300 /* Reset register pointer to wr0 */
301
302 pro_com_b_wr0 = pro_com_b_wr0 & ~PRO_COM_RP;
303
304 break;
305
306 case 017773310:
307 data = pro_com_mcr0;
308 break;
309
310 case 017773312:
311 /* Get modem control lines */
312
313 pro_com_ctrl_get();
314
315 data = pro_com_mcr1;
316 break;
317
318 /* Write-only */
319
320 case 017773304:
321 case 017773314:
322
323 data = 0;
324 break;
325
326 default:
327 data = 0;
328 break;
329 }
330
331 return data;
332 }
333
pro_com_wr(int data,int pa,int access)334 void pro_com_wr (int data, int pa, int access)
335 {
336 switch (pa & 017777776)
337 {
338 case 017773300:
339 /* Check if transmitter enabled */
340
341 if ((pro_com_a_wr5 & PRO_COM_TXEN) != 0)
342 {
343 /* Store write data for use in event handler */
344
345 WRITE_WB(pro_com_wdata, PRO_COM_W, access);
346
347 /* Clear "transmit buffer empty" and "all sent bits" */
348
349 pro_com_a_rr0 &= ~PRO_COM_TBMT;
350 pro_com_a_rr1 &= ~PRO_COM_AS;
351
352 /* Queue write data event */
353
354 pro_eq_sched(PRO_EVENT_COM, PRO_EQ_COM);
355 }
356
357 break;
358
359 case 017773302:
360 if ((pro_com_a_wr0 & PRO_COM_RP) == 00)
361 {
362 WRITE_WB(pro_com_a_wr0, PRO_COM_W, access);
363
364 /* Decode commands */
365 /* XXX Unfinished */
366
367 switch (pro_com_a_wr0 & PRO_COM_CMD)
368 {
369 case PRO_COM_EOI: /* end of interrupt */
370
371 /* Clear interrupt at head of queue */
372
373 if (pro_com_intq_h != pro_com_intq_t)
374 {
375 pro_com_intq_h++;
376
377 if (pro_com_intq_h == (PRO_COM_INTQ_DEPTH + 1))
378 pro_com_intq_h = 0;
379
380 /* Set new interrupt if queue not empty,
381 otherwise, clear interrupt pending bit */
382
383 if (pro_com_intq_h != pro_com_intq_t)
384 pro_int_set(PRO_INT_COM);
385 else
386 pro_com_a_rr0 &= ~PRO_COM_INTP;
387 }
388 break;
389
390 default:
391 break;
392 }
393 }
394 else
395 {
396 switch (pro_com_a_wr0 & PRO_COM_RP)
397 {
398 case 01:
399 WRITE_WB(pro_com_a_wr1, PRO_COM_W, access);
400 break;
401
402 case 02:
403 WRITE_WB(pro_com_a_wr2, PRO_COM_W, access);
404 break;
405
406 case 03:
407 WRITE_WB(pro_com_a_wr3, PRO_COM_W, access);
408
409 /* Update line parameters */
410
411 pro_com_ctrl_put();
412 break;
413
414 case 04:
415 WRITE_WB(pro_com_a_wr4, PRO_COM_W, access);
416
417 /* Update line parameters */
418
419 pro_com_ctrl_put();
420 break;
421
422 case 05:
423 WRITE_WB(pro_com_a_wr5, PRO_COM_W, access);
424
425 /* Update line parameters */
426
427 pro_com_ctrl_put();
428 break;
429
430 case 06:
431 WRITE_WB(pro_com_a_wr6, PRO_COM_W, access);
432 break;
433
434 case 07:
435 WRITE_WB(pro_com_a_wr7, PRO_COM_W, access);
436 break;
437
438 default:
439 break;
440 }
441
442 /* Reset register pointer to wr0 */
443
444 pro_com_a_wr0 = pro_com_a_wr0 & ~PRO_COM_RP;
445 }
446
447 break;
448
449 case 017773306:
450 if ((pro_com_b_wr0 & PRO_COM_RP) == 00)
451 WRITE_WB(pro_com_b_wr0, PRO_COM_W, access);
452 else
453 {
454 switch (pro_com_b_wr0 & PRO_COM_RP)
455 {
456 case 01:
457 WRITE_WB(pro_com_b_wr1, PRO_COM_W, access);
458 break;
459
460 case 02:
461 WRITE_WB(pro_com_b_wr2, PRO_COM_W, access);
462 break;
463
464 default:
465 break;
466 }
467
468 /* Reset register pointer to wr0 */
469
470 pro_com_b_wr0 = pro_com_b_wr0 & ~PRO_COM_RP;
471 }
472
473 break;
474
475 case 017773310:
476 WRITE_WB(pro_com_mcr0, PRO_COM_W, access);
477 break;
478
479 case 017773314:
480 WRITE_WB(pro_com_baud, PRO_COM_W, access);
481
482 /* Update line parameters */
483
484 pro_com_ctrl_put();
485 break;
486
487 /* Read-only */
488
489 case 017773304:
490 case 017773312:
491
492 break;
493
494 default:
495 break;
496 }
497 }
498
pro_com_reset()499 void pro_com_reset ()
500 {
501 int i;
502
503
504 /* Initialize serial line parameters */
505
506 memset(&pro_com_ctrl, 0, sizeof(pro_com_ctrl));
507
508 pro_com_dataq_h = 0; /* clear data queue */
509 pro_com_dataq_t = 0;
510
511 /* Not necessary, but clean */
512
513 for(i=0; i<PRO_COM_DATAQ_DEPTH; i++)
514 pro_com_dataq[i] = 0;
515
516 pro_com_intq_h = 0; /* clear interrupt queue */
517 pro_com_intq_t = 0;
518
519 /* Not necessary, but clean */
520
521 for(i=0; i<PRO_COM_INTQ_DEPTH; i++)
522 pro_com_intq[i] = 0;
523
524 pro_com_a_wr0 = 0;
525 pro_com_a_wr1 = 0;
526 pro_com_a_wr2 = 0;
527 pro_com_a_wr3 = 0;
528 pro_com_a_wr4 = 0;
529 pro_com_a_wr5 = 0;
530 pro_com_a_wr6 = 0;
531 pro_com_a_wr7 = 0;
532 pro_com_a_rr0 = PRO_COM_TU | PRO_COM_TBMT;
533 pro_com_a_rr1 = PRO_COM_AS;
534 pro_com_a_rr2 = 0;
535 pro_com_b_wr0 = 0;
536 pro_com_b_wr1 = 0;
537 pro_com_b_wr2 = 0; /* also readable as b_rr2 */
538 pro_com_mcr0 = 0;
539 pro_com_mcr1 = 0;
540 pro_com_baud = 0;
541 pro_com_wdata = 0;
542
543 /* Schedule receive character polling event */
544
545 pro_eq_sched(PRO_EVENT_COM_POLL, PRO_EQ_COM_POLL);
546
547 /* Open serial port */
548
549 pro_com_open();
550 }
551
pro_com_open()552 void pro_com_open ()
553 {
554 /* Open serial device */
555
556 pro_com->reset(PRO_SER_COM, pro_com_port);
557
558 /* Set and get serial line parameters */
559
560 pro_com_ctrl_put();
561 pro_com_ctrl_get();
562 }
563
pro_com_exit()564 void pro_com_exit ()
565 {
566 pro_com->exit(PRO_SER_COM);
567 }
568 #endif
569