Advertisement
tristanseifert

Untitled

Nov 2nd, 2013
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 2.72 KB | None | 0 0
  1. /*
  2.  * RS232 IRQ handler
  3.  *
  4.  * portSet is a parameter passed by the assembly ISR wrapper: It's set to 1 for ports
  5.  * COM2 and 4, and set to 0 for COM1 and 3.
  6.  */
  7. void rs232_irq_handler(uint32_t portSet) {
  8.     uint16_t port_addr[2][2] = {
  9.         {rs232_to_io_map[0], rs232_to_io_map[2]},
  10.         {rs232_to_io_map[1], rs232_to_io_map[3]}
  11.     };
  12.  
  13.     sys_pic_irq_eoi((portSet == 0) ? 3 : 4); // send int ack to PIC
  14.  
  15.     // Read IRQ registers
  16.     uint8_t irq_port1 = io_inb(port_addr[portSet & 0x01][0]+2);
  17.     uint8_t irq_port2 = io_inb(port_addr[portSet & 0x01][1]+2);
  18.  
  19. process_irq: ; // gcc is stupid
  20.     // Determine which port triggered it
  21.     uint8_t triggered_port = 0;
  22.     if((irq_port2 & 0x01)) triggered_port = 0;
  23.     else if((irq_port1 & 0x01)) triggered_port = 1;
  24.     else return; // none of the two ports wants to ack the interrupt
  25.  
  26.     // Shift the entire value right one bit, and get low 3 bits only
  27.     // We could use the high two bits to determine if FIFOs are on, but without
  28.     // them we wouldn't have a working driver
  29.     uint8_t irq = (((triggered_port == 0) ? irq_port1 : irq_port2) >> 0x01) & 0x07;
  30.     uint16_t port = port_addr[portSet & 0x03][triggered_port];
  31.  
  32.     terminal_write_string("IRQ : 0x");
  33.     terminal_write_byte(irq);
  34.  
  35.     // Get the struct
  36.     rs232_buffer_t *port_info = &rs232_buffer_ptrs[portSet + (triggered_port << 1)];
  37.  
  38.     // Service appropriate IRQ
  39.     switch(irq) {
  40.         case 0: { // Modem bits have changed (Read MSR to service)
  41.             port_info->delta_flags = io_inb(port + 6);
  42.             break;
  43.         }
  44.        
  45.         case 1: { // Transmitter FIFO empty (Write to THR/read IIR)
  46.             // Check if we have any data in the TX buffer
  47.             if(port_info->tx_buf_off == 0) break;
  48.  
  49.             int offset = port_info->tx_buf_off;
  50.             uint8_t *data_read = port_info->tx_buf;
  51.  
  52.             // Write 14 bytes if more than 14 are pending
  53.             int num_bytes_write = (offset > 14) ? 14 : offset;
  54.  
  55.             for(int i = 0; i < num_bytes_write; i++) {
  56.                 io_outb(port, *data_read++);
  57.             }
  58.  
  59.             // Shift buffer
  60.             rs232_shift_buffer(port_info, true, num_bytes_write);
  61.  
  62.             break;
  63.         }
  64.        
  65.         case 2: { // RX FIFO threshold (14 bytes) reached (Read RBR to service)
  66.  
  67.             break;
  68.         }
  69.        
  70.         case 3: { // Status changed (Read LSR to service)
  71.             port_info->line_status = io_inb(port + 5);
  72.             break;
  73.         }
  74.        
  75.         case 6: { // No RX act for 4 words, but data avail (Read RBR to service)
  76.  
  77.             break;
  78.         }
  79.  
  80.         // well son you dun fucked up good if you get here
  81.         default:
  82.             PANIC("Got unrecognised RS232 interrupt");
  83.             break;
  84.     }
  85.  
  86.     // Re-read the IRQ states for both ports
  87.     irq_port1 = io_inb(port_addr[portSet & 0x01][0]+2);
  88.     irq_port2 = io_inb(port_addr[portSet & 0x01][1]+2);
  89.  
  90.     // If any of them do NOT have bit 0 clear, process IRQ again
  91.     if(!(irq_port1 & 0x01)) goto process_irq;
  92.     if(!(irq_port2 & 0x01)) goto process_irq;
  93. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement