Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * RS232 IRQ handler
- *
- * portSet is a parameter passed by the assembly ISR wrapper: It's set to 1 for ports
- * COM2 and 4, and set to 0 for COM1 and 3.
- */
- void rs232_irq_handler(uint32_t portSet) {
- uint16_t port_addr[2][2] = {
- {rs232_to_io_map[0], rs232_to_io_map[2]},
- {rs232_to_io_map[1], rs232_to_io_map[3]}
- };
- sys_pic_irq_eoi((portSet == 0) ? 3 : 4); // send int ack to PIC
- // Read IRQ registers
- uint8_t irq_port1 = io_inb(port_addr[portSet & 0x01][0]+2);
- uint8_t irq_port2 = io_inb(port_addr[portSet & 0x01][1]+2);
- process_irq: ; // gcc is stupid
- // Determine which port triggered it
- uint8_t triggered_port = 0;
- if((irq_port2 & 0x01)) triggered_port = 0;
- else if((irq_port1 & 0x01)) triggered_port = 1;
- else return; // none of the two ports wants to ack the interrupt
- // Shift the entire value right one bit, and get low 3 bits only
- // We could use the high two bits to determine if FIFOs are on, but without
- // them we wouldn't have a working driver
- uint8_t irq = (((triggered_port == 0) ? irq_port1 : irq_port2) >> 0x01) & 0x07;
- uint16_t port = port_addr[portSet & 0x03][triggered_port];
- terminal_write_string("IRQ : 0x");
- terminal_write_byte(irq);
- // Get the struct
- rs232_buffer_t *port_info = &rs232_buffer_ptrs[portSet + (triggered_port << 1)];
- // Service appropriate IRQ
- switch(irq) {
- case 0: { // Modem bits have changed (Read MSR to service)
- port_info->delta_flags = io_inb(port + 6);
- break;
- }
- case 1: { // Transmitter FIFO empty (Write to THR/read IIR)
- // Check if we have any data in the TX buffer
- if(port_info->tx_buf_off == 0) break;
- int offset = port_info->tx_buf_off;
- uint8_t *data_read = port_info->tx_buf;
- // Write 14 bytes if more than 14 are pending
- int num_bytes_write = (offset > 14) ? 14 : offset;
- for(int i = 0; i < num_bytes_write; i++) {
- io_outb(port, *data_read++);
- }
- // Shift buffer
- rs232_shift_buffer(port_info, true, num_bytes_write);
- break;
- }
- case 2: { // RX FIFO threshold (14 bytes) reached (Read RBR to service)
- break;
- }
- case 3: { // Status changed (Read LSR to service)
- port_info->line_status = io_inb(port + 5);
- break;
- }
- case 6: { // No RX act for 4 words, but data avail (Read RBR to service)
- break;
- }
- // well son you dun fucked up good if you get here
- default:
- PANIC("Got unrecognised RS232 interrupt");
- break;
- }
- // Re-read the IRQ states for both ports
- irq_port1 = io_inb(port_addr[portSet & 0x01][0]+2);
- irq_port2 = io_inb(port_addr[portSet & 0x01][1]+2);
- // If any of them do NOT have bit 0 clear, process IRQ again
- if(!(irq_port1 & 0x01)) goto process_irq;
- if(!(irq_port2 & 0x01)) goto process_irq;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement