1 |
/* |
/* |
2 |
* QEMU Parallel PORT emulation |
* QEMU Parallel PORT emulation |
3 |
* |
* |
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
* Copyright (c) 2003-2005 Fabrice Bellard |
5 |
* |
* |
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
* 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 |
* of this software and associated documentation files (the "Software"), to deal |
50 |
int irq; |
int irq; |
51 |
int irq_pending; |
int irq_pending; |
52 |
CharDriverState *chr; |
CharDriverState *chr; |
53 |
|
int hw_driver; |
54 |
}; |
}; |
55 |
|
|
56 |
static void parallel_update_irq(ParallelState *s) |
static void parallel_update_irq(ParallelState *s) |
71 |
#endif |
#endif |
72 |
switch(addr) { |
switch(addr) { |
73 |
case 0: |
case 0: |
74 |
s->data = val; |
if (s->hw_driver) { |
75 |
parallel_update_irq(s); |
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; |
break; |
82 |
case 2: |
case 2: |
83 |
if ((val & PARA_CTR_INIT) == 0 ) { |
if (s->hw_driver) { |
84 |
s->status = PARA_STS_BUSY; |
s->control = val; |
85 |
s->status |= PARA_STS_ACK; |
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control); |
86 |
s->status |= PARA_STS_ONLINE; |
} else { |
87 |
s->status |= PARA_STS_ERROR; |
if ((val & PARA_CTR_INIT) == 0 ) { |
88 |
} |
s->status = PARA_STS_BUSY; |
89 |
else if (val & PARA_CTR_SELECT) { |
s->status |= PARA_STS_ACK; |
90 |
if (val & PARA_CTR_STROBE) { |
s->status |= PARA_STS_ONLINE; |
91 |
s->status &= ~PARA_STS_BUSY; |
s->status |= PARA_STS_ERROR; |
92 |
if ((s->control & PARA_CTR_STROBE) == 0) |
} |
93 |
qemu_chr_write(s->chr, &s->data, 1); |
else if (val & PARA_CTR_SELECT) { |
94 |
} else { |
if (val & PARA_CTR_STROBE) { |
95 |
if (s->control & PARA_CTR_INTEN) { |
s->status &= ~PARA_STS_BUSY; |
96 |
s->irq_pending = 1; |
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 |
} |
} |
|
parallel_update_irq(s); |
|
|
s->control = val; |
|
107 |
break; |
break; |
108 |
} |
} |
109 |
} |
} |
116 |
addr &= 7; |
addr &= 7; |
117 |
switch(addr) { |
switch(addr) { |
118 |
case 0: |
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; |
ret = s->data; |
123 |
break; |
break; |
124 |
case 1: |
case 1: |
125 |
ret = s->status; |
if (s->hw_driver) { |
126 |
s->irq_pending = 0; |
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status); |
127 |
if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { |
ret = s->status; |
128 |
/* XXX Fixme: wait 5 microseconds */ |
} else { |
129 |
if (s->status & PARA_STS_ACK) |
ret = s->status; |
130 |
s->status &= ~PARA_STS_ACK; |
s->irq_pending = 0; |
131 |
else { |
if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { |
132 |
/* XXX Fixme: wait 5 microseconds */ |
/* XXX Fixme: wait 5 microseconds */ |
133 |
s->status |= PARA_STS_ACK; |
if (s->status & PARA_STS_ACK) |
134 |
s->status |= PARA_STS_BUSY; |
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 |
} |
} |
|
parallel_update_irq(s); |
|
143 |
break; |
break; |
144 |
case 2: |
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; |
ret = s->control; |
149 |
break; |
break; |
150 |
} |
} |
175 |
parallel_receive_byte(s, buf[0]); |
parallel_receive_byte(s, buf[0]); |
176 |
} |
} |
177 |
|
|
|
static void parallel_event(void *opaque, int event) |
|
|
{ |
|
|
} |
|
|
|
|
178 |
/* If fd is zero, it means that the parallel device uses the console */ |
/* If fd is zero, it means that the parallel device uses the console */ |
179 |
ParallelState *parallel_init(int base, int irq, CharDriverState *chr) |
ParallelState *parallel_init(int base, int irq, CharDriverState *chr) |
180 |
{ |
{ |
181 |
ParallelState *s; |
ParallelState *s; |
182 |
|
uint8_t dummy; |
183 |
|
|
184 |
s = qemu_mallocz(sizeof(ParallelState)); |
s = qemu_mallocz(sizeof(ParallelState)); |
185 |
if (!s) |
if (!s) |
186 |
return NULL; |
return NULL; |
187 |
|
s->chr = chr; |
188 |
|
s->hw_driver = 0; |
189 |
|
if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) |
190 |
|
s->hw_driver = 1; |
191 |
|
|
192 |
s->irq = irq; |
s->irq = irq; |
193 |
s->data = 0; |
s->data = 0; |
194 |
s->status = PARA_STS_BUSY; |
s->status = PARA_STS_BUSY; |
200 |
|
|
201 |
register_ioport_write(base, 8, 1, parallel_ioport_write, s); |
register_ioport_write(base, 8, 1, parallel_ioport_write, s); |
202 |
register_ioport_read(base, 8, 1, parallel_ioport_read, s); |
register_ioport_read(base, 8, 1, parallel_ioport_read, s); |
|
s->chr = chr; |
|
203 |
qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); |
qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); |
|
qemu_chr_add_event_handler(chr, parallel_event); |
|
204 |
return s; |
return s; |
205 |
} |
} |