MIPS target (Jocelyn Mayer)
[qemu] / hw / parallel.c
1 /*
2  * QEMU Parallel PORT emulation
3  * 
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25
26 //#define DEBUG_PARALLEL
27
28 /*
29  * These are the definitions for the Printer Status Register
30  */
31 #define PARA_STS_BUSY   0x80    /* Busy complement */
32 #define PARA_STS_ACK    0x40    /* Acknowledge */
33 #define PARA_STS_PAPER  0x20    /* Out of paper */
34 #define PARA_STS_ONLINE 0x10    /* Online */
35 #define PARA_STS_ERROR  0x08    /* Error complement */
36
37 /*
38  * These are the definitions for the Printer Control Register
39  */
40 #define PARA_CTR_INTEN  0x10    /* IRQ Enable */
41 #define PARA_CTR_SELECT 0x08    /* Select In complement */
42 #define PARA_CTR_INIT   0x04    /* Initialize Printer complement */
43 #define PARA_CTR_AUTOLF 0x02    /* Auto linefeed complement */
44 #define PARA_CTR_STROBE 0x01    /* Strobe complement */
45
46 struct ParallelState {
47     uint8_t data;
48     uint8_t status; /* read only register */
49     uint8_t control;
50     int irq;
51     int irq_pending;
52     CharDriverState *chr;
53 };
54
55 static void parallel_update_irq(ParallelState *s)
56 {
57     if (s->irq_pending)
58         pic_set_irq(s->irq, 1);
59     else
60         pic_set_irq(s->irq, 0);
61 }
62
63 static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
64 {
65     ParallelState *s = opaque;
66     
67     addr &= 7;
68 #ifdef DEBUG_PARALLEL
69     printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
70 #endif
71     switch(addr) {
72     case 0:
73         s->data = val;
74         parallel_update_irq(s);
75         break;
76     case 2:
77         if ((val & PARA_CTR_INIT) == 0 ) {
78             s->status = PARA_STS_BUSY;
79             s->status |= PARA_STS_ACK;
80             s->status |= PARA_STS_ONLINE;
81             s->status |= PARA_STS_ERROR;
82         }
83         else if (val & PARA_CTR_SELECT) {
84             if (val & PARA_CTR_STROBE) {
85                 s->status &= ~PARA_STS_BUSY;
86                 if ((s->control & PARA_CTR_STROBE) == 0)
87                     qemu_chr_write(s->chr, &s->data, 1);
88             } else {
89                 if (s->control & PARA_CTR_INTEN) {
90                     s->irq_pending = 1;
91                 }
92             }
93         }
94         parallel_update_irq(s);
95         s->control = val;
96         break;
97     }
98 }
99
100 static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
101 {
102     ParallelState *s = opaque;
103     uint32_t ret = 0xff;
104
105     addr &= 7;
106     switch(addr) {
107     case 0:
108         ret = s->data; 
109         break;
110     case 1:
111         ret = s->status;
112         s->irq_pending = 0;
113         if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
114             /* XXX Fixme: wait 5 microseconds */
115             if (s->status & PARA_STS_ACK)
116                 s->status &= ~PARA_STS_ACK;
117             else {
118             /* XXX Fixme: wait 5 microseconds */
119                 s->status |= PARA_STS_ACK;
120                 s->status |= PARA_STS_BUSY;
121             }
122         }
123         parallel_update_irq(s);
124         break;
125     case 2:
126         ret = s->control;
127         break;
128     }
129 #ifdef DEBUG_PARALLEL
130     printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
131 #endif
132     return ret;
133 }
134
135 static int parallel_can_receive(ParallelState *s)
136 {
137     return 0;
138 }
139
140 static void parallel_receive_byte(ParallelState *s, int ch)
141 {
142 }
143
144 static int parallel_can_receive1(void *opaque)
145 {
146     ParallelState *s = opaque;
147     return parallel_can_receive(s);
148 }
149
150 static void parallel_receive1(void *opaque, const uint8_t *buf, int size)
151 {
152     ParallelState *s = opaque;
153     parallel_receive_byte(s, buf[0]);
154 }
155
156 static void parallel_event(void *opaque, int event)
157 {
158 }
159
160 /* If fd is zero, it means that the parallel device uses the console */
161 ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
162 {
163     ParallelState *s;
164
165     s = qemu_mallocz(sizeof(ParallelState));
166     if (!s)
167         return NULL;
168     s->irq = irq;
169     s->data = 0;
170     s->status = PARA_STS_BUSY;
171     s->status |= PARA_STS_ACK;
172     s->status |= PARA_STS_ONLINE;
173     s->status |= PARA_STS_ERROR;
174     s->control = PARA_CTR_SELECT;
175     s->control |= PARA_CTR_INIT;
176
177     register_ioport_write(base, 8, 1, parallel_ioport_write, s);
178     register_ioport_read(base, 8, 1, parallel_ioport_read, s);
179     s->chr = chr;
180     qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s);
181     qemu_chr_add_event_handler(chr, parallel_event);
182     return s;
183 }