]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
some serial config support
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 18 Jul 2010 12:43:23 +0000 (14:43 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 18 Jul 2010 12:43:23 +0000 (14:43 +0200)
include/grub/serial.h
term/ns8250.c
term/serial.c
term/usbserial.c

index 7828a7c98eda2da37449822939add67c473e123f..5afc1f172ce5e12854a4de22b50efa44e47b21c3 100644 (file)
@@ -36,12 +36,26 @@ struct grub_serial_driver
   void (*put) (struct grub_serial_port *port, const int c);
 };
 
+/* The type of parity.  */
+typedef enum
+  {
+    GRUB_SERIAL_PARITY_NONE,
+    GRUB_SERIAL_PARITY_ODD,
+    GRUB_SERIAL_PARITY_EVEN,
+  } grub_serial_parity_t;
+
+typedef enum
+  {
+    GRUB_SERIAL_STOP_BITS_1,
+    GRUB_SERIAL_STOP_BITS_2,
+  } grub_serial_stop_bits_t;
+
 struct grub_serial_config
 {
   unsigned speed;
   unsigned short word_len;
-  unsigned int   parity;
-  unsigned short stop_bits;
+  grub_serial_parity_t parity;
+  grub_serial_stop_bits_t stop_bits;
 };
 
 struct grub_serial_port
@@ -76,15 +90,6 @@ void grub_serial_unregister (struct grub_serial_port *port);
 #define UART_7BITS_WORD        0x02
 #define UART_8BITS_WORD        0x03
 
-/* The type of parity.  */
-#define UART_NO_PARITY         0x00
-#define UART_ODD_PARITY                0x08
-#define UART_EVEN_PARITY       0x18
-
-/* The type of the length of stop bit.  */
-#define UART_1_STOP_BIT                0x00
-#define UART_2_STOP_BITS       0x04
-
   /* Set default settings.  */
 static inline grub_err_t
 grub_serial_config_defaults (struct grub_serial_port *port)
@@ -97,8 +102,8 @@ grub_serial_config_defaults (struct grub_serial_port *port)
       .speed = 9600,
 #endif
       .word_len = UART_8BITS_WORD,
-      .parity = UART_NO_PARITY,
-      .stop_bits = UART_1_STOP_BIT
+      .parity = GRUB_SERIAL_PARITY_NONE,
+      .stop_bits = GRUB_SERIAL_STOP_BITS_1
     };
 
   return port->driver->configure (port, &config);
index c63bc6494511ec4803cc2bccb35bdd96933c2e91..a69c683f2697791bb076a6bd4e14918b93f6ac82 100644 (file)
@@ -77,14 +77,20 @@ do_real_config (struct grub_serial_port *port)
 {
   int divisor;
   unsigned char status = 0;
+  const unsigned char parities[] = {
+    [GRUB_SERIAL_PARITY_NONE] = UART_NO_PARITY,
+    [GRUB_SERIAL_PARITY_ODD] = UART_ODD_PARITY,
+    [GRUB_SERIAL_PARITY_EVEN] = UART_EVEN_PARITY
+  };
+  const unsigned char stop_bits[] = {
+    [GRUB_SERIAL_STOP_BITS_1] = UART_1_STOP_BIT,
+    [GRUB_SERIAL_STOP_BITS_2] = UART_2_STOP_BITS,
+  };
 
   if (port->configured)
     return;
 
   divisor = serial_get_divisor (port->config.speed);
-  /* Shouldn't happen.  */
-  if (divisor == 0)
-    return;
 
   /* Turn off the interrupt.  */
   grub_outb (0, port->port + UART_IER);
@@ -97,8 +103,8 @@ do_real_config (struct grub_serial_port *port)
   grub_outb (divisor >> 8, port->port + UART_DLH);
 
   /* Set the line status.  */
-  status |= (port->config.parity | port->config.word_len
-            | port->config.stop_bits);
+  status |= (parities[port->config.parity]
+            | port->config.word_len | stop_bits[port->config.stop_bits]);
   grub_outb (status, port->port + UART_LCR);
 
   /* In Yeeloong serial port has only 3 wires.  */
@@ -170,6 +176,15 @@ serial_hw_configure (struct grub_serial_port *port,
   if (divisor == 0)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
 
+  if (config->parity != GRUB_SERIAL_PARITY_NONE
+      && config->parity != GRUB_SERIAL_PARITY_ODD
+      && config->parity != GRUB_SERIAL_PARITY_EVEN)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
+
+  if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
+      && config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
+
   port->config = *config;
   port->configured = 0;
 
index 00214cb4c0f2cd29789d84acbf90fc42298beaf4..5f27b16b6c3276a840bfbc7f1e2c8f0ba6813add 100644 (file)
@@ -203,11 +203,11 @@ grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args)
   if (state[4].set)
     {
       if (! grub_strcmp (state[4].arg, "no"))
-       config.parity = UART_NO_PARITY;
+       config.parity = GRUB_SERIAL_PARITY_NONE;
       else if (! grub_strcmp (state[4].arg, "odd"))
-       config.parity = UART_ODD_PARITY;
+       config.parity = GRUB_SERIAL_PARITY_ODD;
       else if (! grub_strcmp (state[4].arg, "even"))
-       config.parity = UART_EVEN_PARITY;
+       config.parity = GRUB_SERIAL_PARITY_EVEN;
       else
        return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity");
     }
@@ -215,9 +215,9 @@ grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args)
   if (state[5].set)
     {
       if (! grub_strcmp (state[5].arg, "1"))
-       config.stop_bits = UART_1_STOP_BIT;
+       config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
       else if (! grub_strcmp (state[5].arg, "2"))
-       config.stop_bits = UART_2_STOP_BITS;
+       config.stop_bits = GRUB_SERIAL_STOP_BITS_2;
       else
        return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits");
     }
