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