comm_serial_sys.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * Serial Communication API
  4. *
  5. * Copyright 2011 O.S. Systems Software Ltda.
  6. * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
  7. * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  8. * Copyright 2014 Hewlett-Packard Development Company, L.P.
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. */
  22. #if defined __linux__ && !defined ANDROID
  23. #include <assert.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <sys/ioctl.h>
  27. #include <termios.h>
  28. #include <unistd.h>
  29. #include "comm_serial_sys.h"
  30. #ifdef __UCLIBC__
  31. #include "comm.h"
  32. #endif
  33. #include <winpr/crt.h>
  34. #include <winpr/wlog.h>
  35. /* Undocumented flag, not supported everywhere.
  36. * Provide a sensible fallback to avoid compilation problems. */
  37. #ifndef CMSPAR
  38. #define CMSPAR 010000000000
  39. #endif
  40. /* hard-coded in N_TTY */
  41. #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
  42. #define TTY_THRESHOLD_UNTHROTTLE 128
  43. #define N_TTY_BUF_SIZE 4096
  44. #define _BAUD_TABLE_END 0010020 /* __MAX_BAUD + 1 */
  45. /* 0: B* (Linux termios)
  46. * 1: CBR_* or actual baud rate
  47. * 2: BAUD_* (identical to SERIAL_BAUD_*)
  48. */
  49. static const speed_t _BAUD_TABLE[][3] = {
  50. #ifdef B0
  51. { B0, 0, 0 }, /* hang up */
  52. #endif
  53. #ifdef B50
  54. { B50, 50, 0 },
  55. #endif
  56. #ifdef B75
  57. { B75, 75, BAUD_075 },
  58. #endif
  59. #ifdef B110
  60. { B110, CBR_110, BAUD_110 },
  61. #endif
  62. #ifdef B134
  63. { B134, 134, 0 /*BAUD_134_5*/ },
  64. #endif
  65. #ifdef B150
  66. { B150, 150, BAUD_150 },
  67. #endif
  68. #ifdef B200
  69. { B200, 200, 0 },
  70. #endif
  71. #ifdef B300
  72. { B300, CBR_300, BAUD_300 },
  73. #endif
  74. #ifdef B600
  75. { B600, CBR_600, BAUD_600 },
  76. #endif
  77. #ifdef B1200
  78. { B1200, CBR_1200, BAUD_1200 },
  79. #endif
  80. #ifdef B1800
  81. { B1800, 1800, BAUD_1800 },
  82. #endif
  83. #ifdef B2400
  84. { B2400, CBR_2400, BAUD_2400 },
  85. #endif
  86. #ifdef B4800
  87. { B4800, CBR_4800, BAUD_4800 },
  88. #endif
  89. /* {, ,BAUD_7200} */
  90. #ifdef B9600
  91. { B9600, CBR_9600, BAUD_9600 },
  92. #endif
  93. /* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */
  94. #ifdef B19200
  95. { B19200, CBR_19200, BAUD_19200 },
  96. #endif
  97. #ifdef B38400
  98. { B38400, CBR_38400, BAUD_38400 },
  99. #endif
  100. /* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */
  101. #ifdef B57600
  102. { B57600, CBR_57600, BAUD_57600 },
  103. #endif
  104. #ifdef B115200
  105. { B115200, CBR_115200, BAUD_115200 },
  106. #endif
  107. /* {, CBR_128000, BAUD_128K}, /\* unsupported on Linux *\/ */
  108. /* {, CBR_256000, BAUD_USER}, /\* unsupported on Linux *\/ */
  109. #ifdef B230400
  110. { B230400, 230400, BAUD_USER },
  111. #endif
  112. #ifdef B460800
  113. { B460800, 460800, BAUD_USER },
  114. #endif
  115. #ifdef B500000
  116. { B500000, 500000, BAUD_USER },
  117. #endif
  118. #ifdef B576000
  119. { B576000, 576000, BAUD_USER },
  120. #endif
  121. #ifdef B921600
  122. { B921600, 921600, BAUD_USER },
  123. #endif
  124. #ifdef B1000000
  125. { B1000000, 1000000, BAUD_USER },
  126. #endif
  127. #ifdef B1152000
  128. { B1152000, 1152000, BAUD_USER },
  129. #endif
  130. #ifdef B1500000
  131. { B1500000, 1500000, BAUD_USER },
  132. #endif
  133. #ifdef B2000000
  134. { B2000000, 2000000, BAUD_USER },
  135. #endif
  136. #ifdef B2500000
  137. { B2500000, 2500000, BAUD_USER },
  138. #endif
  139. #ifdef B3000000
  140. { B3000000, 3000000, BAUD_USER },
  141. #endif
  142. #ifdef B3500000
  143. { B3500000, 3500000, BAUD_USER },
  144. #endif
  145. #ifdef B4000000
  146. { B4000000, 4000000, BAUD_USER }, /* __MAX_BAUD */
  147. #endif
  148. { _BAUD_TABLE_END, 0, 0 }
  149. };
  150. static BOOL _get_properties(WINPR_COMM* pComm, COMMPROP* pProperties)
  151. {
  152. int i;
  153. /* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680684%28v=vs.85%29.aspx
  154. * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363189%28v=vs.85%29.aspx
  155. */
  156. /* FIXME: properties should be better probed. The current
  157. * implementation just relies on the Linux' implementation.
  158. */
  159. if (pProperties->dwProvSpec1 != COMMPROP_INITIALIZED)
  160. {
  161. ZeroMemory(pProperties, sizeof(COMMPROP));
  162. pProperties->wPacketLength = sizeof(COMMPROP);
  163. }
  164. pProperties->wPacketVersion = 2;
  165. pProperties->dwServiceMask = SERIAL_SP_SERIALCOMM;
  166. /* pProperties->Reserved1; not used */
  167. /* FIXME: could be implemented on top of N_TTY */
  168. pProperties->dwMaxTxQueue = N_TTY_BUF_SIZE;
  169. pProperties->dwMaxRxQueue = N_TTY_BUF_SIZE;
  170. /* FIXME: to be probe on the device? */
  171. pProperties->dwMaxBaud = BAUD_USER;
  172. /* FIXME: what about PST_RS232? see also: serial_struct */
  173. pProperties->dwProvSubType = PST_UNSPECIFIED;
  174. /* TODO: to be finalized */
  175. pProperties->dwProvCapabilities =
  176. /*PCF_16BITMODE |*/ PCF_DTRDSR | PCF_INTTIMEOUTS | PCF_PARITY_CHECK | /*PCF_RLSD |*/
  177. PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS |*/ PCF_TOTALTIMEOUTS | PCF_XONXOFF;
  178. /* TODO: double check SP_RLSD */
  179. pProperties->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY |
  180. SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS;
  181. pProperties->dwSettableBaud = 0;
  182. for (i = 0; _BAUD_TABLE[i][0] < _BAUD_TABLE_END; i++)
  183. {
  184. pProperties->dwSettableBaud |= _BAUD_TABLE[i][2];
  185. }
  186. pProperties->wSettableData =
  187. DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 /*| DATABITS_16 | DATABITS_16X*/;
  188. pProperties->wSettableStopParity = STOPBITS_10 | /*STOPBITS_15 |*/ STOPBITS_20 | PARITY_NONE |
  189. PARITY_ODD | PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
  190. /* FIXME: additional input and output buffers could be implemented on top of N_TTY */
  191. pProperties->dwCurrentTxQueue = N_TTY_BUF_SIZE;
  192. pProperties->dwCurrentRxQueue = N_TTY_BUF_SIZE;
  193. /* pProperties->ProvSpec1; see above */
  194. /* pProperties->ProvSpec2; ignored */
  195. /* pProperties->ProvChar[1]; ignored */
  196. return TRUE;
  197. }
  198. static BOOL _set_baud_rate(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate)
  199. {
  200. int i;
  201. speed_t newSpeed;
  202. struct termios futureState;
  203. ZeroMemory(&futureState, sizeof(struct termios));
  204. if (tcgetattr(pComm->fd, &futureState) <
  205. 0) /* NB: preserves current settings not directly handled by the Communication Functions */
  206. {
  207. SetLastError(ERROR_IO_DEVICE);
  208. return FALSE;
  209. }
  210. for (i = 0; _BAUD_TABLE[i][0] < _BAUD_TABLE_END; i++)
  211. {
  212. if (_BAUD_TABLE[i][1] == pBaudRate->BaudRate)
  213. {
  214. newSpeed = _BAUD_TABLE[i][0];
  215. if (cfsetspeed(&futureState, newSpeed) < 0)
  216. {
  217. CommLog_Print(WLOG_WARN, "failed to set speed 0x%x (%" PRIu32 ")", newSpeed,
  218. pBaudRate->BaudRate);
  219. return FALSE;
  220. }
  221. assert(cfgetispeed(&futureState) == newSpeed);
  222. if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0)
  223. {
  224. CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%" PRIX32 "",
  225. GetLastError());
  226. return FALSE;
  227. }
  228. return TRUE;
  229. }
  230. }
  231. CommLog_Print(WLOG_WARN, "could not find a matching speed for the baud rate %" PRIu32 "",
  232. pBaudRate->BaudRate);
  233. SetLastError(ERROR_INVALID_DATA);
  234. return FALSE;
  235. }
  236. static BOOL _get_baud_rate(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate)
  237. {
  238. int i;
  239. speed_t currentSpeed;
  240. struct termios currentState;
  241. ZeroMemory(&currentState, sizeof(struct termios));
  242. if (tcgetattr(pComm->fd, &currentState) < 0)
  243. {
  244. SetLastError(ERROR_IO_DEVICE);
  245. return FALSE;
  246. }
  247. currentSpeed = cfgetispeed(&currentState);
  248. for (i = 0; _BAUD_TABLE[i][0] < _BAUD_TABLE_END; i++)
  249. {
  250. if (_BAUD_TABLE[i][0] == currentSpeed)
  251. {
  252. pBaudRate->BaudRate = _BAUD_TABLE[i][1];
  253. return TRUE;
  254. }
  255. }
  256. CommLog_Print(WLOG_WARN, "could not find a matching baud rate for the speed 0x%x",
  257. currentSpeed);
  258. SetLastError(ERROR_INVALID_DATA);
  259. return FALSE;
  260. }
  261. /**
  262. * NOTE: Only XonChar and XoffChar are plenty supported with the Linux
  263. * N_TTY line discipline.
  264. *
  265. * ERRORS:
  266. * ERROR_IO_DEVICE
  267. * ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same;
  268. * ERROR_NOT_SUPPORTED
  269. */
  270. static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
  271. {
  272. BOOL result = TRUE;
  273. struct termios upcomingTermios;
  274. ZeroMemory(&upcomingTermios, sizeof(struct termios));
  275. if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
  276. {
  277. SetLastError(ERROR_IO_DEVICE);
  278. return FALSE;
  279. }
  280. if (pSerialChars->XonChar == pSerialChars->XoffChar)
  281. {
  282. /* https://msdn.microsoft.com/en-us/library/windows/hardware/ff546688?v=vs.85.aspx */
  283. SetLastError(ERROR_INVALID_PARAMETER);
  284. return FALSE;
  285. }
  286. /* termios(3): (..) above symbolic subscript values are all
  287. * different, except that VTIME, VMIN may have the same value
  288. * as VEOL, VEOF, respectively. In noncanonical mode the
  289. * special character meaning is replaced by the timeout
  290. * meaning.
  291. *
  292. * EofChar and c_cc[VEOF] are not quite the same, prefer to
  293. * don't use c_cc[VEOF] at all.
  294. *
  295. * FIXME: might be implemented during read/write I/O
  296. */
  297. if (pSerialChars->EofChar != '\0')
  298. {
  299. CommLog_Print(WLOG_WARN, "EofChar %02" PRIX8 " cannot be set\n", pSerialChars->EofChar);
  300. SetLastError(ERROR_NOT_SUPPORTED);
  301. result = FALSE; /* but keep on */
  302. }
  303. /* According the Linux's n_tty discipline, charaters with a
  304. * parity error can only be let unchanged, replaced by \0 or
  305. * get the prefix the prefix \377 \0
  306. */
  307. /* FIXME: see also: _set_handflow() */
  308. if (pSerialChars->ErrorChar != '\0')
  309. {
  310. CommLog_Print(WLOG_WARN, "ErrorChar 0x%02" PRIX8 " ('%c') cannot be set (unsupported).\n",
  311. pSerialChars->ErrorChar, (char)pSerialChars->ErrorChar);
  312. SetLastError(ERROR_NOT_SUPPORTED);
  313. result = FALSE; /* but keep on */
  314. }
  315. /* FIXME: see also: _set_handflow() */
  316. if (pSerialChars->BreakChar != '\0')
  317. {
  318. CommLog_Print(WLOG_WARN, "BreakChar 0x%02" PRIX8 " ('%c') cannot be set (unsupported).\n",
  319. pSerialChars->BreakChar, (char)pSerialChars->BreakChar);
  320. SetLastError(ERROR_NOT_SUPPORTED);
  321. result = FALSE; /* but keep on */
  322. }
  323. if (pSerialChars->EventChar != '\0')
  324. {
  325. pComm->eventChar = pSerialChars->EventChar;
  326. }
  327. upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar;
  328. upcomingTermios.c_cc[VSTOP] = pSerialChars->XoffChar;
  329. if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
  330. {
  331. CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%08" PRIX32 "",
  332. GetLastError());
  333. return FALSE;
  334. }
  335. return result;
  336. }
  337. static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
  338. {
  339. struct termios currentTermios;
  340. ZeroMemory(&currentTermios, sizeof(struct termios));
  341. if (tcgetattr(pComm->fd, &currentTermios) < 0)
  342. {
  343. SetLastError(ERROR_IO_DEVICE);
  344. return FALSE;
  345. }
  346. ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
  347. /* EofChar unsupported */
  348. /* ErrorChar unsupported */
  349. /* BreakChar unsupported */
  350. /* FIXME: see also: _set_serial_chars() */
  351. /* EventChar */
  352. pSerialChars->XonChar = currentTermios.c_cc[VSTART];
  353. pSerialChars->XoffChar = currentTermios.c_cc[VSTOP];
  354. return TRUE;
  355. }
  356. static BOOL _set_line_control(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLineControl)
  357. {
  358. BOOL result = TRUE;
  359. struct termios upcomingTermios;
  360. /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx
  361. *
  362. * The use of 5 data bits with 2 stop bits is an invalid
  363. * combination, as is 6, 7, or 8 data bits with 1.5 stop bits.
  364. *
  365. * FIXME: prefered to let the underlying driver to deal with
  366. * this issue. At least produce a warning message?
  367. */
  368. ZeroMemory(&upcomingTermios, sizeof(struct termios));
  369. if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
  370. {
  371. SetLastError(ERROR_IO_DEVICE);
  372. return FALSE;
  373. }
  374. /* FIXME: use of a COMMPROP to validate new settings? */
  375. switch (pLineControl->StopBits)
  376. {
  377. case STOP_BIT_1:
  378. upcomingTermios.c_cflag &= ~CSTOPB;
  379. break;
  380. case STOP_BITS_1_5:
  381. CommLog_Print(WLOG_WARN, "Unsupported one and a half stop bits.");
  382. break;
  383. case STOP_BITS_2:
  384. upcomingTermios.c_cflag |= CSTOPB;
  385. break;
  386. default:
  387. CommLog_Print(WLOG_WARN, "unexpected number of stop bits: %" PRIu8 "\n",
  388. pLineControl->StopBits);
  389. result = FALSE; /* but keep on */
  390. break;
  391. }
  392. switch (pLineControl->Parity)
  393. {
  394. case NO_PARITY:
  395. upcomingTermios.c_cflag &= ~(PARENB | PARODD | CMSPAR);
  396. break;
  397. case ODD_PARITY:
  398. upcomingTermios.c_cflag &= ~CMSPAR;
  399. upcomingTermios.c_cflag |= PARENB | PARODD;
  400. break;
  401. case EVEN_PARITY:
  402. upcomingTermios.c_cflag &= ~(PARODD | CMSPAR);
  403. upcomingTermios.c_cflag |= PARENB;
  404. break;
  405. case MARK_PARITY:
  406. upcomingTermios.c_cflag |= PARENB | PARODD | CMSPAR;
  407. break;
  408. case SPACE_PARITY:
  409. upcomingTermios.c_cflag &= ~PARODD;
  410. upcomingTermios.c_cflag |= PARENB | CMSPAR;
  411. break;
  412. default:
  413. CommLog_Print(WLOG_WARN, "unexpected type of parity: %" PRIu8 "\n",
  414. pLineControl->Parity);
  415. result = FALSE; /* but keep on */
  416. break;
  417. }
  418. switch (pLineControl->WordLength)
  419. {
  420. case 5:
  421. upcomingTermios.c_cflag &= ~CSIZE;
  422. upcomingTermios.c_cflag |= CS5;
  423. break;
  424. case 6:
  425. upcomingTermios.c_cflag &= ~CSIZE;
  426. upcomingTermios.c_cflag |= CS6;
  427. break;
  428. case 7:
  429. upcomingTermios.c_cflag &= ~CSIZE;
  430. upcomingTermios.c_cflag |= CS7;
  431. break;
  432. case 8:
  433. upcomingTermios.c_cflag &= ~CSIZE;
  434. upcomingTermios.c_cflag |= CS8;
  435. break;
  436. default:
  437. CommLog_Print(WLOG_WARN, "unexpected number od data bits per character: %" PRIu8 "\n",
  438. pLineControl->WordLength);
  439. result = FALSE; /* but keep on */
  440. break;
  441. }
  442. if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
  443. {
  444. CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%08" PRIX32 "",
  445. GetLastError());
  446. return FALSE;
  447. }
  448. return result;
  449. }
  450. static BOOL _get_line_control(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineControl)
  451. {
  452. struct termios currentTermios;
  453. ZeroMemory(&currentTermios, sizeof(struct termios));
  454. if (tcgetattr(pComm->fd, &currentTermios) < 0)
  455. {
  456. SetLastError(ERROR_IO_DEVICE);
  457. return FALSE;
  458. }
  459. pLineControl->StopBits = (currentTermios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BIT_1;
  460. if (!(currentTermios.c_cflag & PARENB))
  461. {
  462. pLineControl->Parity = NO_PARITY;
  463. }
  464. else if (currentTermios.c_cflag & CMSPAR)
  465. {
  466. pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? MARK_PARITY : SPACE_PARITY;
  467. }
  468. else
  469. {
  470. /* PARENB is set */
  471. pLineControl->Parity = (currentTermios.c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY;
  472. }
  473. switch (currentTermios.c_cflag & CSIZE)
  474. {
  475. case CS5:
  476. pLineControl->WordLength = 5;
  477. break;
  478. case CS6:
  479. pLineControl->WordLength = 6;
  480. break;
  481. case CS7:
  482. pLineControl->WordLength = 7;
  483. break;
  484. default:
  485. pLineControl->WordLength = 8;
  486. break;
  487. }
  488. return TRUE;
  489. }
  490. static BOOL _set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
  491. {
  492. BOOL result = TRUE;
  493. struct termios upcomingTermios;
  494. ZeroMemory(&upcomingTermios, sizeof(struct termios));
  495. if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
  496. {
  497. SetLastError(ERROR_IO_DEVICE);
  498. return FALSE;
  499. }
  500. /* HUPCL */
  501. /* logical XOR */
  502. if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) &&
  503. (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) ||
  504. ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) &&
  505. !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL)))
  506. {
  507. CommLog_Print(WLOG_WARN,
  508. "SERIAL_DTR_CONTROL:%s and SERIAL_RTS_CONTROL:%s cannot be different, HUPCL "
  509. "will be set since it is claimed for one of the both lines.",
  510. (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ? "ON" : "OFF",
  511. (pHandflow->FlowReplace & SERIAL_RTS_CONTROL) ? "ON" : "OFF");
  512. }
  513. if ((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) ||
  514. (pHandflow->FlowReplace & SERIAL_RTS_CONTROL))
  515. {
  516. upcomingTermios.c_cflag |= HUPCL;
  517. }
  518. else
  519. {
  520. upcomingTermios.c_cflag &= ~HUPCL;
  521. /* FIXME: is the DTR line also needs to be forced to a disable state according
  522. * SERIAL_DTR_CONTROL? */
  523. /* FIXME: is the RTS line also needs to be forced to a disable state according
  524. * SERIAL_RTS_CONTROL? */
  525. }
  526. /* CRTSCTS */
  527. /* logical XOR */
  528. if ((!(pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) &&
  529. (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)) ||
  530. ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) &&
  531. !(pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)))
  532. {
  533. CommLog_Print(WLOG_WARN,
  534. "SERIAL_CTS_HANDSHAKE:%s and SERIAL_RTS_HANDSHAKE:%s cannot be different, "
  535. "CRTSCTS will be set since it is claimed for one of the both lines.",
  536. (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ? "ON" : "OFF",
  537. (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE) ? "ON" : "OFF");
  538. }
  539. if ((pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
  540. (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE))
  541. {
  542. upcomingTermios.c_cflag |= CRTSCTS;
  543. }
  544. else
  545. {
  546. upcomingTermios.c_cflag &= ~CRTSCTS;
  547. }
  548. /* ControlHandShake */
  549. if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE)
  550. {
  551. /* DTR/DSR flow control not supported on Linux */
  552. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature.");
  553. SetLastError(ERROR_NOT_SUPPORTED);
  554. result = FALSE; /* but keep on */
  555. }
  556. if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE)
  557. {
  558. /* DTR/DSR flow control not supported on Linux */
  559. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature.");
  560. SetLastError(ERROR_NOT_SUPPORTED);
  561. result = FALSE; /* but keep on */
  562. }
  563. if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
  564. {
  565. /* DCD flow control not supported on Linux */
  566. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DCD_HANDSHAKE feature.");
  567. SetLastError(ERROR_NOT_SUPPORTED);
  568. result = FALSE; /* but keep on */
  569. }
  570. // FIXME: could be implemented during read/write I/O
  571. if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
  572. {
  573. /* DSR line control not supported on Linux */
  574. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_DSR_SENSITIVITY feature.");
  575. SetLastError(ERROR_NOT_SUPPORTED);
  576. result = FALSE; /* but keep on */
  577. }
  578. // FIXME: could be implemented during read/write I/O
  579. if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
  580. {
  581. /* Aborting operations on error not supported on Linux */
  582. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_ERROR_ABORT feature.");
  583. SetLastError(ERROR_NOT_SUPPORTED);
  584. result = FALSE; /* but keep on */
  585. }
  586. /* FlowReplace */
  587. if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT)
  588. {
  589. upcomingTermios.c_iflag |= IXON;
  590. }
  591. else
  592. {
  593. upcomingTermios.c_iflag &= ~IXON;
  594. }
  595. if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE)
  596. {
  597. upcomingTermios.c_iflag |= IXOFF;
  598. }
  599. else
  600. {
  601. upcomingTermios.c_iflag &= ~IXOFF;
  602. }
  603. // FIXME: could be implemented during read/write I/O, as of today ErrorChar is necessary '\0'
  604. if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR)
  605. {
  606. /* errors will be replaced by the character '\0'. */
  607. upcomingTermios.c_iflag &= ~IGNPAR;
  608. }
  609. else
  610. {
  611. upcomingTermios.c_iflag |= IGNPAR;
  612. }
  613. if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING)
  614. {
  615. upcomingTermios.c_iflag |= IGNBRK;
  616. }
  617. else
  618. {
  619. upcomingTermios.c_iflag &= ~IGNBRK;
  620. }
  621. // FIXME: could be implemented during read/write I/O
  622. if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR)
  623. {
  624. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_BREAK_CHAR feature.");
  625. SetLastError(ERROR_NOT_SUPPORTED);
  626. result = FALSE; /* but keep on */
  627. }
  628. // FIXME: could be implemented during read/write I/O
  629. if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE)
  630. {
  631. /* not supported on Linux */
  632. CommLog_Print(WLOG_WARN, "Attempt to use the unsupported SERIAL_XOFF_CONTINUE feature.");
  633. SetLastError(ERROR_NOT_SUPPORTED);
  634. result = FALSE; /* but keep on */
  635. }
  636. /* XonLimit */
  637. // FIXME: could be implemented during read/write I/O
  638. if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE)
  639. {
  640. CommLog_Print(WLOG_WARN, "Attempt to set XonLimit with an unsupported value: %" PRId32 "",
  641. pHandflow->XonLimit);
  642. SetLastError(ERROR_NOT_SUPPORTED);
  643. result = FALSE; /* but keep on */
  644. }
  645. /* XoffChar */
  646. // FIXME: could be implemented during read/write I/O
  647. if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE)
  648. {
  649. CommLog_Print(WLOG_WARN, "Attempt to set XoffLimit with an unsupported value: %" PRId32 "",
  650. pHandflow->XoffLimit);
  651. SetLastError(ERROR_NOT_SUPPORTED);
  652. result = FALSE; /* but keep on */
  653. }
  654. if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
  655. {
  656. CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%" PRIX32 "",
  657. GetLastError());
  658. return FALSE;
  659. }
  660. return result;
  661. }
  662. static BOOL _get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
  663. {
  664. struct termios currentTermios;
  665. ZeroMemory(&currentTermios, sizeof(struct termios));
  666. if (tcgetattr(pComm->fd, &currentTermios) < 0)
  667. {
  668. SetLastError(ERROR_IO_DEVICE);
  669. return FALSE;
  670. }
  671. /* ControlHandShake */
  672. pHandflow->ControlHandShake = 0;
  673. if (currentTermios.c_cflag & HUPCL)
  674. pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL;
  675. /* SERIAL_DTR_HANDSHAKE unsupported */
  676. if (currentTermios.c_cflag & CRTSCTS)
  677. pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
  678. /* SERIAL_DSR_HANDSHAKE unsupported */
  679. /* SERIAL_DCD_HANDSHAKE unsupported */
  680. /* SERIAL_DSR_SENSITIVITY unsupported */
  681. /* SERIAL_ERROR_ABORT unsupported */
  682. /* FlowReplace */
  683. pHandflow->FlowReplace = 0;
  684. if (currentTermios.c_iflag & IXON)
  685. pHandflow->FlowReplace |= SERIAL_AUTO_TRANSMIT;
  686. if (currentTermios.c_iflag & IXOFF)
  687. pHandflow->FlowReplace |= SERIAL_AUTO_RECEIVE;
  688. if (!(currentTermios.c_iflag & IGNPAR))
  689. pHandflow->FlowReplace |= SERIAL_ERROR_CHAR;
  690. if (currentTermios.c_iflag & IGNBRK)
  691. pHandflow->FlowReplace |= SERIAL_NULL_STRIPPING;
  692. /* SERIAL_BREAK_CHAR unsupported */
  693. if (currentTermios.c_cflag & HUPCL)
  694. pHandflow->FlowReplace |= SERIAL_RTS_CONTROL;
  695. if (currentTermios.c_cflag & CRTSCTS)
  696. pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE;
  697. /* SERIAL_XOFF_CONTINUE unsupported */
  698. /* XonLimit */
  699. pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE;
  700. /* XoffLimit */
  701. pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE;
  702. return TRUE;
  703. }
  704. static BOOL _set_timeouts(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts)
  705. {
  706. /* NB: timeouts are applied on system during read/write I/O */
  707. /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx */
  708. if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
  709. (pTimeouts->ReadTotalTimeoutConstant == MAXULONG))
  710. {
  711. CommLog_Print(
  712. WLOG_WARN,
  713. "ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG");
  714. SetLastError(ERROR_INVALID_PARAMETER);
  715. return FALSE;
  716. }
  717. pComm->timeouts.ReadIntervalTimeout = pTimeouts->ReadIntervalTimeout;
  718. pComm->timeouts.ReadTotalTimeoutMultiplier = pTimeouts->ReadTotalTimeoutMultiplier;
  719. pComm->timeouts.ReadTotalTimeoutConstant = pTimeouts->ReadTotalTimeoutConstant;
  720. pComm->timeouts.WriteTotalTimeoutMultiplier = pTimeouts->WriteTotalTimeoutMultiplier;
  721. pComm->timeouts.WriteTotalTimeoutConstant = pTimeouts->WriteTotalTimeoutConstant;
  722. CommLog_Print(WLOG_DEBUG, "ReadIntervalTimeout %" PRIu32 "",
  723. pComm->timeouts.ReadIntervalTimeout);
  724. CommLog_Print(WLOG_DEBUG, "ReadTotalTimeoutMultiplier %" PRIu32 "",
  725. pComm->timeouts.ReadTotalTimeoutMultiplier);
  726. CommLog_Print(WLOG_DEBUG, "ReadTotalTimeoutConstant %" PRIu32 "",
  727. pComm->timeouts.ReadTotalTimeoutConstant);
  728. CommLog_Print(WLOG_DEBUG, "WriteTotalTimeoutMultiplier %" PRIu32 "",
  729. pComm->timeouts.WriteTotalTimeoutMultiplier);
  730. CommLog_Print(WLOG_DEBUG, "WriteTotalTimeoutConstant %" PRIu32 "",
  731. pComm->timeouts.WriteTotalTimeoutConstant);
  732. return TRUE;
  733. }
  734. static BOOL _get_timeouts(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts)
  735. {
  736. pTimeouts->ReadIntervalTimeout = pComm->timeouts.ReadIntervalTimeout;
  737. pTimeouts->ReadTotalTimeoutMultiplier = pComm->timeouts.ReadTotalTimeoutMultiplier;
  738. pTimeouts->ReadTotalTimeoutConstant = pComm->timeouts.ReadTotalTimeoutConstant;
  739. pTimeouts->WriteTotalTimeoutMultiplier = pComm->timeouts.WriteTotalTimeoutMultiplier;
  740. pTimeouts->WriteTotalTimeoutConstant = pComm->timeouts.WriteTotalTimeoutConstant;
  741. return TRUE;
  742. }
  743. static BOOL _set_lines(WINPR_COMM* pComm, UINT32 lines)
  744. {
  745. if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0)
  746. {
  747. CommLog_Print(WLOG_WARN, "TIOCMBIS ioctl failed, lines=0x%" PRIX32 ", errno=[%d] %s", lines,
  748. errno, strerror(errno));
  749. SetLastError(ERROR_IO_DEVICE);
  750. return FALSE;
  751. }
  752. return TRUE;
  753. }
  754. static BOOL _clear_lines(WINPR_COMM* pComm, UINT32 lines)
  755. {
  756. if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0)
  757. {
  758. CommLog_Print(WLOG_WARN, "TIOCMBIC ioctl failed, lines=0x%" PRIX32 ", errno=[%d] %s", lines,
  759. errno, strerror(errno));
  760. SetLastError(ERROR_IO_DEVICE);
  761. return FALSE;
  762. }
  763. return TRUE;
  764. }
  765. static BOOL _set_dtr(WINPR_COMM* pComm)
  766. {
  767. SERIAL_HANDFLOW handflow;
  768. if (!_get_handflow(pComm, &handflow))
  769. return FALSE;
  770. /* SERIAL_DTR_HANDSHAKE not supported as of today */
  771. assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0);
  772. if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
  773. {
  774. SetLastError(ERROR_INVALID_PARAMETER);
  775. return FALSE;
  776. }
  777. return _set_lines(pComm, TIOCM_DTR);
  778. }
  779. static BOOL _clear_dtr(WINPR_COMM* pComm)
  780. {
  781. SERIAL_HANDFLOW handflow;
  782. if (!_get_handflow(pComm, &handflow))
  783. return FALSE;
  784. /* SERIAL_DTR_HANDSHAKE not supported as of today */
  785. assert((handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) == 0);
  786. if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
  787. {
  788. SetLastError(ERROR_INVALID_PARAMETER);
  789. return FALSE;
  790. }
  791. return _clear_lines(pComm, TIOCM_DTR);
  792. }
  793. static BOOL _set_rts(WINPR_COMM* pComm)
  794. {
  795. SERIAL_HANDFLOW handflow;
  796. if (!_get_handflow(pComm, &handflow))
  797. return FALSE;
  798. if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
  799. {
  800. SetLastError(ERROR_INVALID_PARAMETER);
  801. return FALSE;
  802. }
  803. return _set_lines(pComm, TIOCM_RTS);
  804. }
  805. static BOOL _clear_rts(WINPR_COMM* pComm)
  806. {
  807. SERIAL_HANDFLOW handflow;
  808. if (!_get_handflow(pComm, &handflow))
  809. return FALSE;
  810. if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
  811. {
  812. SetLastError(ERROR_INVALID_PARAMETER);
  813. return FALSE;
  814. }
  815. return _clear_lines(pComm, TIOCM_RTS);
  816. }
  817. static BOOL _get_modemstatus(WINPR_COMM* pComm, ULONG* pRegister)
  818. {
  819. UINT32 lines = 0;
  820. if (ioctl(pComm->fd, TIOCMGET, &lines) < 0)
  821. {
  822. CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno));
  823. SetLastError(ERROR_IO_DEVICE);
  824. return FALSE;
  825. }
  826. ZeroMemory(pRegister, sizeof(ULONG));
  827. /* FIXME: Is the last read of the MSR register available or
  828. * cached somewhere? Not quite sure we need to return the 4
  829. * LSBits anyway. A direct access to the register -- which
  830. * would reset the register -- is likely not expected from
  831. * this function.
  832. */
  833. /* #define SERIAL_MSR_DCTS 0x01 */
  834. /* #define SERIAL_MSR_DDSR 0x02 */
  835. /* #define SERIAL_MSR_TERI 0x04 */
  836. /* #define SERIAL_MSR_DDCD 0x08 */
  837. if (lines & TIOCM_CTS)
  838. *pRegister |= SERIAL_MSR_CTS;
  839. if (lines & TIOCM_DSR)
  840. *pRegister |= SERIAL_MSR_DSR;
  841. if (lines & TIOCM_RI)
  842. *pRegister |= SERIAL_MSR_RI;
  843. if (lines & TIOCM_CD)
  844. *pRegister |= SERIAL_MSR_DCD;
  845. return TRUE;
  846. }
  847. /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
  848. static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK =
  849. SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
  850. SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING |
  851. /* SERIAL_EV_PERR | */
  852. SERIAL_EV_RX80FULL /*|
  853. SERIAL_EV_EVENT1 |
  854. SERIAL_EV_EVENT2*/
  855. ;
  856. static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
  857. {
  858. ULONG possibleMask;
  859. /* Stops pending IOCTL_SERIAL_WAIT_ON_MASK
  860. * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx
  861. */
  862. if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING)
  863. {
  864. /* FIXME: any doubt on reading PendingEvents out of a critical section? */
  865. EnterCriticalSection(&pComm->EventsLock);
  866. pComm->PendingEvents |= SERIAL_EV_FREERDP_STOP;
  867. LeaveCriticalSection(&pComm->EventsLock);
  868. /* waiting the end of the pending _wait_on_mask() */
  869. while (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING)
  870. Sleep(10); /* 10ms */
  871. }
  872. /* NB: ensure to leave the critical section before to return */
  873. EnterCriticalSection(&pComm->EventsLock);
  874. if (*pWaitMask == 0)
  875. {
  876. /* clearing pending events */
  877. if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
  878. {
  879. CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
  880. strerror(errno));
  881. if (pComm->permissive)
  882. {
  883. /* counters could not be reset but keep on */
  884. ZeroMemory(&(pComm->counters), sizeof(struct serial_icounter_struct));
  885. }
  886. else
  887. {
  888. SetLastError(ERROR_IO_DEVICE);
  889. LeaveCriticalSection(&pComm->EventsLock);
  890. return FALSE;
  891. }
  892. }
  893. pComm->PendingEvents = 0;
  894. }
  895. possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK;
  896. if (possibleMask != *pWaitMask)
  897. {
  898. CommLog_Print(WLOG_WARN,
  899. "Not all wait events supported (Serial.sys), requested events= 0x%08" PRIX32
  900. ", possible events= 0x%08" PRIX32 "",
  901. *pWaitMask, possibleMask);
  902. /* FIXME: shall we really set the possibleMask and return FALSE? */
  903. pComm->WaitEventMask = possibleMask;
  904. LeaveCriticalSection(&pComm->EventsLock);
  905. return FALSE;
  906. }
  907. pComm->WaitEventMask = possibleMask;
  908. LeaveCriticalSection(&pComm->EventsLock);
  909. return TRUE;
  910. }
  911. static BOOL _get_wait_mask(WINPR_COMM* pComm, ULONG* pWaitMask)
  912. {
  913. *pWaitMask = pComm->WaitEventMask;
  914. return TRUE;
  915. }
  916. static BOOL _set_queue_size(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSize)
  917. {
  918. if ((pQueueSize->InSize <= N_TTY_BUF_SIZE) && (pQueueSize->OutSize <= N_TTY_BUF_SIZE))
  919. return TRUE; /* nothing to do */
  920. /* FIXME: could be implemented on top of N_TTY */
  921. if (pQueueSize->InSize > N_TTY_BUF_SIZE)
  922. CommLog_Print(WLOG_WARN,
  923. "Requested an incompatible input buffer size: %" PRIu32
  924. ", keeping on with a %" PRIu32 " bytes buffer.",
  925. pQueueSize->InSize, N_TTY_BUF_SIZE);
  926. if (pQueueSize->OutSize > N_TTY_BUF_SIZE)
  927. CommLog_Print(WLOG_WARN,
  928. "Requested an incompatible output buffer size: %" PRIu32
  929. ", keeping on with a %" PRIu32 " bytes buffer.",
  930. pQueueSize->OutSize, N_TTY_BUF_SIZE);
  931. SetLastError(ERROR_CANCELLED);
  932. return FALSE;
  933. }
  934. static BOOL _purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
  935. {
  936. if ((*pPurgeMask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR |
  937. SERIAL_PURGE_RXCLEAR)) > 0)
  938. {
  939. CommLog_Print(WLOG_WARN, "Invalid purge mask: 0x%" PRIX32 "\n", *pPurgeMask);
  940. SetLastError(ERROR_INVALID_PARAMETER);
  941. return FALSE;
  942. }
  943. /* FIXME: currently relying too much on the fact the server
  944. * sends a single IRP_MJ_WRITE or IRP_MJ_READ at a time
  945. * (taking care though that one IRP_MJ_WRITE and one
  946. * IRP_MJ_READ can be sent simultaneously) */
  947. if (*pPurgeMask & SERIAL_PURGE_TXABORT)
  948. {
  949. /* Purges all write (IRP_MJ_WRITE) requests. */
  950. if (eventfd_write(pComm->fd_write_event, FREERDP_PURGE_TXABORT) < 0)
  951. {
  952. if (errno != EAGAIN)
  953. {
  954. CommLog_Print(WLOG_WARN, "eventfd_write failed, errno=[%d] %s", errno,
  955. strerror(errno));
  956. }
  957. assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_WRITE */
  958. }
  959. }
  960. if (*pPurgeMask & SERIAL_PURGE_RXABORT)
  961. {
  962. /* Purges all read (IRP_MJ_READ) requests. */
  963. if (eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT) < 0)
  964. {
  965. if (errno != EAGAIN)
  966. {
  967. CommLog_Print(WLOG_WARN, "eventfd_write failed, errno=[%d] %s", errno,
  968. strerror(errno));
  969. }
  970. assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */
  971. }
  972. }
  973. if (*pPurgeMask & SERIAL_PURGE_TXCLEAR)
  974. {
  975. /* Purges the transmit buffer, if one exists. */
  976. if (tcflush(pComm->fd, TCOFLUSH) < 0)
  977. {
  978. CommLog_Print(WLOG_WARN, "tcflush(TCOFLUSH) failure, errno=[%d] %s", errno,
  979. strerror(errno));
  980. SetLastError(ERROR_CANCELLED);
  981. return FALSE;
  982. }
  983. }
  984. if (*pPurgeMask & SERIAL_PURGE_RXCLEAR)
  985. {
  986. /* Purges the receive buffer, if one exists. */
  987. if (tcflush(pComm->fd, TCIFLUSH) < 0)
  988. {
  989. CommLog_Print(WLOG_WARN, "tcflush(TCIFLUSH) failure, errno=[%d] %s", errno,
  990. strerror(errno));
  991. SetLastError(ERROR_CANCELLED);
  992. return FALSE;
  993. }
  994. }
  995. return TRUE;
  996. }
  997. /* NB: _get_commstatus also produces most of the events consumed by _wait_on_mask(). Exceptions:
  998. * - SERIAL_EV_RXFLAG: FIXME: once EventChar supported
  999. *
  1000. */
  1001. static BOOL _get_commstatus(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus)
  1002. {
  1003. /* http://msdn.microsoft.com/en-us/library/jj673022%28v=vs.85%29.aspx */
  1004. struct serial_icounter_struct currentCounters;
  1005. /* NB: ensure to leave the critical section before to return */
  1006. EnterCriticalSection(&pComm->EventsLock);
  1007. ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS));
  1008. ZeroMemory(&currentCounters, sizeof(struct serial_icounter_struct));
  1009. if (ioctl(pComm->fd, TIOCGICOUNT, &currentCounters) < 0)
  1010. {
  1011. CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
  1012. strerror(errno));
  1013. CommLog_Print(WLOG_WARN, " could not read counters.");
  1014. if (pComm->permissive)
  1015. {
  1016. /* Errors and events based on counters could not be
  1017. * detected but keep on.
  1018. */
  1019. ZeroMemory(&currentCounters, sizeof(struct serial_icounter_struct));
  1020. }
  1021. else
  1022. {
  1023. SetLastError(ERROR_IO_DEVICE);
  1024. LeaveCriticalSection(&pComm->EventsLock);
  1025. return FALSE;
  1026. }
  1027. }
  1028. /* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* >
  1029. * pComm->counters.*) thinking the counters can loop */
  1030. /* Errors */
  1031. if (currentCounters.buf_overrun != pComm->counters.buf_overrun)
  1032. {
  1033. pCommstatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN;
  1034. }
  1035. if (currentCounters.overrun != pComm->counters.overrun)
  1036. {
  1037. pCommstatus->Errors |= SERIAL_ERROR_OVERRUN;
  1038. pComm->PendingEvents |= SERIAL_EV_ERR;
  1039. }
  1040. if (currentCounters.brk != pComm->counters.brk)
  1041. {
  1042. pCommstatus->Errors |= SERIAL_ERROR_BREAK;
  1043. pComm->PendingEvents |= SERIAL_EV_BREAK;
  1044. }
  1045. if (currentCounters.parity != pComm->counters.parity)
  1046. {
  1047. pCommstatus->Errors |= SERIAL_ERROR_PARITY;
  1048. pComm->PendingEvents |= SERIAL_EV_ERR;
  1049. }
  1050. if (currentCounters.frame != pComm->counters.frame)
  1051. {
  1052. pCommstatus->Errors |= SERIAL_ERROR_FRAMING;
  1053. pComm->PendingEvents |= SERIAL_EV_ERR;
  1054. }
  1055. /* HoldReasons */
  1056. /* TODO: SERIAL_TX_WAITING_FOR_CTS */
  1057. /* TODO: SERIAL_TX_WAITING_FOR_DSR */
  1058. /* TODO: SERIAL_TX_WAITING_FOR_DCD */
  1059. /* TODO: SERIAL_TX_WAITING_FOR_XON */
  1060. /* TODO: SERIAL_TX_WAITING_ON_BREAK, see LCR's bit 6 */
  1061. /* TODO: SERIAL_TX_WAITING_XOFF_SENT */
  1062. /* AmountInInQueue */
  1063. if (ioctl(pComm->fd, TIOCINQ, &(pCommstatus->AmountInInQueue)) < 0)
  1064. {
  1065. CommLog_Print(WLOG_WARN, "TIOCINQ ioctl failed, errno=[%d] %s", errno, strerror(errno));
  1066. SetLastError(ERROR_IO_DEVICE);
  1067. LeaveCriticalSection(&pComm->EventsLock);
  1068. return FALSE;
  1069. }
  1070. /* AmountInOutQueue */
  1071. if (ioctl(pComm->fd, TIOCOUTQ, &(pCommstatus->AmountInOutQueue)) < 0)
  1072. {
  1073. CommLog_Print(WLOG_WARN, "TIOCOUTQ ioctl failed, errno=[%d] %s", errno, strerror(errno));
  1074. SetLastError(ERROR_IO_DEVICE);
  1075. LeaveCriticalSection(&pComm->EventsLock);
  1076. return FALSE;
  1077. }
  1078. /* BOOLEAN EofReceived; FIXME: once EofChar supported */
  1079. /* BOOLEAN WaitForImmediate; TODO: once IOCTL_SERIAL_IMMEDIATE_CHAR fully supported */
  1080. /* other events based on counters */
  1081. if (currentCounters.rx != pComm->counters.rx)
  1082. {
  1083. pComm->PendingEvents |= SERIAL_EV_RXFLAG | SERIAL_EV_RXCHAR;
  1084. }
  1085. if ((currentCounters.tx != pComm->counters.tx) && /* at least a transmission occurred AND ...*/
  1086. (pCommstatus->AmountInOutQueue == 0)) /* output bufer is now empty */
  1087. {
  1088. pComm->PendingEvents |= SERIAL_EV_TXEMPTY;
  1089. }
  1090. else
  1091. {
  1092. /* FIXME: "now empty" from the specs is ambiguous, need to track previous completed
  1093. * transmission? */
  1094. pComm->PendingEvents &= ~SERIAL_EV_TXEMPTY;
  1095. }
  1096. if (currentCounters.cts != pComm->counters.cts)
  1097. {
  1098. pComm->PendingEvents |= SERIAL_EV_CTS;
  1099. }
  1100. if (currentCounters.dsr != pComm->counters.dsr)
  1101. {
  1102. pComm->PendingEvents |= SERIAL_EV_DSR;
  1103. }
  1104. if (currentCounters.dcd != pComm->counters.dcd)
  1105. {
  1106. pComm->PendingEvents |= SERIAL_EV_RLSD;
  1107. }
  1108. if (currentCounters.rng != pComm->counters.rng)
  1109. {
  1110. pComm->PendingEvents |= SERIAL_EV_RING;
  1111. }
  1112. if (pCommstatus->AmountInInQueue > (0.8 * N_TTY_BUF_SIZE))
  1113. {
  1114. pComm->PendingEvents |= SERIAL_EV_RX80FULL;
  1115. }
  1116. else
  1117. {
  1118. /* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously
  1119. * * occurred? */
  1120. pComm->PendingEvents &= ~SERIAL_EV_RX80FULL;
  1121. }
  1122. pComm->counters = currentCounters;
  1123. LeaveCriticalSection(&pComm->EventsLock);
  1124. return TRUE;
  1125. }
  1126. static BOOL _refresh_PendingEvents(WINPR_COMM* pComm)
  1127. {
  1128. SERIAL_STATUS serialStatus;
  1129. /* NB: also ensures PendingEvents to be up to date */
  1130. ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS));
  1131. if (!_get_commstatus(pComm, &serialStatus))
  1132. {
  1133. return FALSE;
  1134. }
  1135. return TRUE;
  1136. }
  1137. static void _consume_event(WINPR_COMM* pComm, ULONG* pOutputMask, ULONG event)
  1138. {
  1139. if ((pComm->WaitEventMask & event) && (pComm->PendingEvents & event))
  1140. {
  1141. pComm->PendingEvents &= ~event; /* consumed */
  1142. *pOutputMask |= event;
  1143. }
  1144. }
  1145. /*
  1146. * NB: see also: _set_wait_mask()
  1147. */
  1148. static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
  1149. {
  1150. assert(*pOutputMask == 0);
  1151. EnterCriticalSection(&pComm->EventsLock);
  1152. pComm->PendingEvents |= SERIAL_EV_FREERDP_WAITING;
  1153. LeaveCriticalSection(&pComm->EventsLock);
  1154. while (TRUE)
  1155. {
  1156. /* NB: EventsLock also used by _refresh_PendingEvents() */
  1157. if (!_refresh_PendingEvents(pComm))
  1158. {
  1159. EnterCriticalSection(&pComm->EventsLock);
  1160. pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING;
  1161. LeaveCriticalSection(&pComm->EventsLock);
  1162. return FALSE;
  1163. }
  1164. /* NB: ensure to leave the critical section before to return */
  1165. EnterCriticalSection(&pComm->EventsLock);
  1166. if (pComm->PendingEvents & SERIAL_EV_FREERDP_STOP)
  1167. {
  1168. pComm->PendingEvents &= ~SERIAL_EV_FREERDP_STOP;
  1169. /* pOutputMask must remain empty but should
  1170. * not have been modified.
  1171. *
  1172. * http://msdn.microsoft.com/en-us/library/ff546805%28v=vs.85%29.aspx
  1173. */
  1174. assert(*pOutputMask == 0);
  1175. pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING;
  1176. LeaveCriticalSection(&pComm->EventsLock);
  1177. return TRUE;
  1178. }
  1179. _consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR);
  1180. _consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG);
  1181. _consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY);
  1182. _consume_event(pComm, pOutputMask, SERIAL_EV_CTS);
  1183. _consume_event(pComm, pOutputMask, SERIAL_EV_DSR);
  1184. _consume_event(pComm, pOutputMask, SERIAL_EV_RLSD);
  1185. _consume_event(pComm, pOutputMask, SERIAL_EV_BREAK);
  1186. _consume_event(pComm, pOutputMask, SERIAL_EV_ERR);
  1187. _consume_event(pComm, pOutputMask, SERIAL_EV_RING);
  1188. _consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL);
  1189. LeaveCriticalSection(&pComm->EventsLock);
  1190. /* NOTE: PendingEvents can be modified from now on but
  1191. * not pOutputMask */
  1192. if (*pOutputMask != 0)
  1193. {
  1194. /* at least an event occurred */
  1195. EnterCriticalSection(&pComm->EventsLock);
  1196. pComm->PendingEvents &= ~SERIAL_EV_FREERDP_WAITING;
  1197. LeaveCriticalSection(&pComm->EventsLock);
  1198. return TRUE;
  1199. }
  1200. /* waiting for a modification of PendingEvents.
  1201. *
  1202. * NOTE: previously used a semaphore but used
  1203. * sem_timedwait() anyway. Finally preferred a simpler
  1204. * solution with Sleep() without the burden of the
  1205. * semaphore initialization and destroying.
  1206. */
  1207. Sleep(100); /* 100 ms */
  1208. }
  1209. }
  1210. static BOOL _set_break_on(WINPR_COMM* pComm)
  1211. {
  1212. if (ioctl(pComm->fd, TIOCSBRK, NULL) < 0)
  1213. {
  1214. CommLog_Print(WLOG_WARN, "TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno));
  1215. SetLastError(ERROR_IO_DEVICE);
  1216. return FALSE;
  1217. }
  1218. return TRUE;
  1219. }
  1220. static BOOL _set_break_off(WINPR_COMM* pComm)
  1221. {
  1222. if (ioctl(pComm->fd, TIOCCBRK, NULL) < 0)
  1223. {
  1224. CommLog_Print(WLOG_WARN, "TIOCSBRK ioctl failed, errno=[%d] %s", errno, strerror(errno));
  1225. SetLastError(ERROR_IO_DEVICE);
  1226. return FALSE;
  1227. }
  1228. return TRUE;
  1229. }
  1230. static BOOL _set_xoff(WINPR_COMM* pComm)
  1231. {
  1232. if (tcflow(pComm->fd, TCIOFF) < 0)
  1233. {
  1234. CommLog_Print(WLOG_WARN, "TCIOFF failure, errno=[%d] %s", errno, strerror(errno));
  1235. SetLastError(ERROR_IO_DEVICE);
  1236. return FALSE;
  1237. }
  1238. return TRUE;
  1239. }
  1240. static BOOL _set_xon(WINPR_COMM* pComm)
  1241. {
  1242. if (tcflow(pComm->fd, TCION) < 0)
  1243. {
  1244. CommLog_Print(WLOG_WARN, "TCION failure, errno=[%d] %s", errno, strerror(errno));
  1245. SetLastError(ERROR_IO_DEVICE);
  1246. return FALSE;
  1247. }
  1248. return TRUE;
  1249. }
  1250. static BOOL _get_dtrrts(WINPR_COMM* pComm, ULONG* pMask)
  1251. {
  1252. UINT32 lines = 0;
  1253. if (ioctl(pComm->fd, TIOCMGET, &lines) < 0)
  1254. {
  1255. CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno, strerror(errno));
  1256. SetLastError(ERROR_IO_DEVICE);
  1257. return FALSE;
  1258. }
  1259. *pMask = 0;
  1260. if (!(lines & TIOCM_DTR))
  1261. *pMask |= SERIAL_DTR_STATE;
  1262. if (!(lines & TIOCM_RTS))
  1263. *pMask |= SERIAL_RTS_STATE;
  1264. return TRUE;
  1265. }
  1266. static BOOL _config_size(WINPR_COMM* pComm, ULONG* pSize)
  1267. {
  1268. /* http://msdn.microsoft.com/en-us/library/ff546548%28v=vs.85%29.aspx */
  1269. if (!pSize)
  1270. return FALSE;
  1271. *pSize = 0;
  1272. return TRUE;
  1273. }
  1274. static BOOL _immediate_char(WINPR_COMM* pComm, const UCHAR* pChar)
  1275. {
  1276. BOOL result;
  1277. DWORD nbBytesWritten = -1;
  1278. /* FIXME: CommWriteFile uses a critical section, shall it be
  1279. * interrupted?
  1280. *
  1281. * FIXME: see also _get_commstatus()'s WaitForImmediate boolean
  1282. */
  1283. result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL);
  1284. assert(nbBytesWritten == 1);
  1285. return result;
  1286. }
  1287. static BOOL _reset_device(WINPR_COMM* pComm)
  1288. {
  1289. /* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx */
  1290. return TRUE;
  1291. }
  1292. static SERIAL_DRIVER _SerialSys = {
  1293. .id = SerialDriverSerialSys,
  1294. .name = _T("Serial.sys"),
  1295. .set_baud_rate = _set_baud_rate,
  1296. .get_baud_rate = _get_baud_rate,
  1297. .get_properties = _get_properties,
  1298. .set_serial_chars = _set_serial_chars,
  1299. .get_serial_chars = _get_serial_chars,
  1300. .set_line_control = _set_line_control,
  1301. .get_line_control = _get_line_control,
  1302. .set_handflow = _set_handflow,
  1303. .get_handflow = _get_handflow,
  1304. .set_timeouts = _set_timeouts,
  1305. .get_timeouts = _get_timeouts,
  1306. .set_dtr = _set_dtr,
  1307. .clear_dtr = _clear_dtr,
  1308. .set_rts = _set_rts,
  1309. .clear_rts = _clear_rts,
  1310. .get_modemstatus = _get_modemstatus,
  1311. .set_wait_mask = _set_wait_mask,
  1312. .get_wait_mask = _get_wait_mask,
  1313. .wait_on_mask = _wait_on_mask,
  1314. .set_queue_size = _set_queue_size,
  1315. .purge = _purge,
  1316. .get_commstatus = _get_commstatus,
  1317. .set_break_on = _set_break_on,
  1318. .set_break_off = _set_break_off,
  1319. .set_xoff = _set_xoff,
  1320. .set_xon = _set_xon,
  1321. .get_dtrrts = _get_dtrrts,
  1322. .config_size = _config_size,
  1323. .immediate_char = _immediate_char,
  1324. .reset_device = _reset_device,
  1325. };
  1326. SERIAL_DRIVER* SerialSys_s()
  1327. {
  1328. return &_SerialSys;
  1329. }
  1330. #endif /* __linux__ */