hints needed for IRQ Programming serial Device, difference between DOS running in QEMU and and real PC?

10/07/2008 - 14:23 von Andreas Romeyke | Report spam
Hello,

I am a little bit confused about the fact that my test program works
under MSDOS/FreeDOS under QEMU but not under a real PC.

I think it will be a timing problem, but I have no idea how to trigger
the problem or to solve it.

To compile the source you need allegro and the djgpp...

Do you have any hints?

The problem occurs, if I send data to the serial device, then the IRQ
is not triggered if tablet should answer. The same in qemu started
with /dev/ttyS0 as COM1 will work correctly.

I triple checked the hardware with toolstar-testutility and dongles and
it works. Also "mode COM1 96,n,8,1" and "more < COM1" will work, if
drawing with the pen.

Here the DOS-specific driver routines...:

==/*! write a byte to serial device COM1 */
static int write_byte_to_serial0(unsigned char b) {
_bios_serialcom(_COM_SEND, 0, b);
return 0;
}


/*! read data from serial device COM1, this function is called by
interrupt
* installed by install_read_data_from_serial0(). It reads only a byte
* and stores them into a buffer.
*/
static void read_data_from_serial0(void) {
unsigned char lsr;
unsigned char input;
irqcounter++;
/* check if bit0 from line status register indicates waiting
char on COM */
do {
lsr=inportb(COM1_BASE+OFFSET_LSR);
if (lsr & DATA_OK) {
/* if data received */
input=inportb(COM1_BASE+OFFSET_THR_RDR_BRDL); /*
receive data */
com1_fifo_serial0[write_fifo_serial0_pos] input;
write_fifo_serial0_pos++;
write_fifo_serial0_pos %= FIFOBUFLEN; /* end of
FIFO of size FIFOBUFLEN reached ??? */
}
} while (lsr & DATA_OK); /* while data ready */
assert(IC_8259 == 0x20);
outportb(IC_8259,0x20); /* tell programmable IRQ
controller that serial IRQ is finished */
enable(); /* enable IRQs again */
}
static END_OF_FUNCTION(read_data_from_serial0)

==

/*! blocking read one byte from serial device 0 (com1), uses the
ringbuffer filled by IRQ
* @return next byte from serial 0
*/
static unsigned char read_byte_from_serial0 (void) {
int i;
unsigned char buf;
while (write_fifo_serial0_pos == read_fifo_serial0_pos);
buf=com1_fifo_serial0[read_fifo_serial0_pos];
read_fifo_serial0_pos++;
read_fifo_serial0_pos %= FIFOBUFLEN;
/* Debugging */
printf("Actual state of buffer r=%i w=%i: >>",
read_fifo_serial0_pos, write_fifo_serial0_pos);
for (i = 0; i< FIFOBUFLEN; i++) {
printf ("%x ", com1_fifo_serial0[i]);
}
printf ("<<");

return buf;
}

==
/*! this install the IRQ */
void install_serial0_handler(void) {
unsigned char mask_8259;
unsigned int status;
read_fifo_serial0_pos=0;
write_fifo_serial0_pos=0;
data_read_flag=0;
LOCK_VARIABLE(read_fifo_serial0_pos);
LOCK_VARIABLE(write_fifo_serial0_pos);
LOCK_VARIABLE(com1_fifo_serial0);
LOCK_VARIABLE(irqcounter);
LOCK_FUNCTION(read_data_from_serial0);
LOCK_VARIABLE(data_read_flag);
#ifdef BBBB
status=_bios_serialcom(_COM_STATUS, 0, 0);
if (status & 0x0030) { printf("COM1 status: device is active
"); } /* DSR & CTS */
else {
perror("device is inactive, program terminated");
exit(EXIT_FAILURE);
}
rest(ANSWER_TIMEOUT);
#endif
/* Set programmable interrupt controller */
inportb(COM1_BASE);
mask_8259 = inportb(IC_8259+1);
inportb(COM1_BASE);
outportb(IC_8259+1, (mask_8259 & IRQ4_ENABLE));
printf("IRQ will be installed");
if (0 == _install_irq(IRQ4_NUM, read_data_from_serial0)) {; /*
call internal Allegro function */
printf("IRQ should be installed");
irqcounter=0;
} else {
perror("IRQ handler could not be installed");
}
atexit(remove_serial0_handler);
}

==/*! deinstalls IRQ if exit */
void remove_serial0_handler(void) {
_remove_irq(COM1_interrupt);
}

==/*! opens the serial device and sets the communication paremeters
* @return serial handle no
*/
int initialize_serial0(void) {
unsigned int mode;
unsigned int i=0;
int serial_handle=0; /*0 = COM1, 1 = COM2 */
unsigned char lcr=0;
mode = _COM_CHR8 | _COM_NOPARITY | _COM_9600 | _COM_STOP1;
_bios_serialcom(_COM_INIT,serial_handle,mode);
outportb(COM1_BASE+ OFFSET_MCR, SET_HW_HANDSHAKE); /* turn on
DTR, RTS, and OUT2 */
lcr = inportb(COM1_BASE + OFFSET_LCR);
lcr &= ~DLAB;
outportb(COM1_BASE+ OFFSET_LCR, lcr); /* switch BRDH_IER to IER
*/
outportb(COM1_BASE+ OFFSET_BRDH_IER, 0x01); /* Interrupt, if
data received 0x01 to IER */
return serial_handle;
}
==/*! restores original serial device parameters
* @param serial_handle serial handle no
*/
void deinitialize_serial0(int serial_handle) {
remove_serial0_handler();
}
==/*! communicates with the tablet, sends a command and requests an
anwer.
* The answer is cleaned from echoes and carriage return.
* @param serial_handle serial handle no
* @param commandlen how many chars the command string has
* @param command pointer to command string
* @return pointer to answer string
*/
unsigned char * send_command_with_answer (int serial_handle, int
commandlen, const unsigned char * command) {
unsigned char * answer;
assert (MAXBUFLEN > 1);
assert ((unsigned char) '' == (unsigned char) 0xd);
assert ((unsigned char) '' == (unsigned char) 0xa);
assert (1 == sizeof(unsigned char));
printf ("scwa: sending command");
send_command_without_answer(serial_handle, commandlen, command);
printf ("scwa: command sent, receiving answer");
answer= receive_answer(serial_handle);
printf("scwa: answer received '%s', shortening...", answer);
answer+=(commandlen); /* to reduce echoed command */
printf("scwa: answer shortened '%s'", answer );
return answer;
}

==/*! communicates with the tablet, sends a command
* and does not expect an anwer.
* @param serial_handle serial handle no
* @param commandlen how many chars the command string has
* @param command pointer to command string
*/
void send_command_without_answer (int serial_handle, int commandlen,
const unsigned char * command) {
int i;
assert (MAXBUFLEN > 1);
assert ((unsigned char) '' == (unsigned char) 0xd);
assert ((unsigned char) '' == (unsigned char) 0xa);
assert (1 == sizeof(unsigned char));
assert(commandlen < MAXBUFLEN);
assert(commandlen > 0);
assert(command != NULL);
printf("send command: '");
for (i=0; i<commandlen; i++) {
write_byte_to_serial0(command[i]);
/* _bios_serialcom(_COM_SEND,serial_handle,command[i]);
*/
printf ("%c", command[i]);
}
printf("'");
rest(ANSWER_TIMEOUT);
}
==

/*! communicates with the tablet, requests only an anwer.
* @param serial_handle serial handler no
* @return pointer to answer string
*/
unsigned char * receive_answer(int serial_handle) {
static unsigned char answer[MAXBUFLEN];
int i;
unsigned char buffer;
assert (MAXBUFLEN > 1);
assert ((unsigned char) '' == (unsigned char) 0xd);
assert ((unsigned char) '' == (unsigned char) 0xa);
assert (1 == sizeof(unsigned char));
memset(answer, 0, sizeof(unsigned char) * MAXBUFLEN);
printf("RA: Maxbuflen=%i", MAXBUFLEN);
for (i= 0; i < MAXBUFLEN-1; i++) {
printf("RA: i=%i", i);
buffer = read_byte_from_serial0();
printf("|%0x %c|", buffer, buffer);
if ('' == buffer) break; /* if or ends command
sequence marker offset */
answer[i]=buffer;
}
printf("answer: '%s'", answer);
return answer;

}

==
Any hints?

Bye Andreas
 

Lesen sie die antworten

#1 Andreas Romeyke
21/07/2008 - 10:14 | Warnen spam
Hallo,

Am Thu, 10 Jul 2008 14:23:50 +0200
schrieb Andreas Romeyke :

The problem occurs, if I send data to the serial device, then the IRQ
is not triggered if tablet should answer. The same in qemu started
with /dev/ttyS0 as COM1 will work correctly.



Das Problem lag an der BIOS-Funktion bios_serialcom(), die unter QEMU
die Registersettings der COM-Schnittstelle unangetastet làsst und auf
einigen neueren PCs aber veràndert.

Wenn ich die serielle Schnittstelle ohne BIOS-Funktion benutze,
funktioniert auch die IRQ-Routine.

bye Andreas

Ähnliche fragen