mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-26 06:32:34 +02:00
Introduce serialport_write_nonblock()
It seems useful to have a generic and platform-independent method to read and write to a serial port without blocking. This is the write part. This allows to get rid of the explicit temporary disabling of blocking I/O in serprog's sp_synchronize(). Corresponding to flashrom svn r1662. Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
This commit is contained in:
parent
00e1608501
commit
ae3d83765c
@ -660,6 +660,7 @@ extern fdtype sp_fd;
|
||||
/* expose serialport_shutdown as it's currently used by buspirate */
|
||||
int serialport_shutdown(void *data);
|
||||
int serialport_write(unsigned char *buf, unsigned int writecnt);
|
||||
int serialport_write_nonblock(unsigned char *buf, unsigned int writecnt, unsigned int timeout, unsigned int *really_wrote);
|
||||
int serialport_read(unsigned char *buf, unsigned int readcnt);
|
||||
int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned int timeout, unsigned int *really_read);
|
||||
|
||||
|
72
serial.c
72
serial.c
@ -431,3 +431,75 @@ int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned in
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Tries up to timeout ms to write writecnt characters from the array starting at buf. Returns
|
||||
* 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
|
||||
* If really_wrote is not NULL, this function sets its contents to the number of bytes written successfully. */
|
||||
int serialport_write_nonblock(unsigned char *buf, unsigned int writecnt, unsigned int timeout, unsigned int *really_wrote)
|
||||
{
|
||||
int ret = 1;
|
||||
/* disable blocked i/o and declare platform-specific variables */
|
||||
#ifdef _WIN32
|
||||
DWORD rv;
|
||||
COMMTIMEOUTS oldTimeout;
|
||||
COMMTIMEOUTS newTimeout = {
|
||||
.ReadIntervalTimeout = MAXDWORD,
|
||||
.ReadTotalTimeoutMultiplier = 0,
|
||||
.ReadTotalTimeoutConstant = 0,
|
||||
.WriteTotalTimeoutMultiplier = 0,
|
||||
.WriteTotalTimeoutConstant = 0
|
||||
};
|
||||
if(!GetCommTimeouts(sp_fd, &oldTimeout)) {
|
||||
msg_perr_strerror("Could not get serial port timeout settings: ");
|
||||
return -1;
|
||||
}
|
||||
if(!SetCommTimeouts(sp_fd, &newTimeout)) {
|
||||
msg_perr_strerror("Could not set serial port timeout settings: ");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
ssize_t rv;
|
||||
const int flags = fcntl(sp_fd, F_GETFL);
|
||||
fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
int wr_bytes = 0;
|
||||
for (i = 0; i < timeout; i++) {
|
||||
msg_pspew("writecnt %d wr_bytes %d\n", writecnt, wr_bytes);
|
||||
#ifdef _WIN32
|
||||
WriteFile(sp_fd, buf + wr_bytes, writecnt - wr_bytes, &rv, NULL);
|
||||
msg_pspew("wrote %lu bytes\n", rv);
|
||||
#else
|
||||
rv = write(sp_fd, buf + wr_bytes, writecnt - wr_bytes);
|
||||
msg_pspew("wrote %zd bytes\n", rv);
|
||||
#endif
|
||||
if ((rv == -1) && (errno != EAGAIN)) {
|
||||
msg_perr_strerror("Serial port write error: ");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (rv > 0) {
|
||||
wr_bytes += rv;
|
||||
if (wr_bytes == writecnt) {
|
||||
msg_pspew("write successful\n");
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
internal_delay(1000); /* 1ms units */
|
||||
}
|
||||
if (really_wrote != NULL)
|
||||
*really_wrote = wr_bytes;
|
||||
|
||||
/* restore original blocking behavior */
|
||||
#ifdef _WIN32
|
||||
if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
|
||||
msg_perr_strerror("Could not restore serial port timeout settings: ");
|
||||
#else
|
||||
if (fcntl(sp_fd, F_SETFL, flags) != 0) {
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
19
serprog.c
19
serprog.c
@ -117,23 +117,19 @@ static int sp_opensocket(char *ip, unsigned int port)
|
||||
|
||||
/* Synchronize: a bit tricky algorithm that tries to (and in my tests has *
|
||||
* always succeeded in) bring the serial protocol to known waiting-for- *
|
||||
* command state - uses nonblocking read - rest of the driver uses *
|
||||
* command state - uses nonblocking I/O - rest of the driver uses *
|
||||
* blocking read - TODO: add an alarm() timer for the rest of the app on *
|
||||
* serial operations, though not such a big issue as the first thing to *
|
||||
* do is synchronize (eg. check that device is alive). */
|
||||
static int sp_synchronize(void)
|
||||
{
|
||||
int i;
|
||||
int flags = fcntl(sp_fd, F_GETFL);
|
||||
unsigned char buf[8];
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(sp_fd, F_SETFL, flags);
|
||||
/* First sends 8 NOPs, then flushes the return data - should cause *
|
||||
* the device serial parser to get to a sane state, unless if it *
|
||||
* is waiting for a real long write-n. */
|
||||
memset(buf, S_CMD_NOP, 8);
|
||||
if (write(sp_fd, buf, 8) != 8) {
|
||||
msg_perr("flush write: %s\n", strerror(errno));
|
||||
if (serialport_write_nonblock(buf, 8, 1, NULL) != 0) {
|
||||
goto err_out;
|
||||
}
|
||||
/* A second should be enough to get all the answers to the buffer */
|
||||
@ -147,8 +143,7 @@ static int sp_synchronize(void)
|
||||
for (i = 0; i < 8; i++) {
|
||||
int n;
|
||||
unsigned char c = S_CMD_SYNCNOP;
|
||||
if (write(sp_fd, &c, 1) != 1) {
|
||||
msg_perr("sync write: %s\n", strerror(errno));
|
||||
if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
|
||||
goto err_out;
|
||||
}
|
||||
msg_pdbg(".");
|
||||
@ -165,9 +160,8 @@ static int sp_synchronize(void)
|
||||
if (ret > 0 || c != S_ACK)
|
||||
continue;
|
||||
c = S_CMD_SYNCNOP;
|
||||
if (write(sp_fd, &c, 1) != 1) {
|
||||
msg_perr("sync write: %s\n", strerror(errno));
|
||||
return 1;
|
||||
if (serialport_write_nonblock(&c, 1, 1, NULL) != 0) {
|
||||
goto err_out;
|
||||
}
|
||||
ret = serialport_read_nonblock(&c, 1, 500, NULL);
|
||||
if (ret < 0)
|
||||
@ -179,9 +173,6 @@ static int sp_synchronize(void)
|
||||
goto err_out;
|
||||
if (c != S_ACK)
|
||||
break; /* fail */
|
||||
/* Ok, synchronized; back to blocking reads and return. */
|
||||
flags &= ~O_NONBLOCK;
|
||||
fcntl(sp_fd, F_SETFL, flags);
|
||||
msg_pdbg("\n");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user