Support --base-clock for serial command to handle weird cards with
non-standard base clock.
This commit is contained in:
parent
eb03ede014
commit
89295a0628
4 changed files with 64 additions and 48 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2013-11-01 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Support --base-clock for serial command to handle weird cards with
|
||||||
|
non-standard base clock.
|
||||||
|
|
||||||
2013-11-01 Vladimir Serbinenko <phcoder@gmail.com>
|
2013-11-01 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* grub-core/fs/ext2.c (grub_ext2_read_symlink): Use memcpy rather
|
* grub-core/fs/ext2.c (grub_ext2_read_symlink): Use memcpy rather
|
||||||
|
|
|
@ -38,46 +38,33 @@ static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS;
|
||||||
|
|
||||||
static int dead_ports = 0;
|
static int dead_ports = 0;
|
||||||
|
|
||||||
|
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||||
|
#define DEFAULT_BASE_CLOCK (2 * 115200)
|
||||||
|
#else
|
||||||
|
#define DEFAULT_BASE_CLOCK 115200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Convert speed to divisor. */
|
/* Convert speed to divisor. */
|
||||||
static unsigned short
|
static unsigned short
|
||||||
serial_get_divisor (const struct grub_serial_port *port __attribute__ ((unused)),
|
serial_get_divisor (const struct grub_serial_port *port __attribute__ ((unused)),
|
||||||
const struct grub_serial_config *config)
|
const struct grub_serial_config *config)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
grub_uint32_t base_clock;
|
||||||
|
grub_uint32_t divisor;
|
||||||
|
grub_uint32_t actual_speed, error;
|
||||||
|
|
||||||
/* The structure for speed vs. divisor. */
|
base_clock = config->base_clock ? (config->base_clock >> 4) : DEFAULT_BASE_CLOCK;
|
||||||
struct divisor
|
|
||||||
{
|
|
||||||
unsigned int speed;
|
|
||||||
unsigned short div;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The table which lists common configurations. */
|
divisor = (base_clock + (config->speed / 2)) / config->speed;
|
||||||
/* 1843200 / (speed * 16) */
|
if (divisor > 0xffff || divisor == 0)
|
||||||
static struct divisor divisor_tab[] =
|
|
||||||
{
|
|
||||||
{ 2400, 0x0030 },
|
|
||||||
{ 4800, 0x0018 },
|
|
||||||
{ 9600, 0x000C },
|
|
||||||
{ 19200, 0x0006 },
|
|
||||||
{ 38400, 0x0003 },
|
|
||||||
{ 57600, 0x0002 },
|
|
||||||
{ 115200, 0x0001 }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Set the baud rate. */
|
|
||||||
for (i = 0; i < ARRAY_SIZE (divisor_tab); i++)
|
|
||||||
if (divisor_tab[i].speed == config->speed)
|
|
||||||
{
|
|
||||||
/* internal Loongson UART runs twice the usual rate. */
|
|
||||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
|
||||||
if (port->port == 0xbff003f8)
|
|
||||||
return 2 * divisor_tab[i].div;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
return divisor_tab[i].div;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
actual_speed = base_clock / divisor;
|
||||||
|
error = actual_speed > config->speed ? (actual_speed - config->speed)
|
||||||
|
: (config->speed - actual_speed);
|
||||||
|
if (error > (config->speed / 30 + 1))
|
||||||
|
return 0;
|
||||||
|
return divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -39,6 +39,17 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
|
#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OPTION_UNIT,
|
||||||
|
OPTION_PORT,
|
||||||
|
OPTION_SPEED,
|
||||||
|
OPTION_WORD,
|
||||||
|
OPTION_PARITY,
|
||||||
|
OPTION_STOP,
|
||||||
|
OPTION_BASE_CLOCK
|
||||||
|
};
|
||||||
|
|
||||||
/* Argument options. */
|
/* Argument options. */
|
||||||
static const struct grub_arg_option options[] =
|
static const struct grub_arg_option options[] =
|
||||||
{
|
{
|
||||||
|
@ -48,6 +59,7 @@ static const struct grub_arg_option options[] =
|
||||||
{"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT},
|
{"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT},
|
||||||
{"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING},
|
{"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING},
|
||||||
{"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT},
|
{"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT},
|
||||||
|
{"base-clock", 'b', 0, N_("Set the base clock."), 0, ARG_TYPE_INT},
|
||||||
{0, 0, 0, 0, 0, 0}
|
{0, 0, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,14 +190,14 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||||
struct grub_serial_config config;
|
struct grub_serial_config config;
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
|
|
||||||
if (state[0].set)
|
if (state[OPTION_UNIT].set)
|
||||||
{
|
{
|
||||||
grub_snprintf (pname, sizeof (pname), "com%ld",
|
grub_snprintf (pname, sizeof (pname), "com%ld",
|
||||||
grub_strtoul (state[0].arg, 0, 0));
|
grub_strtoul (state[0].arg, 0, 0));
|
||||||
name = pname;
|
name = pname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state[1].set)
|
if (state[OPTION_PORT].set)
|
||||||
{
|
{
|
||||||
grub_snprintf (pname, sizeof (pname), "port%lx",
|
grub_snprintf (pname, sizeof (pname), "port%lx",
|
||||||
grub_strtoul (state[1].arg, 0, 0));
|
grub_strtoul (state[1].arg, 0, 0));
|
||||||
|
@ -206,38 +218,48 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||||
|
|
||||||
config = port->config;
|
config = port->config;
|
||||||
|
|
||||||
if (state[2].set)
|
if (state[OPTION_SPEED].set)
|
||||||
config.speed = grub_strtoul (state[2].arg, 0, 0);
|
config.speed = grub_strtoul (state[OPTION_SPEED].arg, 0, 0);
|
||||||
|
|
||||||
if (state[3].set)
|
if (state[OPTION_WORD].set)
|
||||||
config.word_len = grub_strtoul (state[3].arg, 0, 0);
|
config.word_len = grub_strtoul (state[OPTION_WORD].arg, 0, 0);
|
||||||
|
|
||||||
if (state[4].set)
|
if (state[OPTION_PARITY].set)
|
||||||
{
|
{
|
||||||
if (! grub_strcmp (state[4].arg, "no"))
|
if (! grub_strcmp (state[OPTION_PARITY].arg, "no"))
|
||||||
config.parity = GRUB_SERIAL_PARITY_NONE;
|
config.parity = GRUB_SERIAL_PARITY_NONE;
|
||||||
else if (! grub_strcmp (state[4].arg, "odd"))
|
else if (! grub_strcmp (state[OPTION_PARITY].arg, "odd"))
|
||||||
config.parity = GRUB_SERIAL_PARITY_ODD;
|
config.parity = GRUB_SERIAL_PARITY_ODD;
|
||||||
else if (! grub_strcmp (state[4].arg, "even"))
|
else if (! grub_strcmp (state[OPTION_PARITY].arg, "even"))
|
||||||
config.parity = GRUB_SERIAL_PARITY_EVEN;
|
config.parity = GRUB_SERIAL_PARITY_EVEN;
|
||||||
else
|
else
|
||||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||||
N_("unsupported serial port parity"));
|
N_("unsupported serial port parity"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state[5].set)
|
if (state[OPTION_STOP].set)
|
||||||
{
|
{
|
||||||
if (! grub_strcmp (state[5].arg, "1"))
|
if (! grub_strcmp (state[OPTION_STOP].arg, "1"))
|
||||||
config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
|
config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
|
||||||
else if (! grub_strcmp (state[5].arg, "2"))
|
else if (! grub_strcmp (state[OPTION_STOP].arg, "2"))
|
||||||
config.stop_bits = GRUB_SERIAL_STOP_BITS_2;
|
config.stop_bits = GRUB_SERIAL_STOP_BITS_2;
|
||||||
else if (! grub_strcmp (state[5].arg, "1.5"))
|
else if (! grub_strcmp (state[OPTION_STOP].arg, "1.5"))
|
||||||
config.stop_bits = GRUB_SERIAL_STOP_BITS_1_5;
|
config.stop_bits = GRUB_SERIAL_STOP_BITS_1_5;
|
||||||
else
|
else
|
||||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||||
N_("unsupported serial port stop bits number"));
|
N_("unsupported serial port stop bits number"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state[OPTION_BASE_CLOCK].set)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
config.base_clock = grub_strtoull (state[OPTION_BASE_CLOCK].arg, &ptr, 0);
|
||||||
|
if (ptr && *ptr == 'M')
|
||||||
|
config.base_clock *= 1000000;
|
||||||
|
if (ptr && (*ptr == 'k' || *ptr == 'K'))
|
||||||
|
config.base_clock *= 1000;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize with new settings. */
|
/* Initialize with new settings. */
|
||||||
err = port->driver->configure (port, &config);
|
err = port->driver->configure (port, &config);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct grub_serial_config
|
||||||
int word_len;
|
int word_len;
|
||||||
grub_serial_parity_t parity;
|
grub_serial_parity_t parity;
|
||||||
grub_serial_stop_bits_t stop_bits;
|
grub_serial_stop_bits_t stop_bits;
|
||||||
|
grub_uint64_t base_clock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct grub_serial_port
|
struct grub_serial_port
|
||||||
|
@ -163,7 +164,8 @@ grub_serial_config_defaults (struct grub_serial_port *port)
|
||||||
#endif
|
#endif
|
||||||
.word_len = 8,
|
.word_len = 8,
|
||||||
.parity = GRUB_SERIAL_PARITY_NONE,
|
.parity = GRUB_SERIAL_PARITY_NONE,
|
||||||
.stop_bits = GRUB_SERIAL_STOP_BITS_1
|
.stop_bits = GRUB_SERIAL_STOP_BITS_1,
|
||||||
|
.base_clock = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return port->driver->configure (port, &config);
|
return port->driver->configure (port, &config);
|
||||||
|
|
Loading…
Reference in a new issue