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
)
128 status
= BS
->LocateHandle(ByProtocol
, &serial
, NULL
, &bufsz
, handles
);
129 if (status
!= EFI_BUFFER_TOO_SMALL
)
132 if ((handles
= malloc(bufsz
)) == NULL
)
135 *nhandles
= (int)(bufsz
/sizeof (EFI_HANDLE
));
139 status
= BS
->LocateHandle(ByProtocol
, &serial
, NULL
, &bufsz
, handles
);
140 if (EFI_ERROR(status
)) {
149 comc_probe(struct console
*cp
)
156 EFI_HANDLE
*handles
= NULL
; /* array of handles */
157 int nhandles
= 0; /* number of handles in array */
159 /* are we already set up? */
160 if (cp
->c_private
!= NULL
)
163 /* make sure the handles are available */
164 status
= efi_serial_init(&handles
, &nhandles
);
166 cp
->c_private
= malloc(sizeof (struct serial
));
167 port
= cp
->c_private
;
168 port
->baudrate
= COMSPEED
;
170 if (strcmp(cp
->c_name
, "ttya") == 0)
172 else if (strcmp(cp
->c_name
, "ttyb") == 0)
174 else if (strcmp(cp
->c_name
, "ttyc") == 0)
176 else if (strcmp(cp
->c_name
, "ttyd") == 0)
179 if (port
->ioaddr
>= nhandles
)
180 port
->ioaddr
= -1; /* invalid port */
182 port
->databits
= 8; /* 8,n,1 */
183 port
->parity
= NoParity
; /* 8,n,1 */
184 port
->stopbits
= OneStopBit
; /* 8,n,1 */
185 port
->ignore_cd
= 1; /* ignore cd */
186 port
->rtsdtr_off
= 0; /* rts-dtr is on */
189 if (port
->ioaddr
!= -1) {
190 status
= BS
->OpenProtocol(handles
[port
->ioaddr
],
191 &serial
, (void**)&port
->sio
, IH
, NULL
,
192 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
194 if (EFI_ERROR(status
))
195 port
->ioaddr
= -1; /* invalid port */
200 snprintf(name
, sizeof (name
), "%s-mode", cp
->c_name
);
204 (void) comc_parse_mode(port
, env
);
206 env
= comc_asprint_mode(port
);
210 env_setenv(name
, EV_VOLATILE
, env
, comc_mode_set
, env_nounset
);
214 snprintf(name
, sizeof (name
), "%s-ignore-cd", cp
->c_name
);
217 if (strcmp(env
, "true") == 0)
219 else if (strcmp(env
, "false") == 0)
223 snprintf(value
, sizeof (value
), "%s",
224 port
->ignore_cd
? "true" : "false");
226 env_setenv(name
, EV_VOLATILE
, value
, comc_cd_set
, env_nounset
);
228 snprintf(name
, sizeof (name
), "%s-rts-dtr-off", cp
->c_name
);
231 if (strcmp(env
, "true") == 0)
232 port
->rtsdtr_off
= 1;
233 else if (strcmp(env
, "false") == 0)
234 port
->rtsdtr_off
= 0;
237 snprintf(value
, sizeof (value
), "%s",
238 port
->rtsdtr_off
? "true" : "false");
240 env_setenv(name
, EV_VOLATILE
, value
, comc_rtsdtr_set
, env_nounset
);
245 comc_init(struct console
*cp
, int arg
__attribute((unused
)))
250 if ((cp
->c_flags
& (C_PRESENTIN
| C_PRESENTOUT
)) ==
251 (C_PRESENTIN
| C_PRESENTOUT
))
257 comc_putchar(struct console
*cp
, int c
)
263 struct serial
*sp
= cp
->c_private
;
268 for (wait
= COMC_TXWAIT
; wait
> 0; wait
--) {
269 status
= sp
->sio
->Write(sp
->sio
, &bufsz
, &cb
);
270 if (status
!= EFI_TIMEOUT
)
276 comc_getchar(struct console
*cp
)
281 struct serial
*sp
= cp
->c_private
;
283 if (sp
->sio
== NULL
|| !comc_ischar(cp
))
286 status
= sp
->sio
->Read(sp
->sio
, &bufsz
, &c
);
287 if (EFI_ERROR(status
) || bufsz
== 0)
294 comc_ischar(struct console
*cp
)
298 struct serial
*sp
= cp
->c_private
;
303 status
= sp
->sio
->GetControl(sp
->sio
, &control
);
304 if (EFI_ERROR(status
))
307 return (!(status
& EFI_SERIAL_INPUT_BUFFER_EMPTY
));
311 comc_asprint_mode(struct serial
*sp
)
313 char par
= 'n', *buf
;
319 switch (sp
->parity
) {
320 case NoParity
: par
= 'n';
322 case EvenParity
: par
= 'e';
324 case OddParity
: par
= 'o';
327 switch (sp
->stopbits
) {
328 case OneStopBit
: stop
= 1;
330 case TwoStopBits
: stop
= 2;
334 asprintf(&buf
, "%ju,%d,%c,%d,-", sp
->baudrate
, sp
->databits
, par
, stop
);
339 comc_parse_mode(struct serial
*sp
, const char *value
)
343 uint8_t databits
= 8;
344 int parity
= NoParity
;
345 int stopbits
= OneStopBit
;
348 if (value
== NULL
|| *value
== '\0')
352 n
= strtoul(value
, &ep
, 10);
353 if (errno
!= 0 || *ep
!= ',')
358 n
= strtoul(ep
, &ep
, 10);
359 if (errno
!= 0 || *ep
!= ',')
363 case 7: databits
= 7;
365 case 8: databits
= 8;
373 case 'n': parity
= NoParity
;
375 case 'e': parity
= EvenParity
;
377 case 'o': parity
= OddParity
;
389 case '1': stopbits
= OneStopBit
;
391 case '2': stopbits
= TwoStopBits
;
397 /* handshake is ignored, but we check syntax anyhow */
415 sp
->baudrate
= baudrate
;
416 sp
->databits
= databits
;
418 sp
->stopbits
= stopbits
;
422 static struct console
*
423 get_console(char *name
)
425 struct console
*cp
= NULL
;
428 case 'a': cp
= &ttya
;
430 case 'b': cp
= &ttyb
;
432 case 'c': cp
= &ttyc
;
434 case 'd': cp
= &ttyd
;
441 comc_mode_set(struct env_var
*ev
, int flags
, const void *value
)
448 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
451 if (comc_parse_mode(cp
->c_private
, value
) == CMD_ERROR
)
455 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
461 comc_cd_set(struct env_var
*ev
, int flags
, const void *value
)
469 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
473 if (strcmp(value
, "true") == 0)
475 else if (strcmp(value
, "false") == 0)
481 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
487 comc_rtsdtr_set(struct env_var
*ev
, int flags
, const void *value
)
495 if ((cp
= get_console(ev
->ev_name
)) == NULL
)
499 if (strcmp(value
, "true") == 0)
501 else if (strcmp(value
, "false") == 0)
507 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
513 comc_setup(struct console
*cp
)
517 struct serial
*sp
= cp
->c_private
;
519 if ((cp
->c_flags
& (C_ACTIVEIN
| C_ACTIVEOUT
)) == 0)
522 /* port is not usable */
523 if (sp
->sio
== NULL
) {
524 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
528 cp
->c_flags
|= (C_PRESENTIN
| C_PRESENTOUT
);
529 status
= sp
->sio
->Reset(sp
->sio
);
530 if (EFI_ERROR(status
)) {
531 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
534 status
= sp
->sio
->SetAttributes(sp
->sio
, sp
->baudrate
, 0, 0, sp
->parity
,
535 sp
->databits
, sp
->stopbits
);
536 if (EFI_ERROR(status
)) {
537 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
540 if (sp
->rtsdtr_off
) {
541 status
= sp
->sio
->GetControl(sp
->sio
, &control
);
542 if (EFI_ERROR(status
)) {
543 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);
545 control
&= ~(EFI_SERIAL_REQUEST_TO_SEND
|
546 EFI_SERIAL_DATA_TERMINAL_READY
);
547 status
= sp
->sio
->SetControl(sp
->sio
, control
);
548 if (EFI_ERROR(status
)) {
549 cp
->c_flags
&= ~(C_PRESENTIN
| C_PRESENTOUT
);