2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/serial.h>
20 #include <grub/term.h>
21 #include <grub/types.h>
23 #include <grub/misc.h>
24 #include <grub/terminfo.h>
25 #if !defined (GRUB_MACHINE_EMU) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
26 #include <grub/cpu/io.h>
28 #include <grub/extcmd.h>
29 #include <grub/i18n.h>
30 #include <grub/list.h>
31 #ifdef GRUB_MACHINE_MIPS_LOONGSON
32 #include <grub/machine/kernel.h>
34 #ifdef GRUB_MACHINE_IEEE1275
35 #include <grub/ieee1275/console.h>
38 GRUB_MOD_LICENSE ("GPLv3+");
40 #define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
54 /* Argument options. */
55 static const struct grub_arg_option options
[] =
57 {"unit", 'u', 0, N_("Set the serial unit."), 0, ARG_TYPE_INT
},
58 {"port", 'p', 0, N_("Set the serial port address."), 0, ARG_TYPE_STRING
},
59 {"speed", 's', 0, N_("Set the serial port speed."), 0, ARG_TYPE_INT
},
60 {"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT
},
61 {"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING
},
62 {"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT
},
63 {"base-clock", 'b', 0, N_("Set the base frequency."), 0, ARG_TYPE_STRING
},
64 {"rtscts", 'f', 0, N_("Enable/disable RTS/CTS."), "on|off", ARG_TYPE_STRING
},
68 static struct grub_serial_port
*grub_serial_ports
;
70 struct grub_serial_output_state
72 struct grub_terminfo_output_state tinfo
;
73 struct grub_serial_port
*port
;
76 struct grub_serial_input_state
78 struct grub_terminfo_input_state tinfo
;
79 struct grub_serial_port
*port
;
83 serial_put (grub_term_output_t term
, const int c
)
85 struct grub_serial_output_state
*data
= term
->data
;
86 data
->port
->driver
->put (data
->port
, c
);
90 serial_fetch (grub_term_input_t term
)
92 struct grub_serial_input_state
*data
= term
->data
;
93 return data
->port
->driver
->fetch (data
->port
);
96 static const struct grub_serial_input_state grub_serial_terminfo_input_template
=
100 .readkey
= serial_fetch
104 static const struct grub_serial_output_state grub_serial_terminfo_output_template
=
113 static struct grub_serial_input_state grub_serial_terminfo_input
;
115 static struct grub_serial_output_state grub_serial_terminfo_output
;
117 static int registered
= 0;
119 static struct grub_term_input grub_serial_term_input
=
122 .init
= grub_terminfo_input_init
,
123 .getkey
= grub_terminfo_getkey
,
124 .data
= &grub_serial_terminfo_input
127 static struct grub_term_output grub_serial_term_output
=
130 .init
= grub_terminfo_output_init
,
131 .putchar
= grub_terminfo_putchar
,
132 .getwh
= grub_terminfo_getwh
,
133 .getxy
= grub_terminfo_getxy
,
134 .gotoxy
= grub_terminfo_gotoxy
,
135 .cls
= grub_terminfo_cls
,
136 .setcolorstate
= grub_terminfo_setcolorstate
,
137 .setcursor
= grub_terminfo_setcursor
,
138 .flags
= GRUB_TERM_CODE_TYPE_ASCII
,
139 .data
= &grub_serial_terminfo_output
,
140 .progress_update_divisor
= GRUB_PROGRESS_SLOW
145 struct grub_serial_port
*
146 grub_serial_find (const char *name
)
148 struct grub_serial_port
*port
;
150 FOR_SERIAL_PORTS (port
)
151 if (grub_strcmp (port
->name
, name
) == 0)
154 #if (defined(__mips__) || defined (__i386__) || defined (__x86_64__)) && !defined(GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC)
155 if (!port
&& grub_memcmp (name
, "port", sizeof ("port") - 1) == 0
156 && grub_isxdigit (name
[sizeof ("port") - 1]))
158 name
= grub_serial_ns8250_add_port (grub_strtoul (&name
[sizeof ("port") - 1],
163 FOR_SERIAL_PORTS (port
)
164 if (grub_strcmp (port
->name
, name
) == 0)
169 #ifdef GRUB_MACHINE_IEEE1275
170 if (!port
&& grub_memcmp (name
, "ieee1275/", sizeof ("ieee1275/") - 1) == 0)
172 name
= grub_ofserial_add_port (&name
[sizeof ("ieee1275/") - 1]);
176 FOR_SERIAL_PORTS (port
)
177 if (grub_strcmp (port
->name
, name
) == 0)
186 grub_cmd_serial (grub_extcmd_context_t ctxt
, int argc
, char **args
)
188 struct grub_arg_list
*state
= ctxt
->state
;
190 const char *name
= NULL
;
191 struct grub_serial_port
*port
;
192 struct grub_serial_config config
;
195 if (state
[OPTION_UNIT
].set
)
197 grub_snprintf (pname
, sizeof (pname
), "com%ld",
198 grub_strtoul (state
[0].arg
, 0, 0));
202 if (state
[OPTION_PORT
].set
)
204 grub_snprintf (pname
, sizeof (pname
), "port%lx",
205 grub_strtoul (state
[1].arg
, 0, 0));
215 port
= grub_serial_find (name
);
217 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
218 N_("serial port `%s' isn't found"),
221 config
= port
->config
;
223 if (state
[OPTION_SPEED
].set
) {
224 config
.speed
= grub_strtoul (state
[OPTION_SPEED
].arg
, 0, 0);
225 if (config
.speed
== 0)
226 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
227 N_("unsupported serial port parity"));
230 if (state
[OPTION_WORD
].set
)
231 config
.word_len
= grub_strtoul (state
[OPTION_WORD
].arg
, 0, 0);
233 if (state
[OPTION_PARITY
].set
)
235 if (! grub_strcmp (state
[OPTION_PARITY
].arg
, "no"))
236 config
.parity
= GRUB_SERIAL_PARITY_NONE
;
237 else if (! grub_strcmp (state
[OPTION_PARITY
].arg
, "odd"))
238 config
.parity
= GRUB_SERIAL_PARITY_ODD
;
239 else if (! grub_strcmp (state
[OPTION_PARITY
].arg
, "even"))
240 config
.parity
= GRUB_SERIAL_PARITY_EVEN
;
242 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
243 N_("unsupported serial port parity"));
246 if (state
[OPTION_RTSCTS
].set
)
248 if (grub_strcmp (state
[OPTION_RTSCTS
].arg
, "on") == 0)
250 else if (grub_strcmp (state
[OPTION_RTSCTS
].arg
, "off") == 0)
253 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
254 N_("unsupported serial port flow control"));
257 if (state
[OPTION_STOP
].set
)
259 if (! grub_strcmp (state
[OPTION_STOP
].arg
, "1"))
260 config
.stop_bits
= GRUB_SERIAL_STOP_BITS_1
;
261 else if (! grub_strcmp (state
[OPTION_STOP
].arg
, "2"))
262 config
.stop_bits
= GRUB_SERIAL_STOP_BITS_2
;
263 else if (! grub_strcmp (state
[OPTION_STOP
].arg
, "1.5"))
264 config
.stop_bits
= GRUB_SERIAL_STOP_BITS_1_5
;
266 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
267 N_("unsupported serial port stop bits number"));
270 if (state
[OPTION_BASE_CLOCK
].set
)
273 config
.base_clock
= grub_strtoull (state
[OPTION_BASE_CLOCK
].arg
, &ptr
, 0);
276 if (ptr
&& *ptr
== 'M')
277 config
.base_clock
*= 1000000;
278 if (ptr
&& (*ptr
== 'k' || *ptr
== 'K'))
279 config
.base_clock
*= 1000;
282 if (config
.speed
== 0)
285 /* Initialize with new settings. */
286 err
= port
->driver
->configure (port
, &config
);
289 #if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
291 /* Compatibility kludge. */
292 if (port
->driver
== &grub_ns8250_driver
)
296 grub_terminfo_output_register (&grub_serial_term_output
, "vt100");
298 grub_term_register_input ("serial", &grub_serial_term_input
);
299 grub_term_register_output ("serial", &grub_serial_term_output
);
301 grub_serial_terminfo_output
.port
= port
;
302 grub_serial_terminfo_input
.port
= port
;
306 return GRUB_ERR_NONE
;
309 #ifdef GRUB_MACHINE_MIPS_LOONGSON
310 const char loongson_defserial
[][6] =
312 [GRUB_ARCH_MACHINE_YEELOONG
] = "com0",
313 [GRUB_ARCH_MACHINE_FULOONG2F
] = "com2",
314 [GRUB_ARCH_MACHINE_FULOONG2E
] = "com1"
319 grub_serial_register (struct grub_serial_port
*port
)
321 struct grub_term_input
*in
;
322 struct grub_term_output
*out
;
323 struct grub_serial_input_state
*indata
;
324 struct grub_serial_output_state
*outdata
;
326 in
= grub_malloc (sizeof (*in
));
330 indata
= grub_malloc (sizeof (*indata
));
337 grub_memcpy (in
, &grub_serial_term_input
, sizeof (*in
));
339 in
->name
= grub_xasprintf ("serial_%s", port
->name
);
340 grub_memcpy (indata
, &grub_serial_terminfo_input
, sizeof (*indata
));
349 out
= grub_zalloc (sizeof (*out
));
353 grub_free ((char *) in
->name
);
358 outdata
= grub_malloc (sizeof (*outdata
));
362 grub_free ((char *) in
->name
);
368 grub_memcpy (out
, &grub_serial_term_output
, sizeof (*out
));
370 out
->name
= in
->name
;
371 grub_memcpy (outdata
, &grub_serial_terminfo_output
, sizeof (*outdata
));
373 grub_list_push (GRUB_AS_LIST_P (&grub_serial_ports
), GRUB_AS_LIST (port
));
374 ((struct grub_serial_input_state
*) in
->data
)->port
= port
;
375 ((struct grub_serial_output_state
*) out
->data
)->port
= port
;
377 port
->term_out
= out
;
378 grub_terminfo_output_register (out
, "vt100");
379 #ifdef GRUB_MACHINE_MIPS_LOONGSON
380 if (grub_strcmp (port
->name
, loongson_defserial
[grub_arch_machine
]) == 0)
382 grub_term_register_input_active ("serial_*", in
);
383 grub_term_register_output_active ("serial_*", out
);
387 grub_term_register_input_inactive ("serial_*", in
);
388 grub_term_register_output_inactive ("serial_*", out
);
391 grub_term_register_input ("serial_*", in
);
392 grub_term_register_output ("serial_*", out
);
395 return GRUB_ERR_NONE
;
399 grub_serial_unregister (struct grub_serial_port
*port
)
401 if (port
->driver
->fini
)
402 port
->driver
->fini (port
);
405 grub_term_unregister_input (port
->term_in
);
407 grub_term_unregister_output (port
->term_out
);
409 grub_list_remove (GRUB_AS_LIST (port
));
413 grub_serial_unregister_driver (struct grub_serial_driver
*driver
)
415 struct grub_serial_port
*port
, *next
;
416 for (port
= grub_serial_ports
; port
; port
= next
)
419 if (port
->driver
== driver
)
420 grub_serial_unregister (port
);
424 static grub_extcmd_t cmd
;
426 GRUB_MOD_INIT(serial
)
428 cmd
= grub_register_extcmd ("serial", grub_cmd_serial
, 0,
430 N_("Configure serial port."), options
);
431 grub_memcpy (&grub_serial_terminfo_output
,
432 &grub_serial_terminfo_output_template
,
433 sizeof (grub_serial_terminfo_output
));
435 grub_memcpy (&grub_serial_terminfo_input
,
436 &grub_serial_terminfo_input_template
,
437 sizeof (grub_serial_terminfo_input
));
439 #if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
442 #ifdef GRUB_MACHINE_IEEE1275
443 grub_ofserial_init ();
445 #ifdef GRUB_MACHINE_EFI
446 grub_efiserial_init ();
448 #ifdef GRUB_MACHINE_ARC
449 grub_arcserial_init ();
453 GRUB_MOD_FINI(serial
)
455 while (grub_serial_ports
)
456 grub_serial_unregister (grub_serial_ports
);
459 grub_term_unregister_input (&grub_serial_term_input
);
460 grub_term_unregister_output (&grub_serial_term_output
);
462 grub_unregister_extcmd (cmd
);