1 /* pro_2661ptr.c: serial port controller (used by ptr & ptr)
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 		-implement reading of line status
24 			break
25 			parity error
26 		-update line parameters only if something changed
27 		-overrun is not implemented.  Is it needed for loopback?
28 		-do global mask for odd byte writes
29 */
30 
31 #ifdef PRO
32 #include "pdp11_defs.h"
33 
34 /* XXX make generic */
35 
36 LOCAL int	pro_2661ptr_data;
37 LOCAL int	pro_2661ptr_wdata;
38 LOCAL int	pro_2661ptr_stat;
39 LOCAL int	pro_2661ptr_mr1;
40 LOCAL int	pro_2661ptr_mr2;
41 LOCAL int	pro_2661ptr_cmd;
42 
43 LOCAL int	pro_2661ptr_mode_ptr;	/* Indicates which mode register is to be accessed */
44 
45 struct serctrl	pro_2661ptr_ctrl;	/* Stores line control parameters */
46 
47 
pro_2661ptr_ctrl_get()48 LOCAL void pro_2661ptr_ctrl_get ()
49 {
50 	pro_ptr->ctrl_get(PRO_SER_PTR, &pro_2661ptr_ctrl);
51 
52 	pro_2661ptr_stat = (pro_2661ptr_stat & ~PRO_2661_DSR);
53 
54 	if (pro_2661ptr_ctrl.dsr == 1)
55 	  pro_2661ptr_stat |= PRO_2661_DSR;
56 }
57 
58 
pro_2661ptr_ctrl_put()59 LOCAL void pro_2661ptr_ctrl_put ()
60 {
61 	pro_2661ptr_ctrl.cs = (pro_2661ptr_mr1 & PRO_2661_CL) >> 2;
62 	pro_2661ptr_ctrl.stop = (pro_2661ptr_mr1 & PRO_2661_SBL) >> 6;
63 	pro_2661ptr_ctrl.parity = (pro_2661ptr_mr1 & PRO_2661_PT) >> 5;
64 	pro_2661ptr_ctrl.penable = (pro_2661ptr_mr1 & PRO_2661_PC) >> 4;
65 	pro_2661ptr_ctrl.ibaud = pro_2661ptr_mr2 & PRO_2661_BAUD;
66 	pro_2661ptr_ctrl.obaud = pro_2661ptr_mr2 & PRO_2661_BAUD;
67 	pro_2661ptr_ctrl.dtr = (pro_2661ptr_cmd & PRO_2661_DTR) >> 1;
68 	pro_2661ptr_ctrl.obrk = (pro_2661ptr_cmd & PRO_2661_FB) >> 3;
69 
70 	/* Hardwire rts */
71 
72 	pro_2661ptr_ctrl.rts = 1;
73 
74 	/* XXX Update serial line parameters only if they changed */
75 
76 	pro_ptr->ctrl_put(PRO_SER_PTR, &pro_2661ptr_ctrl);
77 }
78 
79 
80 /* Polling event queue scheduler */
81 
pro_2661ptr_poll_sched()82 LOCAL void pro_2661ptr_poll_sched ()
83 {
84 	pro_eq_sched(PRO_EVENT_PTR_POLL, PRO_EQ_PTR_POLL);
85 }
86 
87 
88 /* Polling event queue handler */
89 
pro_2661ptr_poll_eq()90 void pro_2661ptr_poll_eq ()
91 {
92 int	schar;
93 
94 	/* Only poll if receiver done is cleared, to avoid overrun */
95 
96 	/* Check if receiver is enabled */
97 
98 	if (((pro_2661ptr_cmd & PRO_2661_OM) == PRO_2661_NORMAL)
99 	   && ((pro_2661ptr_cmd & PRO_2661_RXEN) != 0)
100 	   && ((pro_2661ptr_stat & PRO_2661_RD) == 0))
101 	{
102 	  schar = pro_ptr->get(PRO_SER_PTR);
103 
104 	  if (schar != PRO_NOCHAR)
105 	  {
106 	    /* Copy received character to input buffer */
107 
108 	    pro_2661ptr_data = schar;
109 
110 	    /* Set receiver done bit */
111 
112 	    pro_2661ptr_stat = pro_2661ptr_stat | PRO_2661_RD;
113 
114 	    /* Set receiver interrupt event */
115 
116 	    pro_int_set(PRO_INT_PTR_RCV);
117 	  }
118 	}
119 
120 	/* Schedule next polling event */
121 
122 	pro_2661ptr_poll_sched();
123 }
124 
125 
126 /* Write data event handler */
127 
pro_2661ptr_eq()128 void pro_2661ptr_eq ()
129 {
130 	/* Queue another write data event if in NORMAL mode
131 	   and character send failed.  Otherwise, complete write
132 	   data event */
133 
134 	if ((pro_2661ptr_cmd & PRO_2661_OM) == PRO_2661_NORMAL)
135 	{
136 	  if (pro_ptr->put(PRO_SER_PTR, pro_2661ptr_wdata) == PRO_FAIL)
137 	  {
138 	    pro_eq_sched(PRO_EVENT_PTR, PRO_EQ_PTR_RETRY);
139 	    return;
140 	  }
141 	}
142 
143 	/* Set transmitter ready bit */
144 
145 	pro_2661ptr_stat = pro_2661ptr_stat | PRO_2661_TR;
146 
147 	/* Set transmitter intterrupt */
148 
149 	pro_int_set(PRO_INT_PTR_XMIT);
150 
151 	/* Set receive int+rd if local loopback is enabled */
152 
153 	/* XXX is a delay between xmit and rcv interrupts needed? */
154 
155 	/* XXX does this cause an int+rd if RXEN is disabled? */
156 
157 	/* XXX various bits needed for loopback are not checked */
158 
159 	if ((pro_2661ptr_cmd & PRO_2661_OM) == PRO_2661_LOOPBACK)
160 	{
161 	  /* Loop write data back */
162 
163 	  pro_2661ptr_data = pro_2661ptr_wdata;
164 
165 	  /* Set receiver done bit */
166 
167 	  pro_2661ptr_stat = pro_2661ptr_stat | PRO_2661_RD;
168 
169 	  /* Set receiver interrupt */
170 
171 	  pro_int_set(PRO_INT_PTR_RCV);
172 	}
173 }
174 
175 
176 /* 2661 serial controller registers */
177 
pro_2661ptr_rd(int pa)178 int pro_2661ptr_rd (int pa)
179 {
180 int	data;
181 
182 	switch (pa & 06)
183 	{
184 	  case 00:
185 	    data = pro_2661ptr_data;
186 
187 	    pro_2661ptr_stat = pro_2661ptr_stat & ~PRO_2661_RD; /* clear rec. done bit */
188 
189 	    break;
190 
191 	  case 02:
192 	    /* Get serial line status first */
193 
194 	    pro_2661ptr_ctrl_get();
195 	    data = pro_2661ptr_stat;
196 	    break;
197 
198 	  case 04:
199 	    if (pro_2661ptr_mode_ptr == 0)
200 	    {
201 	      data = pro_2661ptr_mr1;
202 	      pro_2661ptr_mode_ptr = 1;
203 	    }
204 	    else
205 	    {
206 	      data = pro_2661ptr_mr2;
207 	      pro_2661ptr_mode_ptr = 0;
208 	    }
209 	    break;
210 
211 	  case 06:
212 	    data = pro_2661ptr_cmd;
213 
214 	    if (pro_2661ptr_mode_ptr == 0)
215 	      pro_2661ptr_mode_ptr = 1;
216 	    else
217 	      pro_2661ptr_mode_ptr = 0;
218 
219 	    break;
220 
221 	  default:
222 	    data = 0;
223 	    break;
224 	}
225 
226 	return data;
227 }
228 
pro_2661ptr_wr(int data,int pa,int access)229 void pro_2661ptr_wr (int data, int pa, int access)
230 {
231 	switch (pa & 06)
232 	{
233 	  case 00:
234 	    if ((pro_2661ptr_cmd & PRO_2661_TXEN) != 0)
235 	    {
236 	      /* Store write data value for use in event handler */
237 
238 	      WRITE_WB(pro_2661ptr_wdata, PRO_2661_DATA_W, access);
239 
240 	      /* Clear transmitter ready bit */
241 
242 	      pro_2661ptr_stat = pro_2661ptr_stat & ~PRO_2661_TR;
243 
244 	      /* Queue write data event */
245 
246 	      pro_eq_sched(PRO_EVENT_PTR, PRO_EQ_PTR);
247 	    }
248 
249 	    break;
250 
251 	  case 04:
252 	    if (pro_2661ptr_mode_ptr == 0)
253 	    {
254 	      WRITE_WB(pro_2661ptr_mr1, PRO_2661_MR1_W, access);
255 	      pro_2661ptr_mode_ptr = 1;
256 	    }
257 	    else
258 	    {
259 	      WRITE_WB(pro_2661ptr_mr2, PRO_2661_MR2_W, access);
260 	      pro_2661ptr_mode_ptr = 0;
261 	    }
262 
263 	    /* Update line parameters */
264 
265 	    pro_2661ptr_ctrl_put();
266 	    break;
267 
268 	  case 06:
269 	    /* XXX Reset error unimplemented */
270 
271 	    WRITE_WB(pro_2661ptr_cmd, PRO_2661_CMD_W, access);
272 
273 	    /* Clear receiver done if receiver is disabled */
274 
275 	    if ((pro_2661ptr_cmd & PRO_2661_RXEN) == 0)
276 	      pro_2661ptr_stat = pro_2661ptr_stat & ~PRO_2661_RD;
277 
278 	    /* Clear transmitter ready if auto-echo or remote loopback modes */
279 
280 	    if (((pro_2661ptr_cmd & PRO_2661_OM0) == 1)
281 	       || ((pro_2661ptr_cmd & PRO_2661_TXEN) == 0))
282 	      pro_2661ptr_stat = pro_2661ptr_stat & ~PRO_2661_TR;
283 	    else
284 	      pro_2661ptr_stat = pro_2661ptr_stat | PRO_2661_TR;
285 
286 	    /* Update line parameters */
287 
288 	    pro_2661ptr_ctrl_put();
289 	    break;
290 
291 	  default:
292 	    break;
293 	}
294 }
295 
296 
pro_2661ptr_reset()297 void pro_2661ptr_reset ()
298 {
299 	pro_2661ptr_data = 0000;
300 	pro_2661ptr_stat = 0100 | PRO_2661_TR;	/* transmit ready, cleared for auto-echo or rem. loopback */
301 	pro_2661ptr_mr1 = 0000;
302 	pro_2661ptr_mr2 = 0000;
303 	pro_2661ptr_cmd = 0000;
304 
305 	pro_2661ptr_mode_ptr = 0;
306 
307 	/* Initialize serial line parameters */
308 
309 	memset(&pro_2661ptr_ctrl, 0, sizeof(pro_2661ptr_ctrl));
310 
311 	/* Schedule 2661 polling event */
312 
313 	pro_2661ptr_poll_sched();
314 }
315 
pro_2661ptr_open()316 void pro_2661ptr_open ()
317 {
318 	/* Open serial port */
319 
320 	pro_ptr->reset(PRO_SER_PTR, pro_ptr_port);
321 
322 	/* Set and get serial line parameters */
323 
324 	pro_2661ptr_ctrl_put();
325 	pro_2661ptr_ctrl_get();
326 }
327 #endif
328