mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-17 10:18:38 +00:00
Merge branch 'next' of https://source.denx.de/u-boot/custodians/u-boot-marvell into next
- kwboot higher baudrate (Pali & Marek)
This commit is contained in:
commit
570320da3b
6 changed files with 1404 additions and 319 deletions
10
MAINTAINERS
10
MAINTAINERS
|
@ -775,6 +775,16 @@ S: Maintained
|
|||
T: git https://source.denx.de/u-boot/custodians/u-boot-i2c.git
|
||||
F: drivers/i2c/
|
||||
|
||||
KWBIMAGE / KWBOOT TOOLS
|
||||
M: Pali Rohár <pali@kernel.org>
|
||||
M: Marek Behún <marek.behun@nic.cz>
|
||||
M: Stefan Roese <sr@denx.de>
|
||||
S: Maintained
|
||||
T: git https://source.denx.de/u-boot/custodians/u-boot-marvell.git
|
||||
F: doc/README.kwbimage
|
||||
F: doc/kwboot.1
|
||||
F: tools/kwb*
|
||||
|
||||
LOGGING
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
|
|
60
doc/kwboot.1
60
doc/kwboot.1
|
@ -1,21 +1,22 @@
|
|||
.TH KWBOOT 1 "2012-05-19"
|
||||
.TH KWBOOT 1 "2021-08-25"
|
||||
|
||||
.SH NAME
|
||||
kwboot \- Boot Marvell Kirkwood SoCs over a serial link.
|
||||
kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link.
|
||||
.SH SYNOPSIS
|
||||
.B kwboot
|
||||
.RB [ "-b \fIimage\fP" ]
|
||||
.RB [ "-p" ]
|
||||
.RB [ "-t" ]
|
||||
.RB [ "-B \fIbaudrate\fP" ]
|
||||
.RB \fITTY\fP
|
||||
.SH "DESCRIPTION"
|
||||
|
||||
The \fBmkimage\fP program boots boards based on Marvell's Kirkwood
|
||||
platform over their integrated UART. Boot image files will typically
|
||||
The \fBkwboot\fP program boots boards based on Marvell's 32-bit
|
||||
platforms including Kirkwood, Dove, A370, AXP, A375, A38x
|
||||
and A39x over their integrated UART. Boot image files will typically
|
||||
contain a second stage boot loader, such as U-Boot. The image file
|
||||
must conform to Marvell's BootROM firmware image format
|
||||
(\fIkwbimage\fP), created using a tool such as \fBmkimage\fP.
|
||||
(\fIkwbimage v0\fP or \fIv1\fP), created using a tool such as
|
||||
\fBmkimage\fP.
|
||||
|
||||
Following power-up or a system reset, system BootROM code polls the
|
||||
UART for a brief period of time, sensing a handshake message which
|
||||
|
@ -36,25 +37,23 @@ by the second-stage loader.
|
|||
Handshake; then upload file \fIimage\fP over \fITTY\fP.
|
||||
|
||||
Note that for the encapsulated boot code to be executed, \fIimage\fP
|
||||
must be of type "UART boot" (0x69). Boot images of different types,
|
||||
such as backup images of vendor firmware downloaded from flash memory
|
||||
(type 0x8B), will not work (or not as expected). See \fB-p\fP for a
|
||||
workaround.
|
||||
must be of type "UART boot" (0x69). The \fBkwboot\fP program changes
|
||||
this type automatically, unless the \fIimage\fP is signed, in which
|
||||
case it cannot be changed.
|
||||
|
||||
This mode writes handshake status and upload progress indication to
|
||||
stdout.
|
||||
stdout. It is possible that \fIimage\fP contains an optional binary
|
||||
code in it's header which may also print some output via UART (for
|
||||
example U-Boot SPL does this). In such a case, this output is also
|
||||
written to stdout after the header is sent.
|
||||
|
||||
.TP
|
||||
.BI "\-p"
|
||||
In combination with \fB-b\fP, patches the header in \fIimage\fP prior
|
||||
to upload, to "UART boot" type.
|
||||
Obsolete. Does nothing.
|
||||
|
||||
This option attempts on-the-fly conversion of some none-UART image
|
||||
types, such as images which were originally formatted to be stored in
|
||||
flash memory.
|
||||
|
||||
Conversion is performed in memory. The contents of \fIimage\fP will
|
||||
not be altered.
|
||||
In the past, when this option was used, the program patched the header
|
||||
in the image prior upload, to "UART boot" type. This is now done by
|
||||
default.
|
||||
|
||||
.TP
|
||||
.BI "\-t"
|
||||
|
@ -65,11 +64,26 @@ If used in combination with \fB-b\fP, terminal mode is entered
|
|||
immediately following a successful image upload.
|
||||
|
||||
If standard I/O streams connect to a console, this mode will terminate
|
||||
after receiving 'ctrl-\\' followed by 'c' from console input.
|
||||
after receiving \fBctrl-\e\fP followed by \fBc\fP from console input.
|
||||
|
||||
.TP
|
||||
.BI "\-B \fIbaudrate\fP"
|
||||
Adjust the baud rate on \fITTY\fP. Default rate is 115200.
|
||||
If used in combination with \fB-b\fP, inject into the image header
|
||||
code that changes baud rate to \fIbaudrate\fP after uploading image
|
||||
header, and code that changes the baud rate back to the default
|
||||
(115200 Bd) before executing payload, and also adjust the baud rate
|
||||
on \fITTY\fP correspondingly. This can make the upload significantly
|
||||
faster.
|
||||
|
||||
If used in combination with \fB-t\fP, adjust the baud rate to
|
||||
\fIbaudrate\fP on \fITTY\fP before starting terminal.
|
||||
|
||||
If both \fB-b\fP and \fB-t\fP are used, the baud rate is changed
|
||||
back to 115200 after the upload.
|
||||
|
||||
Tested values for \fIbaudrate\fP for Armada 38x include: 115200,
|
||||
230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000,
|
||||
2000000, 2500000, 3125000, 4000000 and 5200000.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
|
@ -82,3 +96,7 @@ Daniel Stodden <daniel.stodden@gmail.com>
|
|||
Luka Perkov <luka@openwrt.org>
|
||||
.br
|
||||
David Purdy <david.c.purdy@gmail.com>
|
||||
.br
|
||||
Pali Rohár <pali@kernel.org>
|
||||
.br
|
||||
Marek Behún <marek.behun@nic.cz>
|
||||
|
|
130
tools/kwbimage.c
130
tools/kwbimage.c
|
@ -1,7 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Image manipulator for Marvell SoCs
|
||||
* supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x
|
||||
* supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and
|
||||
* Armada 39x
|
||||
*
|
||||
* (C) Copyright 2013 Thomas Petazzoni
|
||||
* <thomas.petazzoni@free-electrons.com>
|
||||
|
@ -280,14 +281,6 @@ static uint8_t image_checksum8(void *start, uint32_t len)
|
|||
return csum;
|
||||
}
|
||||
|
||||
size_t kwbimage_header_size(unsigned char *ptr)
|
||||
{
|
||||
if (image_version((void *)ptr) == 0)
|
||||
return sizeof(struct main_hdr_v0);
|
||||
else
|
||||
return KWBHEADER_V1_SIZE((struct main_hdr_v1 *)ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify checksum over a complete header that includes the checksum field.
|
||||
* Return 1 when OK, otherwise 0.
|
||||
|
@ -298,7 +291,7 @@ static int main_hdr_checksum_ok(void *hdr)
|
|||
struct main_hdr_v0 *main_hdr = (struct main_hdr_v0 *)hdr;
|
||||
uint8_t checksum;
|
||||
|
||||
checksum = image_checksum8(hdr, kwbimage_header_size(hdr));
|
||||
checksum = image_checksum8(hdr, kwbheader_size_for_csum(hdr));
|
||||
/* Calculated checksum includes the header checksum field. Compensate
|
||||
* for that.
|
||||
*/
|
||||
|
@ -542,7 +535,7 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf,
|
|||
}
|
||||
|
||||
if (4 + size_seq > sizeof(dst->key)) {
|
||||
fprintf(stderr, "export pk failed: seq too large (%d, %lu)\n",
|
||||
fprintf(stderr, "export pk failed: seq too large (%d, %zu)\n",
|
||||
4 + size_seq, sizeof(dst->key));
|
||||
fprintf(stderr, errmsg, keyname);
|
||||
return -ENOBUFS;
|
||||
|
@ -1618,34 +1611,20 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
|
|||
static void kwbimage_print_header(const void *ptr)
|
||||
{
|
||||
struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
|
||||
struct opt_hdr_v1 *ohdr;
|
||||
|
||||
printf("Image Type: MVEBU Boot from %s Image\n",
|
||||
image_boot_mode_name(mhdr->blockid));
|
||||
printf("Image version:%d\n", image_version((void *)ptr));
|
||||
if (image_version((void *)ptr) == 1) {
|
||||
struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
|
||||
printf("Image version:%d\n", kwbimage_version(ptr));
|
||||
|
||||
if (mhdr->ext & 0x1) {
|
||||
struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
|
||||
((uint8_t *)ptr +
|
||||
sizeof(*mhdr));
|
||||
|
||||
while (1) {
|
||||
uint32_t ohdr_size;
|
||||
|
||||
ohdr_size = (ohdr->headersz_msb << 16) |
|
||||
le16_to_cpu(ohdr->headersz_lsb);
|
||||
if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
|
||||
printf("BIN Hdr Size: ");
|
||||
genimg_print_size(ohdr_size - 12 - 4 * ohdr->data[0]);
|
||||
}
|
||||
if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
|
||||
break;
|
||||
ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
|
||||
ohdr_size);
|
||||
}
|
||||
for_each_opt_hdr_v1 (ohdr, mhdr) {
|
||||
if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
|
||||
printf("BIN Hdr Size: ");
|
||||
genimg_print_size(opt_hdr_v1_size(ohdr) - 12 -
|
||||
4 * ohdr->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Data Size: ");
|
||||
genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
|
||||
printf("Load Address: %08x\n", mhdr->destaddr);
|
||||
|
@ -1663,8 +1642,8 @@ static int kwbimage_check_image_types(uint8_t type)
|
|||
static int kwbimage_verify_header(unsigned char *ptr, int image_size,
|
||||
struct image_tool_params *params)
|
||||
{
|
||||
uint8_t checksum;
|
||||
size_t header_size = kwbimage_header_size(ptr);
|
||||
size_t header_size = kwbheader_size(ptr);
|
||||
uint8_t csum;
|
||||
|
||||
if (header_size > image_size)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
@ -1673,52 +1652,27 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,
|
|||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
/* Only version 0 extended header has checksum */
|
||||
if (image_version((void *)ptr) == 0) {
|
||||
if (kwbimage_version(ptr) == 0) {
|
||||
struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
|
||||
|
||||
if (mhdr->ext & 0x1) {
|
||||
struct ext_hdr_v0 *ext_hdr;
|
||||
struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
|
||||
|
||||
if (header_size + sizeof(*ext_hdr) > image_size)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
ext_hdr = (struct ext_hdr_v0 *)
|
||||
(ptr + sizeof(struct main_hdr_v0));
|
||||
checksum = image_checksum8(ext_hdr,
|
||||
sizeof(struct ext_hdr_v0)
|
||||
- sizeof(uint8_t));
|
||||
if (checksum != ext_hdr->checksum)
|
||||
csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
|
||||
if (csum != ext_hdr->checksum)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
}
|
||||
} else if (image_version((void *)ptr) == 1) {
|
||||
} else if (kwbimage_version(ptr) == 1) {
|
||||
struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
|
||||
const uint8_t *mhdr_end;
|
||||
struct opt_hdr_v1 *ohdr;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
if (mhdr->ext & 0x1) {
|
||||
uint32_t ohdr_size;
|
||||
struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
|
||||
(ptr + sizeof(*mhdr));
|
||||
|
||||
while (1) {
|
||||
if ((uint8_t *)ohdr + sizeof(*ohdr) >
|
||||
(uint8_t *)mhdr + header_size)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
ohdr_size = (ohdr->headersz_msb << 16) |
|
||||
le16_to_cpu(ohdr->headersz_lsb);
|
||||
|
||||
if (ohdr_size < 8 ||
|
||||
(uint8_t *)ohdr + ohdr_size >
|
||||
(uint8_t *)mhdr + header_size)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
|
||||
break;
|
||||
ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
|
||||
ohdr_size);
|
||||
}
|
||||
}
|
||||
mhdr_end = (uint8_t *)mhdr + header_size;
|
||||
for_each_opt_hdr_v1 (ohdr, ptr)
|
||||
if (!opt_hdr_v1_valid_size(ohdr, mhdr_end))
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
|
||||
offset = le32_to_cpu(mhdr->srcaddr);
|
||||
|
||||
|
@ -1864,37 +1818,25 @@ static int kwbimage_generate(struct image_tool_params *params,
|
|||
static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params)
|
||||
{
|
||||
struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
|
||||
size_t header_size = kwbimage_header_size(ptr);
|
||||
size_t header_size = kwbheader_size(ptr);
|
||||
struct opt_hdr_v1 *ohdr;
|
||||
int idx = params->pflag;
|
||||
int cur_idx = 0;
|
||||
uint32_t offset;
|
||||
ulong image;
|
||||
ulong size;
|
||||
|
||||
if (image_version((void *)ptr) == 1 && (mhdr->ext & 0x1)) {
|
||||
struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
|
||||
((uint8_t *)ptr +
|
||||
sizeof(*mhdr));
|
||||
for_each_opt_hdr_v1 (ohdr, ptr) {
|
||||
if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
|
||||
continue;
|
||||
|
||||
while (1) {
|
||||
uint32_t ohdr_size = (ohdr->headersz_msb << 16) |
|
||||
le16_to_cpu(ohdr->headersz_lsb);
|
||||
|
||||
if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
|
||||
if (idx == cur_idx) {
|
||||
image = (ulong)&ohdr->data[4 +
|
||||
4 * ohdr->data[0]];
|
||||
size = ohdr_size - 12 -
|
||||
4 * ohdr->data[0];
|
||||
goto extract;
|
||||
}
|
||||
++cur_idx;
|
||||
}
|
||||
if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
|
||||
break;
|
||||
ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
|
||||
ohdr_size);
|
||||
if (idx == cur_idx) {
|
||||
image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
|
||||
size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
|
||||
goto extract;
|
||||
}
|
||||
|
||||
++cur_idx;
|
||||
}
|
||||
|
||||
if (idx != cur_idx) {
|
||||
|
|
|
@ -69,12 +69,7 @@ struct ext_hdr_v0 {
|
|||
uint8_t checksum;
|
||||
} __packed;
|
||||
|
||||
struct kwb_header {
|
||||
struct main_hdr_v0 kwb_hdr;
|
||||
struct ext_hdr_v0 kwb_exthdr;
|
||||
} __packed;
|
||||
|
||||
/* Structure of the main header, version 1 (Armada 370/38x/XP) */
|
||||
/* Structure of the main header, version 1 (Armada 370/XP/375/38x/39x) */
|
||||
struct main_hdr_v1 {
|
||||
uint8_t blockid; /* 0x0 */
|
||||
uint8_t flags; /* 0x1 */
|
||||
|
@ -108,7 +103,7 @@ struct main_hdr_v1 {
|
|||
#define MAIN_HDR_V1_OPT_BAUD_115200 0x7
|
||||
|
||||
/*
|
||||
* Header for the optional headers, version 1 (Armada 370, Armada XP)
|
||||
* Header for the optional headers, version 1 (Armada 370/XP/375/38x/39x)
|
||||
*/
|
||||
struct opt_hdr_v1 {
|
||||
uint8_t headertype;
|
||||
|
@ -132,7 +127,7 @@ struct sig_v1 {
|
|||
} __packed;
|
||||
|
||||
/*
|
||||
* Structure of secure header (Armada 38x)
|
||||
* Structure of secure header (Armada XP/375/38x/39x)
|
||||
*/
|
||||
struct secure_hdr_v1 {
|
||||
uint8_t headertype; /* 0x0 */
|
||||
|
@ -195,9 +190,6 @@ struct register_set_hdr_v1 {
|
|||
#define OPT_HDR_V1_BINARY_TYPE 0x2
|
||||
#define OPT_HDR_V1_REGISTER_TYPE 0x3
|
||||
|
||||
#define KWBHEADER_V1_SIZE(hdr) \
|
||||
(((hdr)->headersz_msb << 16) | le16_to_cpu((hdr)->headersz_lsb))
|
||||
|
||||
enum kwbimage_cmd {
|
||||
CMD_INVALID,
|
||||
CMD_BOOT_FROM,
|
||||
|
@ -225,10 +217,91 @@ void init_kwb_image_type (void);
|
|||
* header, byte 8 was reserved, and always set to 0. In the v1 header,
|
||||
* byte 8 has been changed to a proper field, set to 1.
|
||||
*/
|
||||
static inline unsigned int image_version(void *header)
|
||||
static inline unsigned int kwbimage_version(const void *header)
|
||||
{
|
||||
unsigned char *ptr = header;
|
||||
const unsigned char *ptr = header;
|
||||
return ptr[8];
|
||||
}
|
||||
|
||||
static inline size_t kwbheader_size(const void *header)
|
||||
{
|
||||
if (kwbimage_version(header) == 0) {
|
||||
const struct main_hdr_v0 *hdr = header;
|
||||
|
||||
return sizeof(*hdr) +
|
||||
(hdr->ext & 0x1) ? sizeof(struct ext_hdr_v0) : 0;
|
||||
} else {
|
||||
const struct main_hdr_v1 *hdr = header;
|
||||
|
||||
return (hdr->headersz_msb << 16) |
|
||||
le16_to_cpu(hdr->headersz_lsb);
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t kwbheader_size_for_csum(const void *header)
|
||||
{
|
||||
if (kwbimage_version(header) == 0)
|
||||
return sizeof(struct main_hdr_v0);
|
||||
else
|
||||
return kwbheader_size(header);
|
||||
}
|
||||
|
||||
static inline uint32_t opt_hdr_v1_size(const struct opt_hdr_v1 *ohdr)
|
||||
{
|
||||
return (ohdr->headersz_msb << 16) | le16_to_cpu(ohdr->headersz_lsb);
|
||||
}
|
||||
|
||||
static inline int opt_hdr_v1_valid_size(const struct opt_hdr_v1 *ohdr,
|
||||
const void *mhdr_end)
|
||||
{
|
||||
uint32_t ohdr_size;
|
||||
|
||||
if ((void *)(ohdr + 1) > mhdr_end)
|
||||
return 0;
|
||||
|
||||
ohdr_size = opt_hdr_v1_size(ohdr);
|
||||
if (ohdr_size < 8 || (void *)((uint8_t *)ohdr + ohdr_size) > mhdr_end)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline struct opt_hdr_v1 *opt_hdr_v1_first(void *img) {
|
||||
struct main_hdr_v1 *mhdr;
|
||||
|
||||
if (kwbimage_version(img) != 1)
|
||||
return NULL;
|
||||
|
||||
mhdr = img;
|
||||
if (mhdr->ext & 0x1)
|
||||
return (struct opt_hdr_v1 *)(mhdr + 1);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint8_t *opt_hdr_v1_ext(struct opt_hdr_v1 *cur)
|
||||
{
|
||||
uint32_t size = opt_hdr_v1_size(cur);
|
||||
|
||||
return (uint8_t *)cur + size - 4;
|
||||
}
|
||||
|
||||
static inline struct opt_hdr_v1 *_opt_hdr_v1_next(struct opt_hdr_v1 *cur)
|
||||
{
|
||||
return (struct opt_hdr_v1 *)((uint8_t *)cur + opt_hdr_v1_size(cur));
|
||||
}
|
||||
|
||||
static inline struct opt_hdr_v1 *opt_hdr_v1_next(struct opt_hdr_v1 *cur)
|
||||
{
|
||||
if (*opt_hdr_v1_ext(cur) & 0x1)
|
||||
return _opt_hdr_v1_next(cur);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define for_each_opt_hdr_v1(ohdr, img) \
|
||||
for ((ohdr) = opt_hdr_v1_first((img)); \
|
||||
(ohdr) != NULL; \
|
||||
(ohdr) = opt_hdr_v1_next((ohdr)))
|
||||
|
||||
#endif /* _KWBIMAGE_H_ */
|
||||
|
|
1235
tools/kwboot.c
1235
tools/kwboot.c
File diff suppressed because it is too large
Load diff
189
tools/termios_linux.h
Normal file
189
tools/termios_linux.h
Normal file
|
@ -0,0 +1,189 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* termios fuctions to support arbitrary baudrates (on Linux)
|
||||
*
|
||||
* Copyright (c) 2021 Pali Rohár <pali@kernel.org>
|
||||
* Copyright (c) 2021 Marek Behún <marek.behun@nic.cz>
|
||||
*/
|
||||
|
||||
#ifndef _TERMIOS_LINUX_H_
|
||||
#define _TERMIOS_LINUX_H_
|
||||
|
||||
/*
|
||||
* We need to use raw TCGETS2/TCSETS2 or TCGETS/TCSETS ioctls with the BOTHER
|
||||
* flag in struct termios2/termios, defined in Linux headers <asm/ioctls.h>
|
||||
* (included by <sys/ioctl.h>) and <asm/termbits.h>. Since these headers
|
||||
* conflict with glibc's header file <termios.h>, it is not possible to use
|
||||
* libc's termios functions and we need to reimplement them via ioctl() calls.
|
||||
*
|
||||
* An arbitrary baudrate is supported when the macro BOTHER is defined. The
|
||||
* baudrate value itself is then stored into the c_ospeed and c_ispeed members.
|
||||
* If ioctls TCGETS2/TCSETS2 are defined and supported then these fields are
|
||||
* present in struct termios2, otherwise these fields are present in struct
|
||||
* termios.
|
||||
*
|
||||
* Note that the Bnnn constants from <termios.h> need not be compatible with Bnnn
|
||||
* constants from <asm/termbits.h>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <asm/termbits.h>
|
||||
|
||||
#if defined(BOTHER) && defined(TCGETS2)
|
||||
#define termios termios2
|
||||
#endif
|
||||
|
||||
static inline int tcgetattr(int fd, struct termios *t)
|
||||
{
|
||||
#if defined(BOTHER) && defined(TCGETS2)
|
||||
return ioctl(fd, TCGETS2, t);
|
||||
#else
|
||||
return ioctl(fd, TCGETS, t);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int tcsetattr(int fd, int a, const struct termios *t)
|
||||
{
|
||||
int cmd;
|
||||
|
||||
switch (a) {
|
||||
#if defined(BOTHER) && defined(TCGETS2)
|
||||
case TCSANOW:
|
||||
cmd = TCSETS2;
|
||||
break;
|
||||
case TCSADRAIN:
|
||||
cmd = TCSETSW2;
|
||||
break;
|
||||
case TCSAFLUSH:
|
||||
cmd = TCSETSF2;
|
||||
break;
|
||||
#else
|
||||
case TCSANOW:
|
||||
cmd = TCSETS;
|
||||
break;
|
||||
case TCSADRAIN:
|
||||
cmd = TCSETSW;
|
||||
break;
|
||||
case TCSAFLUSH:
|
||||
cmd = TCSETSF;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ioctl(fd, cmd, t);
|
||||
}
|
||||
|
||||
static inline int tcdrain(int fd)
|
||||
{
|
||||
return ioctl(fd, TCSBRK, 1);
|
||||
}
|
||||
|
||||
static inline int tcflush(int fd, int q)
|
||||
{
|
||||
return ioctl(fd, TCFLSH, q);
|
||||
}
|
||||
|
||||
static inline int tcsendbreak(int fd, int d)
|
||||
{
|
||||
return ioctl(fd, TCSBRK, d);
|
||||
}
|
||||
|
||||
static inline int tcflow(int fd, int a)
|
||||
{
|
||||
return ioctl(fd, TCXONC, a);
|
||||
}
|
||||
|
||||
static inline pid_t tcgetsid(int fd)
|
||||
{
|
||||
pid_t sid;
|
||||
|
||||
if (ioctl(fd, TIOCGSID, &sid) < 0)
|
||||
return (pid_t)-1;
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
static inline speed_t cfgetospeed(const struct termios *t)
|
||||
{
|
||||
return t->c_cflag & CBAUD;
|
||||
}
|
||||
|
||||
static inline int cfsetospeed(struct termios *t, speed_t s)
|
||||
{
|
||||
if (s & ~CBAUD) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IBSHIFT
|
||||
static inline speed_t cfgetispeed(const struct termios *t)
|
||||
{
|
||||
speed_t s = (t->c_cflag >> IBSHIFT) & CBAUD;
|
||||
|
||||
if (s == B0)
|
||||
return cfgetospeed(t);
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline int cfsetispeed(struct termios *t, speed_t s)
|
||||
{
|
||||
if (s == 0)
|
||||
s = B0;
|
||||
|
||||
if (s & ~CBAUD) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
t->c_cflag &= ~(CBAUD << IBSHIFT);
|
||||
t->c_cflag |= s << IBSHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !IBSHIFT */
|
||||
static inline speed_t cfgetispeed(const struct termios *t)
|
||||
{
|
||||
return cfgetospeed(t);
|
||||
}
|
||||
|
||||
static inline int cfsetispeed(struct termios *t, speed_t s)
|
||||
{
|
||||
return cfsetospeed(t, s);
|
||||
}
|
||||
#endif /* !IBSHIFT */
|
||||
|
||||
static inline int cfsetspeed(struct termios *t, speed_t s)
|
||||
{
|
||||
if (cfsetospeed(t, s))
|
||||
return -1;
|
||||
#ifdef IBSHIFT
|
||||
if (cfsetispeed(t, s))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cfmakeraw(struct termios *t)
|
||||
{
|
||||
t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR |
|
||||
ICRNL | IXON);
|
||||
t->c_oflag &= ~OPOST;
|
||||
t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
t->c_cflag &= ~(CSIZE | PARENB);
|
||||
t->c_cflag |= CS8;
|
||||
}
|
||||
|
||||
#endif /* _TERMIOS_LINUX_H_ */
|
Loading…
Reference in a new issue