Statistics
| Branch: | Revision:

root / hw / parallel.c @ 7c9d8e07

History | View | Annotate | Download (5.6 kB)

1
/*
2
 * QEMU Parallel PORT emulation
3
 * 
4
 * Copyright (c) 2003-2005 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
    int hw_driver;
54
};
55

    
56
static void parallel_update_irq(ParallelState *s)
57
{
58
    if (s->irq_pending)
59
        pic_set_irq(s->irq, 1);
60
    else
61
        pic_set_irq(s->irq, 0);
62
}
63

    
64
static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
65
{
66
    ParallelState *s = opaque;
67
    
68
    addr &= 7;
69
#ifdef DEBUG_PARALLEL
70
    printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
71
#endif
72
    switch(addr) {
73
    case 0:
74
        if (s->hw_driver) {
75
            s->data = val;
76
            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data);
77
        } else {
78
            s->data = val;
79
            parallel_update_irq(s);
80
        }
81
        break;
82
    case 2:
83
        if (s->hw_driver) {
84
            s->control = val;
85
            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control);
86
        } else {
87
            if ((val & PARA_CTR_INIT) == 0 ) {
88
                s->status = PARA_STS_BUSY;
89
                s->status |= PARA_STS_ACK;
90
                s->status |= PARA_STS_ONLINE;
91
                s->status |= PARA_STS_ERROR;
92
            }
93
            else if (val & PARA_CTR_SELECT) {
94
                if (val & PARA_CTR_STROBE) {
95
                    s->status &= ~PARA_STS_BUSY;
96
                    if ((s->control & PARA_CTR_STROBE) == 0)
97
                        qemu_chr_write(s->chr, &s->data, 1);
98
                } else {
99
                    if (s->control & PARA_CTR_INTEN) {
100
                        s->irq_pending = 1;
101
                    }
102
                }
103
            }
104
            parallel_update_irq(s);
105
            s->control = val;
106
        }
107
        break;
108
    }
109
}
110

    
111
static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
112
{
113
    ParallelState *s = opaque;
114
    uint32_t ret = 0xff;
115

    
116
    addr &= 7;
117
    switch(addr) {
118
    case 0:
119
        if (s->hw_driver) {
120
            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data);
121
        } 
122
        ret = s->data; 
123
        break;
124
    case 1:
125
        if (s->hw_driver) {
126
            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status);
127
            ret = s->status; 
128
        } else {
129
            ret = s->status;
130
            s->irq_pending = 0;
131
            if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
132
                /* XXX Fixme: wait 5 microseconds */
133
                if (s->status & PARA_STS_ACK)
134
                    s->status &= ~PARA_STS_ACK;
135
                else {
136
                    /* XXX Fixme: wait 5 microseconds */
137
                    s->status |= PARA_STS_ACK;
138
                    s->status |= PARA_STS_BUSY;
139
                }
140
            }
141
            parallel_update_irq(s);
142
        }
143
        break;
144
    case 2:
145
        if (s->hw_driver) {
146
            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
147
        }
148
        ret = s->control;
149
        break;
150
    }
151
#ifdef DEBUG_PARALLEL
152
    printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
153
#endif
154
    return ret;
155
}
156

    
157
/* If fd is zero, it means that the parallel device uses the console */
158
ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
159
{
160
    ParallelState *s;
161
    uint8_t dummy;
162

    
163
    s = qemu_mallocz(sizeof(ParallelState));
164
    if (!s)
165
        return NULL;
166
    s->chr = chr;
167
    s->hw_driver = 0;
168
    if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0)
169
        s->hw_driver = 1;
170

    
171
    s->irq = irq;
172
    s->data = 0;
173
    s->status = PARA_STS_BUSY;
174
    s->status |= PARA_STS_ACK;
175
    s->status |= PARA_STS_ONLINE;
176
    s->status |= PARA_STS_ERROR;
177
    s->control = PARA_CTR_SELECT;
178
    s->control |= PARA_CTR_INIT;
179

    
180
    register_ioport_write(base, 8, 1, parallel_ioport_write, s);
181
    register_ioport_read(base, 8, 1, parallel_ioport_read, s);
182
    return s;
183
}