some serial config support
This commit is contained in:
parent
8c8e269906
commit
1da07b142b
4 changed files with 124 additions and 24 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue