2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
29 #include <sys/errno.h>
30 #include <bootstrap.h>
35 #include "loader_efi.h"
37 static EFI_GUID serial
= SERIAL_IO_PROTOCOL
;
39 #define COMC_TXWAIT 0x40000 /* transmit timeout */
48 EFI_PARITY_TYPE parity
;
49 EFI_STOP_BITS_TYPE stopbits
;
50 uint8_t ignore_cd
; /* boolean */
51 uint8_t rtsdtr_off
; /* boolean */
52 int ioaddr
; /* index in handles array */
53 SERIAL_IO_INTERFACE
*sio
;
56 static void comc_probe(struct console
*);
57 static int comc_init(struct console
*, int);
58 static void comc_putchar(struct console
*, int);
59 static int comc_getchar(struct console
*);
60 static int comc_ischar(struct console
*);
61 static void comc_setup(struct console
*);
62 static char *comc_asprint_mode(struct serial
*);
63 static int comc_parse_mode(struct serial
*, const char *);
64 static int comc_mode_set(struct env_var
*, int, const void *);
65 static int comc_cd_set(struct env_var
*, int, const void *);
66 static int comc_rtsdtr_set(struct env_var
*, int, const void *);
68 struct console ttya
= {
70 .c_desc
= "serial port a",
72 .c_probe
= comc_probe
,
74 .c_out
= comc_putchar
,
76 .c_ready
= comc_ischar
,
80 struct console ttyb
= {
82 .c_desc
= "serial port b",
84 .c_probe
= comc_probe
,
86 .c_out
= comc_putchar
,
88 .c_ready
= comc_ischar
,
92 struct console ttyc
= {
94 .c_desc
= "serial port c",
96 .c_probe
= comc_probe
,
98 .c_out
= comc_putchar
,
100 .c_ready
= comc_ischar
,
104 struct console ttyd
= {
106 .c_desc
= "serial port d",
108 .c_probe
= comc_probe
,
110 .c_out
= comc_putchar
,
111 .c_in
= comc_getchar
,
112 .c_ready
= comc_ischar
,
117 efi_serial_init(EFI_HANDLE
**handlep
, int *nhandles
)
127 status
= BS
->LocateHandle(ByProtocol
, &serial
, NULL
, &bufsz
, handles
);
128 if (status
!= EFI_BUFFER_TOO_SMALL
)
131 if ((handles
= malloc(bufsz
)) == NULL
)
134 *nhandles
= (int)(bufsz
/sizeof (EFI_HANDLE
));
138 status
= BS
->LocateHandle(ByProtocol
, &serial
, NULL
, &bufsz
, handles
);
139 if (EFI_ERROR(status
)) {
148 comc_probe(struct console
*cp
)
155 EFI_HANDLE
*handles
= NULL
; /* array of handles */
156 int nhandles
= 0; /* number of handles in array */
158 /* are we already set up? */
159 if (cp
->c_private
!= NULL
)
162 /* make sure the handles are available */
163 status
= efi_serial_init(&handles
, &nhandles
);
165 cp
->c_private
= malloc(sizeof (struct serial
));
166 port
= cp
->c_private
;
167 port
->baudrate
= COMSPEED
;
169 if (strcmp(cp
->c_name
, "ttya") == 0)
171 else if (strcmp(cp
->c_name
, "ttyb") == 0)
173 else if (strcmp(cp
->c_name
, "ttyc") == 0)
175 else if (strcmp(cp
->c_name
, "ttyd") == 0)
178 if (port
->ioaddr
>= nhandles
)
179 port
->ioaddr
= -1; /* invalid port */
181 port
->databits
= 8; /* 8,n,1 */
182 port
->parity
= NoParity
; /* 8,n,1 */
183 port
->stopbits
= OneStopBit
; /* 8,n,1 */
184 port
->ignore_cd
= 1; /* ignore cd */
185 port
->rtsdtr_off
= 0; /* rts-dtr is on */
188 if (port
->ioaddr
!= -1) {
189 status
= BS
->OpenProtocol(handles
[port
->ioaddr
],
190 &serial
, (void**)&port
->sio
, IH
, NULL
,
191 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
193 if (EFI_ERROR(status
))
194 port
->ioaddr
= -1; /* invalid port */
199 snprintf(name
, sizeof (name
), "%s-mode", cp
->c_name
);
203 (void) comc_parse_mode(port
, env
);
205 env
= comc_asprint_mode(port
);
209 env_setenv(name
, EV_VOLATILE
, env
, comc_mode_set
, env_nounset
);
213 snprintf(name
, sizeof (name
), "%s-ignore-cd", cp
->c_name
);
216 if (strcmp(env
, "true") == 0)
218 else if (strcmp(env
, "false") == 0)
222 snprintf(value
, sizeof (value
), "%s",
223 port
->ignore_cd
? "true" : "false");
225 env_setenv(name
, EV_VOLATILE
, value
, comc_cd_set
, env_nounset
);
227 snprintf(name
, sizeof (name
), "%s-rts-dtr-off", cp
->c_name
);
230 if (strcmp(env
, "true") == 0)
231 port
->rtsdtr_off
= 1;
232 else if (strcmp(env
, "false") == 0)
233 port
->rtsdtr_off
= 0;
236 snprintf(value
, sizeof (value
), "%s",
237 port
->rtsdtr_off
? "true" : "false");
239 env_setenv(name
, EV_VOLATILE
, value
, comc_rtsdtr_set
, env_nounset
);
244 comc_init(struct console
*cp
, int arg
__attribute((unused
)))
249 if ((cp
->c_flags
& (C_PRESENTIN
| C_PRESENTOUT
)) ==
250 (C_PRESENTIN
| C_PRESENTOUT
))
256 comc_putchar(struct console
*cp
, int c
)
262 struct serial
*sp
= cp
->c_private
;
267 for (wait
= COMC_TXWAIT
; wait
> 0; wait
--) {
268 status
= sp
->sio
->Write(sp
->sio
, &bufsz
, &cb
);
269 if (status
!= EFI_TIMEOUT
)
275 comc_getchar(struct console
*cp
)
280 struct serial
*sp
= cp
->c_private
;
282 if (sp
->sio
== NULL
|| !comc_ischar(cp
))
285 status
= sp
->sio
->Read(sp
->sio
, &bufsz
, &c
);
286 if (EFI_ERROR(status
) || bufsz
== 0)
293 comc_ischar(struct console
*cp
)
297 struct serial
*sp
= cp
->c_private
;
302 status
= sp
->sio
->GetControl(sp
->sio
, &control
);
303 if (EFI_ERROR(status
))
306 return (!(status
& EFI_SERIAL_INPUT_BUFFER_EMPTY
));
310 comc_asprint_mode(struct serial
*sp
)
312 char par
= 'n', *buf
;
318 switch (sp
->parity
) {
319 case NoParity
: par
= 'n';
321 case EvenParity
: par
= 'e';
323 case OddParity
: par
= 'o';
326 switch (sp
->stopbits
) {
327 case OneStopBit
: stop
= 1;
329 case TwoStopBits
: stop
= 2;
333 asprintf(&buf
, "%ju,%d,%c,%d,-", sp
->baudrate
, sp
->databits
, par
, stop
);
338 comc_parse_mode(struct serial
*sp
, const char *value
)
342 uint8_t databits
= 8;
343 int parity
= NoParity
;
344 int stopbits
= OneStopBit
;
347 if (value
== NULL
|| *value
== '\0')
351 n
= strtoul(value
, &ep
, 10);
352 if (errno
!= 0 || *ep
!= ',')
357 n
= strtoul(ep
, &ep
, 10);
358 if (errno
!= 0 || *ep
!= ',')
362 case 7: databits
= 7;
364 case 8: databits
= 8;
372 case 'n': parity
= NoParity
;
374 case 'e': parity
= EvenParity
;
376 case 'o': parity
= OddParity
;
388 case '1': stopbits
= OneStopBit
;
390 case '2': stopbits
= TwoStopBits
;
396 /* handshake is ignored, but we check syntax anyhow */
414 sp
->baudrate
= baudrate
;
415 sp
->databits
= databits
;
417 sp
->stopbits
= stopbits
;
421 static struct console
*
422 get_console(char *name
)
424 struct console
*cp
= NULL
;
427 case 'a': cp
= &ttya
;
429 case 'b': cp
= &ttyb
;
431 case 'c': cp
= &ttyc
;
433 case 'd': cp
= &ttyd
;
440 comc_mode_set(struct env_var
*ev
, int flags
, const void *value
)
447 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
450 if (comc_parse_mode(cp
->c_private
, value
) == CMD_ERROR
)
454 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
460 comc_cd_set(struct env_var
*ev
, int flags
, const void *value
)
468 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
472 if (strcmp(value
, "true") == 0)
474 else if (strcmp(value
, "false") == 0)
480 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
486 comc_rtsdtr_set(struct env_var
*ev
, int flags
, const void *value
)
494 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
498 if (strcmp(value
, "true") == 0)
500 else if (strcmp(value
, "false") == 0)
506 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
512 comc_setup(struct console
*cp
)
516 struct serial
*sp
= cp
->c_private
;
518 if ((cp
->c_flags
& (C_ACTIVEIN
| C_ACTIVEOUT
)) == 0)
521 /* port is not usable */
522 if (sp
->sio
== NULL
) {
523 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
527 cp
->c_flags
|= (C_PRESENTIN
| C_PRESENTOUT
);
528 status
= sp
->sio
->Reset(sp
->sio
);
529 if (EFI_ERROR(status
)) {
530 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
533 status
= sp
->sio
->SetAttributes(sp
->sio
, sp
->baudrate
, 0, 0, sp
->parity
,
534 sp
->databits
, sp
->stopbits
);
535 if (EFI_ERROR(status
)) {
536 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
539 if (sp
->rtsdtr_off
) {
540 status
= sp
->sio
->GetControl(sp
->sio
, &control
);
541 if (EFI_ERROR(status
)) {
542 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
544 control
&= ~(EFI_SERIAL_REQUEST_TO_SEND
|
545 EFI_SERIAL_DATA_TERMINAL_READY
);
546 status
= sp
->sio
->SetControl(sp
->sio
, control
);
547 if (EFI_ERROR(status
)) {
548 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);