some serial config support

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-07-18 14:43:23 +02:00
parent 8c8e269906
commit 1da07b142b
4 changed files with 124 additions and 24 deletions

View 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);

View 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;

View 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");
}

View file

@ -23,12 +23,78 @@
#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;