/[dynamips]/upstream/dynamips-0.2.6-RC1/dev_ns16552.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.6-RC1/dev_ns16552.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Oct 6 16:01:44 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.5/dev_ns16552.c
File MIME type: text/plain
File size: 6577 byte(s)
import 0.2.5 from upstream

1 /*
2 * Cisco 3600 simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * NS16552 DUART.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13
14 #include <termios.h>
15 #include <fcntl.h>
16 #include <pthread.h>
17
18 #include "ptask.h"
19 #include "mips64.h"
20 #include "dynamips.h"
21 #include "memory.h"
22 #include "device.h"
23 #include "dev_vtty.h"
24
25 /* Debugging flags */
26 #define DEBUG_UNKNOWN 1
27 #define DEBUG_ACCESS 0
28
29 /* Interrupt Enable Register (IER) */
30 #define IER_ERXRDY 0x1
31 #define IER_ETXRDY 0x2
32
33 /* Interrupt Identification Register */
34 #define IIR_NPENDING 0x01 /* 0: irq pending, 1: no irq pending */
35 #define IIR_TXRDY 0x02
36 #define IIR_RXRDY 0x04
37
38 /* Line Status Register (LSR) */
39 #define LSR_RXRDY 0x01
40 #define LSR_TXRDY 0x20
41 #define LSR_TXEMPTY 0x40
42
43 /* UART channel */
44 struct ns16552_channel {
45 u_int ier,output;
46 vtty_t *vtty;
47 };
48
49 /* NS16552 structure */
50 struct ns16552_data {
51 vm_obj_t vm_obj;
52 struct vdevice dev;
53 vm_instance_t *vm;
54 u_int irq;
55
56 /* Periodic task to trigger DUART IRQ */
57 ptask_id_t tid;
58
59 struct ns16552_channel channel[2];
60 u_int duart_irq_seq;
61 };
62
63 /* Console port input */
64 static void tty_con_input(vtty_t *vtty)
65 {
66 struct ns16552_data *d = vtty->priv_data;
67
68 if (d->channel[0].ier & IER_ERXRDY)
69 vm_set_irq(d->vm,d->irq);
70 }
71
72 /* AUX port input */
73 static void tty_aux_input(vtty_t *vtty)
74 {
75 struct ns16552_data *d = vtty->priv_data;
76
77 if (d->channel[1].ier & IER_ERXRDY)
78 vm_set_irq(d->vm,d->irq);
79 }
80
81 /* IRQ trickery for Console and AUX ports */
82 static int tty_trigger_dummy_irq(struct ns16552_data *d,void *arg)
83 {
84 d->duart_irq_seq++;
85
86 if (d->duart_irq_seq == 2) {
87 if (d->channel[0].ier & IER_ETXRDY) {
88 d->channel[0].output = TRUE;
89 vm_set_irq(d->vm,d->irq);
90 }
91
92 #if 0
93 if (d->channel[1].ier & IER_ETXRDY) {
94 d->channel[1].output = TRUE;
95 vm_set_irq(d->vm,d->irq);
96 }
97 #endif
98
99 d->duart_irq_seq = 0;
100 }
101
102 return(0);
103 }
104
105 /*
106 * dev_ns16552_access()
107 */
108 void *dev_ns16552_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset,
109 u_int op_size,u_int op_type,m_uint64_t *data)
110 {
111 struct ns16552_data *d = dev->priv_data;
112 int channel = 0;
113 u_char odata;
114
115 if (op_type == MTS_READ)
116 *data = 0;
117
118 #if DEBUG_ACCESS
119 if (op_type == MTS_READ) {
120 cpu_log(cpu,"NS16552","read from 0x%x, pc=0x%llx, ra=0x%llx\n",
121 offset,cpu->pc,cpu->gpr[MIPS_GPR_RA]);
122 } else {
123 cpu_log(cpu,"NS16552","write to 0x%x, value=0x%llx, pc=0x%llx\n",
124 offset,*data,cpu->pc);
125 }
126 #endif
127
128 if (offset >= 0x40)
129 channel = 1;
130
131 switch(offset) {
132 /* Receiver Buffer Reg. (RBR) / Transmitting Holding Reg. (THR) */
133 case 0x00:
134 case 0x40:
135 if (op_type == MTS_WRITE) {
136 vtty_put_char(d->channel[channel].vtty,(char)*data);
137
138 if (d->channel[channel].ier & IER_ETXRDY)
139 vm_set_irq(d->vm,d->irq);
140
141 d->channel[channel].output = TRUE;
142 } else {
143 *data = vtty_get_char(d->channel[channel].vtty);
144 }
145 break;
146
147 /* Interrupt Enable Register (IER) */
148 case 0x08:
149 case 0x48:
150 if (op_type == MTS_READ) {
151 *data = d->channel[channel].ier;
152 } else {
153 d->channel[channel].ier = *data & 0xFF;
154
155 if ((*data & 0x02) == 0) { /* transmit holding register */
156 d->channel[channel].vtty->managed_flush = TRUE;
157 vtty_flush(d->channel[channel].vtty);
158 }
159 }
160 break;
161
162 /* Interrupt Ident Register (IIR) */
163 case 0x10:
164 vm_clear_irq(d->vm,d->irq);
165 case 0x50:
166 if (op_type == MTS_READ) {
167 odata = IIR_NPENDING;
168
169 if (vtty_is_char_avail(d->channel[channel].vtty)) {
170 odata = IIR_RXRDY;
171 } else {
172 if (d->channel[channel].output) {
173 odata = IIR_TXRDY;
174 d->channel[channel].output = 0;
175 }
176 }
177
178 *data = odata;
179 }
180 break;
181
182 /* Line Status Register (LSR) */
183 case 0x28:
184 case 0x68:
185 if (op_type == MTS_READ) {
186 odata = 0;
187
188 if (vtty_is_char_avail(d->channel[channel].vtty))
189 odata |= LSR_RXRDY;
190
191 odata |= LSR_TXRDY|LSR_TXEMPTY;
192 *data = odata;
193 }
194 break;
195
196 #if DEBUG_UNKNOWN
197 default:
198 if (op_type == MTS_READ) {
199 cpu_log(cpu,"NS16552","read from addr 0x%x, pc=0x%llx (size=%u)\n",
200 offset,cpu->pc,op_size);
201 } else {
202 cpu_log(cpu,"NS16552","write to addr 0x%x, value=0x%llx, "
203 "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
204 }
205 #endif
206 }
207
208 return NULL;
209 }
210
211 /* Shutdown a NS16552 device */
212 void dev_ns16552_shutdown(vm_instance_t *vm,struct ns16552_data *d)
213 {
214 if (d != NULL) {
215 d->channel[0].vtty->read_notifier = NULL;
216 d->channel[1].vtty->read_notifier = NULL;
217
218 /* Remove the periodic task */
219 ptask_remove(d->tid);
220
221 /* Remove the device */
222 dev_remove(vm,&d->dev);
223
224 /* Free the structure itself */
225 free(d);
226 }
227 }
228
229 /* Create a NS16552 device */
230 int dev_ns16552_init(vm_instance_t *vm,m_uint64_t paddr,m_uint32_t len,
231 u_int irq,vtty_t *vtty_portA,vtty_t *vtty_portB)
232 {
233 struct ns16552_data *d;
234
235 /* Allocate private data structure */
236 if (!(d = malloc(sizeof(*d)))) {
237 fprintf(stderr,"NS16552: out of memory\n");
238 return(-1);
239 }
240
241 memset(d,0,sizeof(*d));
242 d->vm = vm;
243 d->irq = irq;
244 d->channel[0].vtty = vtty_portA;
245 d->channel[1].vtty = vtty_portB;
246
247 vm_object_init(&d->vm_obj);
248 d->vm_obj.name = "ns16552";
249 d->vm_obj.data = d;
250 d->vm_obj.shutdown = (vm_shutdown_t)dev_ns16552_shutdown;
251
252 /* Set device properties */
253 dev_init(&d->dev);
254 d->dev.name = "ns16552";
255 d->dev.phys_addr = paddr;
256 d->dev.phys_len = len;
257 d->dev.handler = dev_ns16552_access;
258 d->dev.priv_data = d;
259
260 vtty_portA->priv_data = d;
261 vtty_portB->priv_data = d;
262 vtty_portA->read_notifier = tty_con_input;
263 vtty_portB->read_notifier = tty_aux_input;
264
265 /* Trigger periodically a dummy IRQ to flush buffers */
266 d->tid = ptask_add((ptask_callback)tty_trigger_dummy_irq,d,NULL);
267
268 /* Map this device to the VM */
269 vm_bind_device(vm,&d->dev);
270 vm_object_add(vm,&d->vm_obj);
271 return(0);
272 }

  ViewVC Help
Powered by ViewVC 1.1.26