Statistics
| Branch: | Revision:

root / hw / parallel.c @ dc9543dc

History | View | Annotate | Download (5.2 kB)

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
}