Subversion Repositories HelenOS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <unistd.h>
  2. #include <ddi.h>
  3. #include <libarch/ddi.h>
  4. #include <stdio.h>
  5.  
  6. #include "isa.h"
  7. #include "serial.h"
  8.  
  9. #define NAME "serial"
  10.  
  11. #define REG_COUNT 7
  12. #define COM1 0x3F8
  13. #define COM2 0x2F8
  14.  
  15. static ioport8_t *com1 = 0, *com2 = 0;
  16.  
  17. static void serial_init_port(ioport8_t *port);
  18. static void serial_write_8(ioport8_t *port, uint8_t c);
  19. static bool is_transmit_empty(ioport8_t *port);
  20. static uint8_t serial_read_8(ioport8_t *port);
  21. static bool serial_received(ioport8_t *port);
  22. static void serial_probe(bridge_to_isa_t *parent);
  23. static void * serial_probe_port(void *phys_addr);
  24.  
  25. static isa_drv_ops_t serial_isa_ops = {
  26.     .probe = serial_probe  
  27. };
  28.  
  29. static isa_drv_t serial_isa_drv = {
  30.     .name = NAME,
  31.     .ops = &serial_isa_ops 
  32. };
  33.  
  34. int serial_init()
  35. {
  36.     // TODO: register this driver by generic isa bus driver
  37.    
  38.     isa_register_driver(&serial_isa_drv);
  39.     return 1;
  40. }
  41.  
  42. static bool serial_received(ioport8_t *port)
  43. {
  44.    return (pio_read_8(port + 5) & 1) != 0;
  45. }
  46.  
  47. static uint8_t serial_read_8(ioport8_t *port)
  48. {
  49.     while (!serial_received(port))
  50.         ;
  51.  
  52.     uint8_t c = pio_read_8(port);
  53.     return c;
  54. }
  55.  
  56. static bool is_transmit_empty(ioport8_t *port)
  57. {
  58.    return (pio_read_8(port + 5) & 0x20) != 0;
  59. }
  60.  
  61. static void serial_write_8(ioport8_t *port, uint8_t c)
  62. {
  63.     while (!is_transmit_empty(port))
  64.         ;
  65.    
  66.     pio_write_8(port, c);
  67. }
  68.  
  69. static void serial_init_port(ioport8_t *port)
  70. {  
  71.     pio_write_8(port + 1, 0x00);    // Disable all interrupts
  72.     pio_write_8(port + 3, 0x80);    // Enable DLAB (set baud rate divisor)
  73.     pio_write_8(port + 0, 0x60);    // Set divisor to 96 (lo byte) 1200 baud
  74.     pio_write_8(port + 1, 0x00);    //                   (hi byte)
  75.     pio_write_8(port + 3, 0x07);    // 8 bits, no parity, two stop bits
  76.     pio_write_8(port + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
  77.     pio_write_8(port + 4, 0x0B);    // IRQs enabled, RTS/DSR set
  78. }
  79.  
  80. static void serial_probe(bridge_to_isa_t *parent)
  81. {
  82.     printf(NAME " driver: probe()\n"); 
  83.  
  84.     printf(NAME " driver: probing com1 \n");
  85.     if (com1 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM1))) {
  86.         printf(NAME " driver: initializing com1 \n");
  87.         serial_init_port(com1);
  88.     }   else {
  89.         printf(NAME " driver: com1 is not present \n");
  90.     }
  91.    
  92.     printf(NAME " driver: probing com2 \n");
  93.     if (com2 = (ioport8_t *)serial_probe_port(parent->ops->absolutize(COM2))) {
  94.         printf(NAME " driver: initializing com2 \n");
  95.         serial_init_port(com2);
  96.     }
  97.     else {
  98.         printf(NAME " driver: com2 is not present \n");
  99.     }  
  100. }
  101.  
  102. // returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise  
  103. static void * serial_probe_port(void *phys_addr)
  104. {
  105.     ioport8_t *port_addr = NULL;
  106.    
  107.     if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) {  // Gain control over port's registers.
  108.         printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr);
  109.         return NULL;
  110.     }
  111.    
  112.     uint8_t olddata;
  113.    
  114.     olddata = pio_read_8(port_addr + 4);
  115.     pio_write_8(port_addr + 4, 0x10);
  116.     if ((pio_read_8(port_addr + 6) & 0xf0)) {
  117.         return NULL;
  118.     }
  119.    
  120.     pio_write_8(port_addr + 4, 0x1f);
  121.     if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) {
  122.         return 0;
  123.     }
  124.     pio_write_8(port_addr + 4, olddata);
  125.    
  126.     return port_addr;
  127. }
  128.