static void handle_irq (unsigned int port_number) { uint8_t iir; uint8_t data; uint8_t tx_chars; uint16_t base; uint16_t tmp = 0; base = serial_port[port_number].port; iir = system_port_in_uint8_t (base + REGISTER_IIR); while ((iir & 0x01) == 0) { iir &= 0x06; iir >>= 1; if (iir == 0) { /* Modem status. */ log_print (&log_structure, LOG_URGENCY_DEBUG, "Serial modem IRQ."); (void) system_port_in_uint8_t (base + REGISTER_MSR); } else if (iir == 1) { /* Ready to transmit. */ tx_chars = 1; if (serial_port[port_number].use_fifo != FALSE) { tx_chars = serial_port[port_number].tx_fifo; } while (serial_port[port_number].lock_tx == TRUE) { system_call_dispatch_next (); } serial_port[port_number].lock_tx = TRUE; while (tx_chars != 0) { tx_chars--; if (serial_port[port_number].tx_current != serial_port[port_number].tx_end) { /* Send one more character. */ data = serial_port[port_number].tx_buffer[serial_port[port_number].tx_current]; serial_port[port_number].tx_current++; serial_port[port_number].tx_current %= BUFFER_SIZE; system_port_out_uint8_t (base + REGISTER_DATA, data); } else { /* No more data. Disable Tx interrupt. */ data = system_port_in_uint8_t (base + REGISTER_IER); data &= 0xFD; system_port_out_uint8_t (base + REGISTER_IER, data); break; } } serial_port[port_number].lock_tx = FALSE; } else if (iir == 2) { /* Rx data available. */ while (serial_port[port_number].lock_rx == TRUE) { system_call_dispatch_next (); } serial_port[port_number].lock_rx = TRUE; do { tmp++; data = system_port_in_uint8_t (base + REGISTER_DATA); serial_port[port_number].rx_buffer[serial_port[port_number].rx_end] = data; serial_port[port_number].rx_end++; serial_port[port_number].rx_end %= BUFFER_SIZE; if (serial_port[port_number].rx_end == serial_port[port_number].rx_current) { log_print (&log_structure, LOG_URGENCY_ERROR, "Rx buffer overflow."); } } while ((system_port_in_uint8_t (base + REGISTER_LSR) & 0x01) == 0x01); log_print_formatted (&log_structure, LOG_URGENCY_DEBUG, "Received %d chars.", tmp); /* Check for pending messages to send. */ if (serial_port[port_number].rx_pending != 0 && unread_size (port_number) >= serial_port[port_number].rx_pending) { send_data (port_number); serial_port[port_number].rx_pending = 0; } serial_port[port_number].lock_rx = FALSE; /* FIXME: Prevent Tx lockup. */ } else { /* Receiver line status. */ log_print (&log_structure, LOG_URGENCY_DEBUG, "Serial line IRQ."); serial_port[port_number].line_error++; data = system_port_in_uint8_t (base + REGISTER_LSR); if ((data & 0x02) != 0) { serial_port[port_number].overrun_error++; log_print (&log_structure, LOG_URGENCY_DEBUG, "Overrun error."); } if ((data & 0x04) != 0) { serial_port[port_number].parity_error++; log_print (&log_structure, LOG_URGENCY_DEBUG, "Parity error."); } if ((data & 0x08) != 0) { log_print (&log_structure, LOG_URGENCY_DEBUG, "Framing error."); serial_port[port_number].framing_error++; } (void) system_port_in_uint8_t (base + REGISTER_DATA); serial_port[port_number].errors++; } iir = system_port_in_uint8_t (base + REGISTER_IIR); } }
int main (void) { keyboard_packet_type keyboard_packet; int event_type; bool local_echo = FALSE; int baudrate_num = 4; log_init (&log_structure, PACKAGE_NAME, &empty_tag); system_call_process_name_set (PACKAGE_NAME); console_init (&console_structure, &empty_tag, IPC_CONSOLE_CONNECTION_CLASS_CLIENT); console_open (&console_structure, 80, 50, 4, VIDEO_MODE_TYPE_TEXT); console_use_keyboard (&console_structure, TRUE, CONSOLE_KEYBOARD_NORMAL); console_clear (&console_structure); console_print (&console_structure, "Terminator 2000 - The final terminator.\n\n"); if (system_call_thread_create () == STORM_RETURN_THREAD_NEW) { unsigned char buffer[100]; int length = 1; while (TRUE) { if (config1 != FALSE) { while (lock == TRUE) { system_call_dispatch_next (); } lock = TRUE; if (serial_init (&ipc_structure1, &empty_tag) != SERIAL_RETURN_SUCCESS) { log_print (&log_structure, LOG_URGENCY_EMERGENCY, "Could not establish connection to a serial service."); return -1; } config1 = FALSE; lock = FALSE; log_print_formatted (&log_structure, LOG_URGENCY_DEBUG, "COM %d opened rx.", port_num+1); } if (serial_read (&ipc_structure1, buffer, length) != SERIAL_RETURN_SUCCESS) { log_print (&log_structure, LOG_URGENCY_ERROR, "Error reading from port."); } else { buffer[length] = 0; console_print (&console_structure, buffer); } } } while (TRUE) { bool send = TRUE; bool configure = FALSE; char key; if (config2 != FALSE) { if (serial_init (&ipc_structure2, &empty_tag) != SERIAL_RETURN_SUCCESS) { log_print (&log_structure, LOG_URGENCY_EMERGENCY, "Could not establish connection to a serial service."); return -1; } config2 = FALSE; log_print_formatted (&log_structure, LOG_URGENCY_DEBUG, "COM %d opened tx.", port_num+1); } console_event_wait (&console_structure, &keyboard_packet, &event_type, TRUE); if (keyboard_packet.key_pressed == TRUE) { if (keyboard_packet.has_character_code == 1) { key = keyboard_packet.character_code[0]; } else if (keyboard_packet.has_special_key == 1) { switch (keyboard_packet.special_key) { case IPC_KEYBOARD_SPECIAL_KEY_ESCAPE: { log_print (&log_structure, LOG_URGENCY_DEBUG, "Local echo toggled."); local_echo = !local_echo; send = FALSE; break; } case IPC_KEYBOARD_SPECIAL_KEY_F10: { if (++port_num >= PORT_NUM) { port_num = 0; } send = FALSE; config2 = TRUE; while (lock == TRUE) { system_call_dispatch_next (); } lock = TRUE; config1 = TRUE; lock = FALSE; break; } case IPC_KEYBOARD_SPECIAL_KEY_F11: { if (--baudrate_num < 0) { baudrate_num = BAUDRATE_NUM - 1; } send = FALSE; configure = TRUE; break; } case IPC_KEYBOARD_SPECIAL_KEY_F12: { if (++baudrate_num >= BAUDRATE_NUM) { baudrate_num = 0; } send = FALSE; configure = TRUE; break; } case IPC_KEYBOARD_SPECIAL_KEY_TAB: { key = '\t'; break; } case IPC_KEYBOARD_SPECIAL_KEY_BACK_SPACE: { key = 8; break; } case IPC_KEYBOARD_SPECIAL_KEY_ENTER: { key = '\n'; break; } } } if (send) { if (serial_write (&ipc_structure2, &key, 1) != SERIAL_RETURN_SUCCESS) { log_print (&log_structure, LOG_URGENCY_ERROR, "Error writing to port."); } else { if (local_echo) { char buffer[] = { key, 0 }; console_print (&console_structure, buffer); } } } if (configure != FALSE) { if (serial_config_line (&ipc_structure2, baudrates[baudrate_num], 8, 0, SERIAL_PARITY_NONE) != SERIAL_RETURN_SUCCESS) { log_print (&log_structure, LOG_URGENCY_ERROR, "Error configuring port."); } else { log_print_formatted (&log_structure, LOG_URGENCY_DEBUG, "%d 8/N/1 selected.", baudrates[baudrate_num]); } } } } return 0; }