serial.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2009 Urja Rannikko <urjaman@gmail.com>
  5. * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "platform.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. #include <fcntl.h>
  28. #include <sys/stat.h>
  29. #include <errno.h>
  30. #include <inttypes.h>
  31. #if IS_WINDOWS
  32. #include <conio.h>
  33. #else
  34. #include <termios.h>
  35. #include <unistd.h>
  36. #include <sys/types.h>
  37. #include <sys/ioctl.h>
  38. #endif
  39. #include "flash.h"
  40. #include "programmer.h"
  41. fdtype sp_fd = SER_INV_FD;
  42. /* There is no way defined by POSIX to use arbitrary baud rates. It only defines some macros that can be used to
  43. * specify respective baud rates and many implementations extend this list with further macros, cf. TERMIOS(3)
  44. * and http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=include/uapi/asm-generic/termbits.h
  45. * The code below creates a mapping in sp_baudtable between these macros and the numerical baud rates to deal
  46. * with numerical user input.
  47. *
  48. * On Linux there is a non-standard way to use arbitrary baud rates that flashrom does not support (yet), cf.
  49. * http://www.downtowndougbrown.com/2013/11/linux-custom-serial-baud-rates/
  50. *
  51. * On Windows there exist similar macros (starting with CBR_ instead of B) but they are only defined for
  52. * backwards compatibility and the API supports arbitrary baud rates in the same manner as the macros, see
  53. * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
  54. */
  55. #if !IS_WINDOWS
  56. struct baudentry {
  57. int flag;
  58. unsigned int baud;
  59. };
  60. #define BAUDENTRY(baud) { B##baud, baud },
  61. static const struct baudentry sp_baudtable[] = {
  62. BAUDENTRY(9600) /* unconditional default */
  63. #ifdef B19200
  64. BAUDENTRY(19200)
  65. #endif
  66. #ifdef B38400
  67. BAUDENTRY(38400)
  68. #endif
  69. #ifdef B57600
  70. BAUDENTRY(57600)
  71. #endif
  72. #ifdef B115200
  73. BAUDENTRY(115200)
  74. #endif
  75. #ifdef B230400
  76. BAUDENTRY(230400)
  77. #endif
  78. #ifdef B460800
  79. BAUDENTRY(460800)
  80. #endif
  81. #ifdef B500000
  82. BAUDENTRY(500000)
  83. #endif
  84. #ifdef B576000
  85. BAUDENTRY(576000)
  86. #endif
  87. #ifdef B921600
  88. BAUDENTRY(921600)
  89. #endif
  90. #ifdef B1000000
  91. BAUDENTRY(1000000)
  92. #endif
  93. #ifdef B1152000
  94. BAUDENTRY(1152000)
  95. #endif
  96. #ifdef B1500000
  97. BAUDENTRY(1500000)
  98. #endif
  99. #ifdef B2000000
  100. BAUDENTRY(2000000)
  101. #endif
  102. #ifdef B2500000
  103. BAUDENTRY(2500000)
  104. #endif
  105. #ifdef B3000000
  106. BAUDENTRY(3000000)
  107. #endif
  108. #ifdef B3500000
  109. BAUDENTRY(3500000)
  110. #endif
  111. #ifdef B4000000
  112. BAUDENTRY(4000000)
  113. #endif
  114. {0, 0} /* Terminator */
  115. };
  116. static const struct baudentry *round_baud(unsigned int baud)
  117. {
  118. int i;
  119. /* Round baud rate to next lower entry in sp_baudtable if it exists, else use the lowest entry. */
  120. for (i = ARRAY_SIZE(sp_baudtable) - 2; i >= 0 ; i--) {
  121. if (sp_baudtable[i].baud == baud)
  122. return &sp_baudtable[i];
  123. if (sp_baudtable[i].baud < baud) {
  124. msg_pwarn("Warning: given baudrate %d rounded down to %d.\n",
  125. baud, sp_baudtable[i].baud);
  126. return &sp_baudtable[i];
  127. }
  128. }
  129. msg_pinfo("Using slowest possible baudrate: %d.\n", sp_baudtable[0].baud);
  130. return &sp_baudtable[0];
  131. }
  132. #endif
  133. /* Uses msg_perr to print the last system error.
  134. * Prints "Error: " followed first by \c msg and then by the description of the last error retrieved via
  135. * strerror() or FormatMessage() and ending with a linebreak. */
  136. static void msg_perr_strerror(const char *msg)
  137. {
  138. msg_perr("Error: %s", msg);
  139. #if IS_WINDOWS
  140. char *lpMsgBuf;
  141. DWORD nErr = GetLastError();
  142. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nErr,
  143. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
  144. msg_perr(lpMsgBuf);
  145. /* At least some formatted messages contain a line break at the end. Make sure to always print one */
  146. if (lpMsgBuf[strlen(lpMsgBuf)-1] != '\n')
  147. msg_perr("\n");
  148. LocalFree(lpMsgBuf);
  149. #else
  150. msg_perr("%s\n", strerror(errno));
  151. #endif
  152. }
  153. int serialport_config(fdtype fd, int baud)
  154. {
  155. if (fd == SER_INV_FD) {
  156. msg_perr("%s: File descriptor is invalid.\n", __func__);
  157. return 1;
  158. }
  159. #if IS_WINDOWS
  160. DCB dcb;
  161. if (!GetCommState(fd, &dcb)) {
  162. msg_perr_strerror("Could not fetch original serial port configuration: ");
  163. return 1;
  164. }
  165. if (baud >= 0) {
  166. dcb.BaudRate = baud;
  167. }
  168. dcb.ByteSize = 8;
  169. dcb.Parity = NOPARITY;
  170. dcb.StopBits = ONESTOPBIT;
  171. if (!SetCommState(fd, &dcb)) {
  172. msg_perr_strerror("Could not change serial port configuration: ");
  173. return 1;
  174. }
  175. if (!GetCommState(fd, &dcb)) {
  176. msg_perr_strerror("Could not fetch new serial port configuration: ");
  177. return 1;
  178. }
  179. msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate);
  180. #else
  181. struct termios wanted, observed;
  182. if (tcgetattr(fd, &observed) != 0) {
  183. msg_perr_strerror("Could not fetch original serial port configuration: ");
  184. return 1;
  185. }
  186. wanted = observed;
  187. if (baud >= 0) {
  188. const struct baudentry *entry = round_baud(baud);
  189. if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) {
  190. msg_perr_strerror("Could not set serial baud rate: ");
  191. return 1;
  192. }
  193. }
  194. wanted.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
  195. wanted.c_cflag |= (CS8 | CLOCAL | CREAD);
  196. wanted.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  197. wanted.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
  198. wanted.c_oflag &= ~OPOST;
  199. if (tcsetattr(fd, TCSANOW, &wanted) != 0) {
  200. msg_perr_strerror("Could not change serial port configuration: ");
  201. return 1;
  202. }
  203. if (tcgetattr(fd, &observed) != 0) {
  204. msg_perr_strerror("Could not fetch new serial port configuration: ");
  205. return 1;
  206. }
  207. if (observed.c_cflag != wanted.c_cflag ||
  208. observed.c_lflag != wanted.c_lflag ||
  209. observed.c_iflag != wanted.c_iflag ||
  210. observed.c_oflag != wanted.c_oflag) {
  211. msg_pwarn("Some requested serial options did not stick, continuing anyway.\n");
  212. msg_pdbg(" observed wanted\n"
  213. "c_cflag: 0x%08lX 0x%08lX\n"
  214. "c_lflag: 0x%08lX 0x%08lX\n"
  215. "c_iflag: 0x%08lX 0x%08lX\n"
  216. "c_oflag: 0x%08lX 0x%08lX\n",
  217. (long)observed.c_cflag, (long)wanted.c_cflag,
  218. (long)observed.c_lflag, (long)wanted.c_lflag,
  219. (long)observed.c_iflag, (long)wanted.c_iflag,
  220. (long)observed.c_oflag, (long)wanted.c_oflag
  221. );
  222. }
  223. if (cfgetispeed(&observed) != cfgetispeed(&wanted) ||
  224. cfgetospeed(&observed) != cfgetospeed(&wanted)) {
  225. msg_pwarn("Could not set baud rates exactly.\n");
  226. msg_pdbg("Actual baud flags are: ispeed: 0x%08lX, ospeed: 0x%08lX\n",
  227. (long)cfgetispeed(&observed), (long)cfgetospeed(&observed));
  228. }
  229. // FIXME: display actual baud rate - at least if none was specified by the user.
  230. #endif
  231. return 0;
  232. }
  233. fdtype sp_openserport(char *dev, int baud)
  234. {
  235. fdtype fd;
  236. #if IS_WINDOWS
  237. char *dev2 = dev;
  238. if ((strlen(dev) > 3) &&
  239. (tolower((unsigned char)dev[0]) == 'c') &&
  240. (tolower((unsigned char)dev[1]) == 'o') &&
  241. (tolower((unsigned char)dev[2]) == 'm')) {
  242. dev2 = malloc(strlen(dev) + 5);
  243. if (!dev2) {
  244. msg_perr_strerror("Out of memory: ");
  245. return SER_INV_FD;
  246. }
  247. strcpy(dev2, "\\\\.\\");
  248. strcpy(dev2 + 4, dev);
  249. }
  250. fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  251. OPEN_EXISTING, 0, NULL);
  252. if (dev2 != dev)
  253. free(dev2);
  254. if (fd == INVALID_HANDLE_VALUE) {
  255. msg_perr_strerror("Cannot open serial port: ");
  256. return SER_INV_FD;
  257. }
  258. if (serialport_config(fd, baud) != 0) {
  259. CloseHandle(fd);
  260. return SER_INV_FD;
  261. }
  262. return fd;
  263. #else
  264. fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); // Use O_NDELAY to ignore DCD state
  265. if (fd < 0) {
  266. msg_perr_strerror("Cannot open serial port: ");
  267. return SER_INV_FD;
  268. }
  269. /* Ensure that we use blocking I/O */
  270. const int flags = fcntl(fd, F_GETFL);
  271. if (flags == -1) {
  272. msg_perr_strerror("Could not get serial port mode: ");
  273. goto err;
  274. }
  275. if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != 0) {
  276. msg_perr_strerror("Could not set serial port mode to blocking: ");
  277. goto err;
  278. }
  279. if (serialport_config(fd, baud) != 0) {
  280. goto err;
  281. }
  282. return fd;
  283. err:
  284. close(fd);
  285. return SER_INV_FD;
  286. #endif
  287. }
  288. void sp_set_pin(enum SP_PIN pin, int val) {
  289. #if IS_WINDOWS
  290. DWORD ctl;
  291. if(pin == PIN_TXD) {
  292. ctl = val ? SETBREAK: CLRBREAK;
  293. }
  294. else if(pin == PIN_DTR) {
  295. ctl = val ? SETDTR: CLRDTR;
  296. }
  297. else {
  298. ctl = val ? SETRTS: CLRRTS;
  299. }
  300. EscapeCommFunction(sp_fd, ctl);
  301. #else
  302. int ctl, s;
  303. if(pin == PIN_TXD) {
  304. ioctl(sp_fd, val ? TIOCSBRK : TIOCCBRK, 0);
  305. }
  306. else {
  307. s = (pin == PIN_DTR) ? TIOCM_DTR : TIOCM_RTS;
  308. ioctl(sp_fd, TIOCMGET, &ctl);
  309. if (val) {
  310. ctl |= s;
  311. }
  312. else {
  313. ctl &= ~s;
  314. }
  315. ioctl(sp_fd, TIOCMSET, &ctl);
  316. }
  317. #endif
  318. }
  319. int sp_get_pin(enum SP_PIN pin) {
  320. int s;
  321. #if IS_WINDOWS
  322. DWORD ctl;
  323. s = (pin == PIN_CTS) ? MS_CTS_ON : MS_DSR_ON;
  324. GetCommModemStatus(sp_fd, &ctl);
  325. #else
  326. int ctl;
  327. s = (pin == PIN_CTS) ? TIOCM_CTS : TIOCM_DSR;
  328. ioctl(sp_fd, TIOCMGET, &ctl);
  329. #endif
  330. return ((ctl & s) ? 1 : 0);
  331. }
  332. void sp_flush_incoming(void)
  333. {
  334. #if IS_WINDOWS
  335. PurgeComm(sp_fd, PURGE_RXCLEAR);
  336. #else
  337. /* FIXME: error handling */
  338. tcflush(sp_fd, TCIFLUSH);
  339. #endif
  340. return;
  341. }
  342. int serialport_shutdown(void *data)
  343. {
  344. #if IS_WINDOWS
  345. CloseHandle(sp_fd);
  346. #else
  347. close(sp_fd);
  348. #endif
  349. return 0;
  350. }
  351. int serialport_write(const unsigned char *buf, unsigned int writecnt)
  352. {
  353. #if IS_WINDOWS
  354. DWORD tmp = 0;
  355. #else
  356. ssize_t tmp = 0;
  357. #endif
  358. unsigned int empty_writes = 250; /* results in a ca. 125ms timeout */
  359. while (writecnt > 0) {
  360. #if IS_WINDOWS
  361. WriteFile(sp_fd, buf, writecnt, &tmp, NULL);
  362. #else
  363. tmp = write(sp_fd, buf, writecnt);
  364. #endif
  365. if (tmp == -1) {
  366. msg_perr("Serial port write error!\n");
  367. return 1;
  368. }
  369. if (!tmp) {
  370. msg_pdbg2("Empty write\n");
  371. empty_writes--;
  372. internal_delay(500);
  373. if (empty_writes == 0) {
  374. msg_perr("Serial port is unresponsive!\n");
  375. return 1;
  376. }
  377. }
  378. writecnt -= tmp;
  379. buf += tmp;
  380. }
  381. return 0;
  382. }
  383. int serialport_read(unsigned char *buf, unsigned int readcnt)
  384. {
  385. #if IS_WINDOWS
  386. DWORD tmp = 0;
  387. #else
  388. ssize_t tmp = 0;
  389. #endif
  390. while (readcnt > 0) {
  391. #if IS_WINDOWS
  392. ReadFile(sp_fd, buf, readcnt, &tmp, NULL);
  393. #else
  394. tmp = read(sp_fd, buf, readcnt);
  395. #endif
  396. if (tmp == -1) {
  397. msg_perr("Serial port read error!\n");
  398. return 1;
  399. }
  400. if (!tmp)
  401. msg_pdbg2("Empty read\n");
  402. readcnt -= tmp;
  403. buf += tmp;
  404. }
  405. return 0;
  406. }
  407. /* Tries up to timeout ms to read readcnt characters and places them into the array starting at c. Returns
  408. * 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
  409. * If really_read is not NULL, this function sets its contents to the number of bytes read successfully. */
  410. int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned int timeout, unsigned int *really_read)
  411. {
  412. int ret = 1;
  413. /* disable blocked i/o and declare platform-specific variables */
  414. #if IS_WINDOWS
  415. DWORD rv;
  416. COMMTIMEOUTS oldTimeout;
  417. COMMTIMEOUTS newTimeout = {
  418. .ReadIntervalTimeout = MAXDWORD,
  419. .ReadTotalTimeoutMultiplier = 0,
  420. .ReadTotalTimeoutConstant = 0,
  421. .WriteTotalTimeoutMultiplier = 0,
  422. .WriteTotalTimeoutConstant = 0
  423. };
  424. if(!GetCommTimeouts(sp_fd, &oldTimeout)) {
  425. msg_perr_strerror("Could not get serial port timeout settings: ");
  426. return -1;
  427. }
  428. if(!SetCommTimeouts(sp_fd, &newTimeout)) {
  429. msg_perr_strerror("Could not set serial port timeout settings: ");
  430. return -1;
  431. }
  432. #else
  433. ssize_t rv;
  434. const int flags = fcntl(sp_fd, F_GETFL);
  435. if (flags == -1) {
  436. msg_perr_strerror("Could not get serial port mode: ");
  437. return -1;
  438. }
  439. if (fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK) != 0) {
  440. msg_perr_strerror("Could not set serial port mode to non-blocking: ");
  441. return -1;
  442. }
  443. #endif
  444. int i;
  445. int rd_bytes = 0;
  446. for (i = 0; i < timeout; i++) {
  447. msg_pspew("readcnt %d rd_bytes %d\n", readcnt, rd_bytes);
  448. #if IS_WINDOWS
  449. ReadFile(sp_fd, c + rd_bytes, readcnt - rd_bytes, &rv, NULL);
  450. msg_pspew("read %lu bytes\n", rv);
  451. #else
  452. rv = read(sp_fd, c + rd_bytes, readcnt - rd_bytes);
  453. msg_pspew("read %zd bytes\n", rv);
  454. #endif
  455. if ((rv == -1) && (errno != EAGAIN)) {
  456. msg_perr_strerror("Serial port read error: ");
  457. ret = -1;
  458. break;
  459. }
  460. if (rv > 0)
  461. rd_bytes += rv;
  462. if (rd_bytes == readcnt) {
  463. ret = 0;
  464. break;
  465. }
  466. internal_delay(1000); /* 1ms units */
  467. }
  468. if (really_read != NULL)
  469. *really_read = rd_bytes;
  470. /* restore original blocking behavior */
  471. #if IS_WINDOWS
  472. if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
  473. msg_perr_strerror("Could not restore serial port timeout settings: ");
  474. ret = -1;
  475. }
  476. #else
  477. if (fcntl(sp_fd, F_SETFL, flags) != 0) {
  478. msg_perr_strerror("Could not restore serial port mode to blocking: ");
  479. ret = -1;
  480. }
  481. #endif
  482. return ret;
  483. }
  484. /* Tries up to timeout ms to write writecnt characters from the array starting at buf. Returns
  485. * 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
  486. * If really_wrote is not NULL, this function sets its contents to the number of bytes written successfully. */
  487. int serialport_write_nonblock(const unsigned char *buf, unsigned int writecnt, unsigned int timeout, unsigned int *really_wrote)
  488. {
  489. int ret = 1;
  490. /* disable blocked i/o and declare platform-specific variables */
  491. #if IS_WINDOWS
  492. DWORD rv;
  493. COMMTIMEOUTS oldTimeout;
  494. COMMTIMEOUTS newTimeout = {
  495. .ReadIntervalTimeout = MAXDWORD,
  496. .ReadTotalTimeoutMultiplier = 0,
  497. .ReadTotalTimeoutConstant = 0,
  498. .WriteTotalTimeoutMultiplier = 0,
  499. .WriteTotalTimeoutConstant = 0
  500. };
  501. if(!GetCommTimeouts(sp_fd, &oldTimeout)) {
  502. msg_perr_strerror("Could not get serial port timeout settings: ");
  503. return -1;
  504. }
  505. if(!SetCommTimeouts(sp_fd, &newTimeout)) {
  506. msg_perr_strerror("Could not set serial port timeout settings: ");
  507. return -1;
  508. }
  509. #else
  510. ssize_t rv;
  511. const int flags = fcntl(sp_fd, F_GETFL);
  512. if (flags == -1) {
  513. msg_perr_strerror("Could not get serial port mode: ");
  514. return -1;
  515. }
  516. if (fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK) != 0) {
  517. msg_perr_strerror("Could not set serial port mode to non-blocking: ");
  518. return -1;
  519. }
  520. #endif
  521. int i;
  522. int wr_bytes = 0;
  523. for (i = 0; i < timeout; i++) {
  524. msg_pspew("writecnt %d wr_bytes %d\n", writecnt, wr_bytes);
  525. #if IS_WINDOWS
  526. WriteFile(sp_fd, buf + wr_bytes, writecnt - wr_bytes, &rv, NULL);
  527. msg_pspew("wrote %lu bytes\n", rv);
  528. #else
  529. rv = write(sp_fd, buf + wr_bytes, writecnt - wr_bytes);
  530. msg_pspew("wrote %zd bytes\n", rv);
  531. #endif
  532. if ((rv == -1) && (errno != EAGAIN)) {
  533. msg_perr_strerror("Serial port write error: ");
  534. ret = -1;
  535. break;
  536. }
  537. if (rv > 0) {
  538. wr_bytes += rv;
  539. if (wr_bytes == writecnt) {
  540. msg_pspew("write successful\n");
  541. ret = 0;
  542. break;
  543. }
  544. }
  545. internal_delay(1000); /* 1ms units */
  546. }
  547. if (really_wrote != NULL)
  548. *really_wrote = wr_bytes;
  549. /* restore original blocking behavior */
  550. #if IS_WINDOWS
  551. if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
  552. msg_perr_strerror("Could not restore serial port timeout settings: ");
  553. return -1;
  554. }
  555. #else
  556. if (fcntl(sp_fd, F_SETFL, flags) != 0) {
  557. msg_perr_strerror("Could not restore serial port blocking behavior: ");
  558. return -1;
  559. }
  560. #endif
  561. return ret;
  562. }