serial: only resample THR interrupt on rising edge of IER.THRI
There is disagreement on whether LSR.THRE should be resampled when IER.THRI goes from 1 to 1. Bochs only does it if IER.THRI goes from 0 to 1; PCE does it even if IER.THRI is unchanged. But the Windows driver seems to always go from 1 to 0 and back to 1, so do things in agreement with Bochs, because the handling of thr_ipending was reported in 2010 (https://lists.gnu.org/archive/html/qemu-devel/2010-03/msg01914.html) as breaking DR-DOS Plus. Reported-by: Roy Tam <roytam@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									023c3a9707
								
							
						
					
					
						commit
						1645b8eee5
					
				@ -336,10 +336,12 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 | 
				
			|||||||
            s->divider = (s->divider & 0x00ff) | (val << 8);
 | 
					            s->divider = (s->divider & 0x00ff) | (val << 8);
 | 
				
			||||||
            serial_update_parameters(s);
 | 
					            serial_update_parameters(s);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            uint8_t changed = (s->ier ^ val) & 0x0f;
 | 
				
			||||||
            s->ier = val & 0x0f;
 | 
					            s->ier = val & 0x0f;
 | 
				
			||||||
            /* If the backend device is a real serial port, turn polling of the modem
 | 
					            /* If the backend device is a real serial port, turn polling of the modem
 | 
				
			||||||
               status lines on physical port on or off depending on UART_IER_MSI state */
 | 
					             * status lines on physical port on or off depending on UART_IER_MSI state.
 | 
				
			||||||
            if (s->poll_msl >= 0) {
 | 
					             */
 | 
				
			||||||
 | 
					            if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
 | 
				
			||||||
                if (s->ier & UART_IER_MSI) {
 | 
					                if (s->ier & UART_IER_MSI) {
 | 
				
			||||||
                     s->poll_msl = 1;
 | 
					                     s->poll_msl = 1;
 | 
				
			||||||
                     serial_update_msl(s);
 | 
					                     serial_update_msl(s);
 | 
				
			||||||
@ -354,19 +356,24 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 | 
				
			|||||||
             * This is not in the datasheet, but Windows relies on it.  It is
 | 
					             * This is not in the datasheet, but Windows relies on it.  It is
 | 
				
			||||||
             * unclear if THRE has to be resampled every time THRI becomes
 | 
					             * unclear if THRE has to be resampled every time THRI becomes
 | 
				
			||||||
             * 1, or only on the rising edge.  Bochs does the latter, and Windows
 | 
					             * 1, or only on the rising edge.  Bochs does the latter, and Windows
 | 
				
			||||||
             * always toggles IER to all zeroes and back to all ones.  But for
 | 
					             * always toggles IER to all zeroes and back to all ones, so do the
 | 
				
			||||||
             * now leave it as it has always been in QEMU.
 | 
					             * same.
 | 
				
			||||||
             *
 | 
					             *
 | 
				
			||||||
             * If IER.THRI is zero, thr_ipending is not used.  Set it to zero
 | 
					             * If IER.THRI is zero, thr_ipending is not used.  Set it to zero
 | 
				
			||||||
             * so that the thr_ipending subsection is not migrated.
 | 
					             * so that the thr_ipending subsection is not migrated.
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
 | 
					            if (changed & UART_IER_THRI) {
 | 
				
			||||||
                if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
 | 
					                if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
 | 
				
			||||||
                    s->thr_ipending = 1;
 | 
					                    s->thr_ipending = 1;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    s->thr_ipending = 0;
 | 
					                    s->thr_ipending = 0;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (changed) {
 | 
				
			||||||
                serial_update_irq(s);
 | 
					                serial_update_irq(s);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 2:
 | 
					    case 2:
 | 
				
			||||||
        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
 | 
					        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user