| 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 |
} |
} |