index 258187ff9451687b98fcf855a8f8bbe5bc9f09b9..b2a89d56ce5285ace1751cb6aef6a46b9a069e91 100644 (file)
 #include <grub/mm.h>
 #include <grub/usb.h>
 
+enum
+  {
+    GRUB_USBSERIAL_MODEM_CTRL = 0x01,
+    GRUB_USBSERIAL_FLOW_CTRL = 0x02,
+    GRUB_USBSERIAL_SPEED_CTRL = 0x03,
+    GRUB_USBSERIAL_DATA_CTRL = 0x04
+  };
+
+#define GRUB_USBSERIAL_MODEM_CTRL_DTRRTS 3
+#define GRUB_USBSERIAL_FLOW_CTRL_DTRRTS 3
+
+/* Convert speed to divisor.  */
+static grub_uint32_t
+get_divisor (unsigned int speed)
+{
+  unsigned int i;
+
+  /* The structure for speed vs. divisor.  */
+  struct divisor
+  {
+    unsigned int speed;
+    grub_uint32_t div;
+  };
+
+  /* The table which lists common configurations.  */
+  static struct divisor divisor_tab[] =
+    {
+      { 9600,   0x4138 },
+    };
+
+  /* Set the baud rate.  */
+  for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
+    if (divisor_tab[i].speed == speed)
+      return divisor_tab[i].div;
+  return 0;
+}
+
 static void
 real_config (struct grub_serial_port *port)
 {
+  grub_uint32_t divisor;
+  const grub_uint16_t parities[] = {
+    [GRUB_SERIAL_PARITY_NONE] = 0x0000,
+    [GRUB_SERIAL_PARITY_ODD] = 0x0100,
+    [GRUB_SERIAL_PARITY_EVEN] = 0x0200
+  };
+  const grub_uint16_t stop_bits[] = {
+    [GRUB_SERIAL_STOP_BITS_1] = 0x0000,
+    [GRUB_SERIAL_STOP_BITS_2] = 0x1000,
+  };
+
   if (port->configured)
     return;
 
+  grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
+                       GRUB_USBSERIAL_MODEM_CTRL,
+                       GRUB_USBSERIAL_MODEM_CTRL_DTRRTS, 0, 0, 0);
+
+  grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
+                       GRUB_USBSERIAL_FLOW_CTRL,
+                       GRUB_USBSERIAL_FLOW_CTRL_DTRRTS, 0, 0, 0);
+
+  divisor = get_divisor (port->config.speed);
+  grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
+                       GRUB_USBSERIAL_SPEED_CTRL,
+                       divisor & 0xffff, divisor >> 16, 0, 0);
+
+  grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT,
+                       GRUB_USBSERIAL_DATA_CTRL,
+                       parities[port->config.parity]
+                       | stop_bits[port->config.stop_bits] , 0, 0, 0);
+
   port->configured = 1;
 }
 
@@ -63,11 +129,25 @@ usbserial_hw_put (struct grub_serial_port *port, const int c)
   grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc);
 }
 
-/* FIXME */
 static grub_err_t
 usbserial_hw_configure (struct grub_serial_port *port,
                        struct grub_serial_config *config)
 {
+  grub_uint16_t divisor;
+
+  divisor = get_divisor (config->speed);
+  if (divisor == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
+
+  if (config->parity != GRUB_SERIAL_PARITY_NONE
+      && config->parity != GRUB_SERIAL_PARITY_ODD
+      && config->parity != GRUB_SERIAL_PARITY_EVEN)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity");
+
+  if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1
+      && config->stop_bits != GRUB_SERIAL_STOP_BITS_2)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits");
+
   port->config = *config;
   port->configured = 0;