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…
	
	Add table
		Add a link
		
	
		Reference in a new issue