summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstefanct <stefanct@2b7e53f0-3cfb-0310-b3e9-8179ed1497e1>2013-04-01 00:45:38 +0000
committerstefanct <stefanct@2b7e53f0-3cfb-0310-b3e9-8179ed1497e1>2013-04-01 00:45:38 +0000
commita13273eb81098883928cbe25234ff5779563b71d (patch)
tree42c1c49a92dcdfe9a406f31f9adc8ea50ac8c666
parenta6d41be08f676de48e12eaefb987ee7f0e3a786f (diff)
downloadflashrom-a13273eb81098883928cbe25234ff5779563b71d.tar.gz
Replace sp_sync_read_timeout() with serialport_read_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 read part. It stores the current blocking properties before disabling blocking and restores them after reading. The timeout is implemented as previously by retrying every millisecond until the timeout is reached or enough characters are available. Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at> Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at> git-svn-id: https://code.coreboot.org/svn/flashrom/trunk@1661 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
-rw-r--r--programmer.h1
-rw-r--r--serial.c70
-rw-r--r--serprog.c28
3 files changed, 75 insertions, 24 deletions
diff --git a/programmer.h b/programmer.h
index b10f568..c36b452 100644
--- a/programmer.h
+++ b/programmer.h
@@ -661,6 +661,7 @@ extern fdtype sp_fd;
int serialport_shutdown(void *data);
int serialport_write(unsigned char *buf, unsigned int writecnt);
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);
/* Serial port/pin mapping:
diff --git a/serial.c b/serial.c
index 9a759ae..d1e2cea 100644
--- a/serial.c
+++ b/serial.c
@@ -361,3 +361,73 @@ int serialport_read(unsigned char *buf, unsigned int readcnt)
return 0;
}
+
+/* Tries up to timeout ms to read readcnt characters and places them into the array starting at c. Returns
+ * 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
+ * If really_read is not NULL, this function sets its contents to the number of bytes read successfully. */
+int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned int timeout, unsigned int *really_read)
+{
+ 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)) {
+#else
+ ssize_t rv;
+ const int flags = fcntl(sp_fd, F_GETFL);
+ if (fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+#endif
+ msg_perr_strerror("Could not set serial port timeout settings %s");
+ return -1;
+ }
+
+ int i;
+ int rd_bytes = 0;
+ for (i = 0; i < timeout; i++) {
+ msg_pspew("readcnt %d rd_bytes %d\n", readcnt, rd_bytes);
+#ifdef _WIN32
+ ReadFile(sp_fd, c + rd_bytes, readcnt - rd_bytes, &rv, NULL);
+ msg_pspew("read %lu bytes\n", rv);
+#else
+ rv = read(sp_fd, c + rd_bytes, readcnt - rd_bytes);
+ msg_pspew("read %zd bytes\n", rv);
+#endif
+ if ((rv == -1) && (errno != EAGAIN)) {
+ msg_perr_strerror("Serial port read error: ");
+ ret = -1;
+ break;
+ }
+ if (rv > 0)
+ rd_bytes += rv;
+ if (rd_bytes == readcnt) {
+ ret = 0;
+ break;
+ }
+ internal_delay(1000); /* 1ms units */
+ }
+ if (really_read != NULL)
+ *really_read = rd_bytes;
+
+ /* restore original blocking behavior */
+#ifdef _WIN32
+ if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
+#else
+ if (fcntl(sp_fd, F_SETFL, flags) != 0) {
+#endif
+ msg_perr_strerror("Could not restore serial port timeout settings: %s\n");
+ ret = -1;
+ }
+ return ret;
+}
diff --git a/serprog.c b/serprog.c
index c36c93d..15d1d1b 100644
--- a/serprog.c
+++ b/serprog.c
@@ -115,26 +115,6 @@ static int sp_opensocket(char *ip, unsigned int port)
return sock;
}
-/* Returns 0 on success and places the character read into the location pointed to by c.
- * Returns positive values on temporary errors and negative ones on permanent errors.
- * An iteration of one loop takes up to 1ms. */
-static int sp_sync_read_timeout(unsigned int loops, unsigned char *c)
-{
- int i;
- for (i = 0; i < loops; i++) {
- ssize_t rv;
- rv = read(sp_fd, c, 1);
- if (rv == 1)
- return 0;
- if ((rv == -1) && (errno != EAGAIN)) {
- msg_perr("read: %s\n", strerror(errno));
- return -1;
- }
- usleep(1000); /* 1ms units */
- }
- return 1;
-}
-
/* 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 *
@@ -174,12 +154,12 @@ static int sp_synchronize(void)
msg_pdbg(".");
fflush(stdout);
for (n = 0; n < 10; n++) {
- int ret = sp_sync_read_timeout(50, &c);
+ int ret = serialport_read_nonblock(&c, 1, 50, NULL);
if (ret < 0)
goto err_out;
if (ret > 0 || c != S_NAK)
continue;
- ret = sp_sync_read_timeout(20, &c);
+ ret = serialport_read_nonblock(&c, 1, 20, NULL);
if (ret < 0)
goto err_out;
if (ret > 0 || c != S_ACK)
@@ -189,12 +169,12 @@ static int sp_synchronize(void)
msg_perr("sync write: %s\n", strerror(errno));
return 1;
}
- ret = sp_sync_read_timeout(500, &c);
+ ret = serialport_read_nonblock(&c, 1, 500, NULL);
if (ret < 0)
goto err_out;
if (ret > 0 || c != S_NAK)
break; /* fail */
- ret = sp_sync_read_timeout(100, &c);
+ ret = serialport_read_nonblock(&c, 1, 100, NULL);
if (ret > 0 || ret < 0)
goto err_out;
if (c != S_ACK)