/[dynamips]/upstream/dynamips-0.2.5/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

Annotation of /upstream/dynamips-0.2.5/dev_ns16552.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Sat Oct 6 16:01:44 2007 UTC (12 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 6577 byte(s)
import 0.2.5 from upstream

1 dpavlin 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