usart.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. /*
  2. * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. */
  32. /*!
  33. * \file dev/usart.c
  34. * \brief Hardware independent part of the U(S)ART driver.
  35. *
  36. * \verbatim
  37. * $Id: usart.c 5526 2014-01-07 18:17:36Z u_bonnes $
  38. * \endverbatim
  39. */
  40. #include <cfg/crt.h>
  41. #include <compiler.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <memdebug.h>
  45. #include <sys/atom.h>
  46. #include <sys/heap.h>
  47. #include <sys/event.h>
  48. #include <sys/timer.h>
  49. #include <sys/nutdebug.h>
  50. #include <sys/select.h>
  51. #include <dev/irqreg.h>
  52. #include <dev/usart.h>
  53. #include <fcntl.h>
  54. /*
  55. * Not nice because stdio already defined them. But in order to save memory,
  56. * we do the whole buffering and including stdio here would be more weird.
  57. */
  58. #ifndef _IOFBF
  59. #define _IOFBF 0x00
  60. #define _IOLBF 0x01
  61. #define _IONBF 0x02
  62. #endif
  63. /*!
  64. * \addtogroup xgUsart
  65. */
  66. /*@{*/
  67. /*!
  68. * \brief Initialize the USART device.
  69. * \internal
  70. *
  71. * This function is called by NutRegisterDevice(), using the
  72. * _NUTDEVICE::dev_init entry. It will call the low level
  73. * driver's _USARTDCB::dcb_init routine to initialize the hardware.
  74. *
  75. * \param dev Identifies the device to initialize.
  76. *
  77. * \return 0 on success, -1 otherwise.
  78. *
  79. * \todo Read initial settings from EEPROM.
  80. */
  81. int UsartInit(NUTDEVICE * dev)
  82. {
  83. int rc;
  84. USARTDCB *dcb = dev->dev_dcb;
  85. /* Initialize the low level hardware driver. */
  86. rc = (*dcb->dcb_init) ();
  87. if (rc == 0) {
  88. /* Ignore errors on initial configuration. */
  89. (*dcb->dcb_set_speed) (USART_INITSPEED);
  90. }
  91. return rc;
  92. }
  93. /*!
  94. * \brief Reset a USART ring buffer.
  95. *
  96. * \param rbf Pointer to the ring buffer structure.
  97. * \param size Buffer size.
  98. * \param lowm Low watermark.
  99. * \param hiwm High watermark.
  100. *
  101. * \return 0 on success, -1 if changing the buffer size fails.
  102. */
  103. static int UsartResetBuffer(RINGBUF * rbf, size_t size, size_t lowm, size_t hiwm)
  104. {
  105. uint8_t *xbp = rbf->rbf_start;
  106. size_t xsz = rbf->rbf_siz;
  107. /* Disable further buffer usage. */
  108. NutEnterCritical();
  109. rbf->rbf_siz = 0;
  110. NutExitCritical();
  111. /* Resize the buffer, if required. */
  112. if (xsz != size) {
  113. if (xsz) {
  114. free(xbp);
  115. }
  116. if (size) {
  117. xbp = malloc(size);
  118. if (xbp == NULL) {
  119. return -1;
  120. }
  121. }
  122. }
  123. /* Update ring buffer status. */
  124. if (size) {
  125. rbf->rbf_start = xbp;
  126. rbf->rbf_head = xbp;
  127. rbf->rbf_tail = xbp;
  128. rbf->rbf_last = xbp + size;
  129. rbf->rbf_lwm = lowm;
  130. rbf->rbf_hwm = hiwm;
  131. rbf->rbf_cnt = 0;
  132. /* Re-enable buffer usage. */
  133. NutEnterCritical();
  134. rbf->rbf_siz = size;
  135. NutExitCritical();
  136. }
  137. return 0;
  138. }
  139. /*!
  140. * \brief Read from device.
  141. * \internal
  142. *
  143. * This function is called by the low level input routines of the
  144. * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_read
  145. * entry.
  146. *
  147. * The function may block the calling thread until at least one
  148. * character has been received or a timeout occurs.
  149. *
  150. * It is recommended to set a proper read timeout with software handshake.
  151. * In this case a timeout may occur, if the communication peer lost our
  152. * last XON character. The application may then use ioctl() to disable the
  153. * receiver and do the read again. This will send out another XON.
  154. *
  155. * \param fp Pointer to a \ref _NUTFILE structure, obtained by a
  156. * previous call to UsartOpen().
  157. * \param buffer Pointer to the buffer that receives the data. If zero,
  158. * then all characters in the input buffer will be
  159. * removed.
  160. * \param size Maximum number of bytes to read.
  161. *
  162. * \return The number of bytes read, which may be less than the number
  163. * of bytes specified. A return value of -1 indicates an error,
  164. * while zero is returned in case of a timeout.
  165. */
  166. int UsartRead(NUTFILE * fp, void *buffer, int size)
  167. {
  168. size_t rc;
  169. size_t avail;
  170. size_t taken = 0;
  171. uint8_t ch;
  172. uint8_t *cp = buffer;
  173. NUTDEVICE *dev;
  174. USARTDCB *dcb;
  175. RINGBUF *rbf;
  176. NUTASSERT(fp != NULL && fp != NUTFILE_EOF);
  177. dev = fp->nf_dev;
  178. dcb = dev->dev_dcb;
  179. rbf = &dcb->dcb_rx_rbf;
  180. if (dcb->dcb_modeflags & USART_MF_BLOCKREAD) {
  181. rbf->rbf_blockptr = buffer;
  182. rbf->rbf_blockcnt = size;
  183. (*dcb->dcb_rx_start) ();
  184. return size;
  185. }
  186. /*
  187. * No buffer allocated, this device is read only.
  188. */
  189. if (rbf->rbf_siz == 0) {
  190. return -1;
  191. }
  192. /*
  193. * Call without data pointer discards receive buffer.
  194. */
  195. if (buffer == NULL) {
  196. UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
  197. (*dcb->dcb_rx_start) ();
  198. return 0;
  199. }
  200. /*
  201. * Wait until at least one character is buffered or until a read
  202. * timeout occured.
  203. */
  204. for (;;) {
  205. /* Atomic access to the ring buffer counter. */
  206. NutEnterCritical();
  207. avail = rbf->rbf_cnt;
  208. NutExitCritical();
  209. if (avail) {
  210. break;
  211. }
  212. /*
  213. * This will enable RTS hardware handshake or re-enable the
  214. * remote transmitter by sending a XON character.
  215. */
  216. (*dcb->dcb_rx_start) ();
  217. if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
  218. return 0;
  219. }
  220. /* Device closed by another thread. */
  221. if (rbf->rbf_siz == 0) {
  222. return -1;
  223. }
  224. }
  225. /*
  226. * Get cooked characters from receive buffer.
  227. */
  228. if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
  229. for (rc = 0; rc < (size_t) size;) {
  230. if (taken >= avail) {
  231. break;
  232. }
  233. ch = *rbf->rbf_tail++;
  234. if (rbf->rbf_tail == rbf->rbf_last) {
  235. rbf->rbf_tail = rbf->rbf_start;
  236. }
  237. taken++;
  238. if (ch == '\r' || ch == '\n') {
  239. if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
  240. dcb->dcb_last_eol = ch;
  241. *cp++ = '\n';
  242. rc++;
  243. }
  244. } else {
  245. dcb->dcb_last_eol = 0;
  246. *cp++ = ch;
  247. rc++;
  248. }
  249. }
  250. }
  251. /*
  252. * Get raw characters from receive buffer.
  253. */
  254. else {
  255. rc = size;
  256. if (rc > avail) {
  257. rc = avail;
  258. }
  259. for (taken = 0; taken < rc; taken++) {
  260. *cp++ = *rbf->rbf_tail++;
  261. if (rbf->rbf_tail == rbf->rbf_last) {
  262. rbf->rbf_tail = rbf->rbf_start;
  263. }
  264. }
  265. }
  266. if (taken) {
  267. NutEnterCritical();
  268. rbf->rbf_cnt -= taken;
  269. NutExitCritical();
  270. if (rbf->rbf_cnt < rbf->rbf_lwm) {
  271. (*dcb->dcb_rx_start) ();
  272. }
  273. }
  274. return (int) rc;
  275. }
  276. /*!
  277. * \brief Flush output buffer.
  278. *
  279. * The current thread will be blocked until all characters up to a
  280. * specified count have been written or until a timeout occurred.
  281. *
  282. * \param dcb Pointer to the device's control block structure.
  283. * \param added Number of bytes to add to the ring buffer counter. The
  284. * characters must have been added without updating the
  285. * counter. Because access to the counter has to be atomic,
  286. * this parameter simplifies the calling routine a bit.
  287. * \param left The maximum number of bytes left in the buffer before
  288. * this function returns.
  289. *
  290. * \return Number of bytes left in the output buffer, which is greater
  291. * than the specified value in case of a timeout.
  292. */
  293. static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
  294. {
  295. size_t rc;
  296. RINGBUF *rbf = &dcb->dcb_tx_rbf;
  297. /*
  298. * Add the new characters to the buffer count.
  299. */
  300. NutEnterCritical();
  301. rbf->rbf_cnt += added;
  302. rc = rbf->rbf_cnt;
  303. NutExitCritical();
  304. while (rc > left) {
  305. /* Start transmitter and wait for the next event. */
  306. (*dcb->dcb_tx_start) ();
  307. if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
  308. break;
  309. }
  310. /* Refresh the count. */
  311. NutEnterCritical();
  312. rc = rbf->rbf_cnt;
  313. NutExitCritical();
  314. };
  315. return rc;
  316. }
  317. /*!
  318. * \brief Write to device.
  319. *
  320. * \param dev Pointer to a previously registered NUTDEVICE structure.
  321. * \param buffer Pointer to the data to write.
  322. * \param len Number of data bytes to write.
  323. * \param pflg If this flag is set, then the buffer is located in
  324. * program space. Used by Harvard architectures only.
  325. *
  326. * \return The number of bytes written. In case of a write timeout, this
  327. * may be less than the specified length.
  328. */
  329. static int UsartPut(NUTDEVICE * dev, const void *buffer, int len, int pflg)
  330. {
  331. int rc;
  332. const uint8_t *cp;
  333. uint8_t lbmode;
  334. ureg_t cooked;
  335. uint8_t ch;
  336. size_t cnt;
  337. size_t added;
  338. USARTDCB *dcb = dev->dev_dcb;
  339. RINGBUF *rbf = &dcb->dcb_tx_rbf;
  340. if (dcb->dcb_modeflags & USART_MF_BLOCKWRITE) {
  341. rbf->rbf_blockptr = (void*)buffer;
  342. rbf->rbf_blockcnt = len;
  343. (*dcb->dcb_tx_start) ();
  344. rc = NutEventWaitNext( &rbf->rbf_que, dcb->dcb_wtimeout);
  345. if (rc == 0) {
  346. rc = len;
  347. }
  348. return rc;
  349. }
  350. /*
  351. * No output ring buffer allocated, this device is read only.
  352. */
  353. if (rbf->rbf_siz == 0) {
  354. return -1;
  355. }
  356. /*
  357. * Call without data pointer flushes the buffer. In this case a return
  358. * value not equal zero indicates write timeout.
  359. */
  360. if (buffer == NULL) {
  361. return UsartFlushOutput(dcb, 0, 0);
  362. }
  363. if (dcb->dcb_modeflags & USART_MF_LINEBUFFER) {
  364. lbmode = 1;
  365. } else {
  366. lbmode = 0;
  367. }
  368. if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
  369. cooked = 1;
  370. } else {
  371. cooked = 0;
  372. }
  373. /*
  374. * Get the number of buffered bytes. The transmit interrupt will modify
  375. * this value, so make the query atomic.
  376. */
  377. NutEnterCritical();
  378. cnt = rbf->rbf_cnt;
  379. NutExitCritical();
  380. /*
  381. * Move bytes to the transmit buffer.
  382. */
  383. cp = buffer;
  384. added = 0;
  385. for (rc = 0; rc < len;) {
  386. /*
  387. * If we reached the high watermark, then kick the hardware driver
  388. * to start transmission and wait until the low watermark is reached.
  389. */
  390. if (cnt + added >= rbf->rbf_hwm) {
  391. cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
  392. added = 0;
  393. /* If still above the mark, then a timeout occured. */
  394. if(cnt > rbf->rbf_lwm) {
  395. break;
  396. }
  397. }
  398. /*
  399. * Get the next data byte. If the pflg parameter is set, then data
  400. * is located in program space.
  401. */
  402. ch = pflg ? PRG_RDB(cp) : *cp;
  403. /*
  404. * In cooked mode we prepend a carriage return to any linefeed
  405. * character.
  406. */
  407. if (cooked == 1 && ch == '\n') {
  408. cooked = 2;
  409. ch = '\r';
  410. if (lbmode == 1) {
  411. lbmode = 2;
  412. }
  413. } else {
  414. if (cooked == 2) {
  415. cooked = 1;
  416. }
  417. cp++;
  418. rc++;
  419. }
  420. *rbf->rbf_head++ = ch;
  421. if (rbf->rbf_head == rbf->rbf_last) {
  422. rbf->rbf_head = rbf->rbf_start;
  423. }
  424. added++;
  425. }
  426. if (added) {
  427. NutEnterCritical();
  428. rbf->rbf_cnt += added;
  429. NutExitCritical();
  430. (*dcb->dcb_tx_start) ();
  431. }
  432. return rc;
  433. }
  434. /*!
  435. * \brief Write a device or file.
  436. * \internal
  437. *
  438. * This function is called by the low level output routines of the
  439. * \ref xrCrtLowio "C runtime library", using the
  440. * \ref _NUTDEVICE::dev_write entry.
  441. *
  442. * The function may block the calling thread.
  443. *
  444. * \param fp Pointer to a _NUTFILE structure, obtained by a previous
  445. * call to UsartOpen().
  446. * \param buffer Pointer to the data to be written. If zero, then the
  447. * output buffer will be flushed.
  448. * \param len Number of bytes to write.
  449. *
  450. * \return The number of bytes written, which may be less than the number
  451. * of bytes specified if a timeout occurred. A return value of -1
  452. * indicates an error.
  453. *
  454. * \note Using a NULL pointer to flush the output buffer is a Nut/OS
  455. * specific extension and will most probably not work on other
  456. * systems.
  457. */
  458. int UsartWrite(NUTFILE * fp, const void *buffer, int len)
  459. {
  460. NUTASSERT(fp != NULL && fp != NUTFILE_EOF);
  461. return UsartPut(fp->nf_dev, buffer, len, 0);
  462. }
  463. #ifdef __HARVARD_ARCH__
  464. /*!
  465. * \brief Write a device or file.
  466. * \internal
  467. *
  468. * Similar to UsartWrite() except that the data is located in program
  469. * memory.
  470. *
  471. * This function is called by the low level output routines of the
  472. * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_write_P
  473. * entry. Used by Harvard architectures only.
  474. *
  475. * The function may block the calling thread.
  476. *
  477. * \param fp Pointer to a NUTFILE structure, obtained by a previous
  478. * call to UsartOpen().
  479. * \param buffer Pointer to the data in program space to be written.
  480. * \param len Number of bytes to write.
  481. *
  482. * \return The number of bytes written, which may be less than the number
  483. * of bytes specified if a timeout occurred. A return value of -1
  484. * indicates an error.
  485. */
  486. int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
  487. {
  488. NUTASSERT(fp != NULL && fp != NUTFILE_EOF);
  489. return UsartPut(fp->nf_dev, (const char *) buffer, len, 1);
  490. }
  491. #endif
  492. /*!
  493. * \brief Close a USART device.
  494. * \internal
  495. *
  496. * This function is called by the low level _close() routine of the C
  497. * runtime library, using the _NUTDEVICE::dev_close entry.
  498. *
  499. * \param fp Pointer to a _NUTFILE structure, obtained by a previous call
  500. * to UsartOpen().
  501. *
  502. * \return 0 on success or -1 otherwise.
  503. *
  504. * \todo We may support shared open and use dev_irq as an open counter.
  505. */
  506. int UsartClose(NUTFILE * fp)
  507. {
  508. int rc = 0;
  509. NUTDEVICE *dev;
  510. USARTDCB *dcb;
  511. NUTASSERT(fp != NULL && fp != NUTFILE_EOF);
  512. dev = fp->nf_dev;
  513. dcb = (USARTDCB *) dev->dev_dcb;
  514. /* Flush the complete output buffer. If this fails, let the caller
  515. know, that not all bytes had been transmitted. */
  516. if (UsartFlushOutput(dcb, 0, 0)) {
  517. rc = -1;
  518. }
  519. (*dcb->dcb_set_status) (UART_RTSDISABLED);
  520. free(fp);
  521. UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
  522. UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
  523. /* Wake-up all threads waiting for incoming data. */
  524. NutEventBroadcast(&dcb->dcb_rx_rbf.rbf_que);
  525. NutSelectWakeup(dcb->dcb_rx_rbf.wq_list, WQ_FLAG_READ);
  526. NutSelectWakeup(dcb->dcb_tx_rbf.wq_list, WQ_FLAG_WRITE);
  527. return rc;
  528. }
  529. /*!
  530. * \brief Open a USART device.
  531. * \internal
  532. *
  533. * This function is called by the low level _open() routine of the C
  534. * runtime library, using the _NUTDEVICE::dev_open entry.
  535. *
  536. * \param dev Pointer to the NUTDEVICE structure.
  537. * \param name Ignored, should point to an empty string.
  538. * \param mode Operation mode. Any of the following values may be or-ed:
  539. * - \ref _O_BINARY
  540. * - \ref _O_RDONLY
  541. * - \ref _O_WRONLY
  542. * \param acc Ignored, should be zero.
  543. *
  544. * \return Pointer to a NUTFILE structure if successful or NUTFILE_EOF
  545. * otherwise.
  546. *
  547. * \todo We may support shared open and use dev_irq as an open counter.
  548. */
  549. NUTFILE *UsartOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  550. {
  551. USARTDCB *dcb = dev->dev_dcb;
  552. NUTFILE *fp;
  553. /*
  554. * Create the transmit buffer unless this is used for read only.
  555. */
  556. if ((mode & 0x0003) != _O_RDONLY) {
  557. if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
  558. return NUTFILE_EOF;
  559. }
  560. }
  561. /*
  562. * Create the receive buffer unless this is used for write only.
  563. */
  564. if ((mode & 0x0003) != _O_WRONLY) {
  565. if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
  566. free(dcb->dcb_tx_rbf.rbf_start);
  567. return NUTFILE_EOF;
  568. }
  569. }
  570. /*
  571. * Allocate memory for the file structure.
  572. */
  573. fp = malloc(sizeof(*fp));
  574. if (fp == NULL) {
  575. free(dcb->dcb_tx_rbf.rbf_start);
  576. free(dcb->dcb_rx_rbf.rbf_start);
  577. return NUTFILE_EOF;
  578. }
  579. /* Set proper device modes. */
  580. if ((mode & 0xC000) == _O_BINARY) {
  581. dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
  582. } else {
  583. dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
  584. }
  585. /*
  586. * For now we do the initialization here. Later we may implement
  587. * a file creation routine to get a linked list of all opened
  588. * files in the system.
  589. */
  590. fp->nf_dev = dev;
  591. fp->nf_fcb = NULL;
  592. if ((mode & 0x0003) != _O_WRONLY) {
  593. (*dcb->dcb_rx_start) ();
  594. }
  595. return fp;
  596. }
  597. /*!
  598. * \brief Perform USART control functions.
  599. * \internal
  600. *
  601. * This function is called by the _ioctl() function of the C runtime
  602. * library.
  603. *
  604. * \param dev Identifies the device that receives the device-control
  605. * function.
  606. * \param req Requested control function. May be set to one of the
  607. * following constants:
  608. * - \ref UART_SETSPEED
  609. * - \ref UART_GETSPEED
  610. * - \ref UART_SETDATABITS
  611. * - \ref UART_GETDATABITS
  612. * - \ref UART_SETPARITY
  613. * - \ref UART_GETPARITY
  614. * - \ref UART_SETSTOPBITS
  615. * - \ref UART_GETSTOPBITS
  616. * - \ref UART_SETSTATUS
  617. * - \ref UART_GETSTATUS
  618. * - \ref UART_SETREADTIMEOUT
  619. * - \ref UART_GETREADTIMEOUT
  620. * - \ref UART_SETWRITETIMEOUT
  621. * - \ref UART_GETWRITETIMEOUT
  622. * - \ref UART_SETLOCALECHO
  623. * - \ref UART_GETLOCALECHO
  624. * - \ref UART_SETFLOWCONTROL
  625. * - \ref UART_GETFLOWCONTROL
  626. * - \ref UART_SETCOOKEDMODE
  627. * - \ref UART_GETCOOKEDMODE
  628. * - \ref UART_SETHDPXMODE
  629. * - \ref UART_GETHDPXMODE
  630. * - \ref UART_SETCLOCKMODE
  631. * - \ref UART_GETCLOCKMODE
  632. * - \ref UART_SETTXBUFSIZ
  633. * - \ref UART_GETTXBUFSIZ
  634. * - \ref UART_SETRXBUFSIZ
  635. * - \ref UART_GETRXBUFSIZ
  636. * - \ref UART_SETTXBUFLWMARK
  637. * - \ref UART_GETTXBUFLWMARK
  638. * - \ref UART_SETTXBUFHWMARK
  639. * - \ref UART_GETTXBUFHWMARK
  640. * - \ref UART_SETRXBUFLWMARK
  641. * - \ref UART_GETRXBUFLWMARK
  642. * - \ref UART_SETRXBUFHWMARK
  643. * - \ref UART_GETRXBUFHWMARK
  644. *
  645. * \param conf Points to a buffer that contains any data required for
  646. * the given control function or receives data from that
  647. * function.
  648. * \return 0 on success, -1 otherwise.
  649. *
  650. * \note Not all control functions may be supported on all platforms.
  651. * In any case applications should check the returned result.
  652. *
  653. * \warning Timeout values are given in milliseconds and are limited to
  654. * the granularity of the system timer. To disable timeout,
  655. * set the parameter to NUT_WAIT_INFINITE.
  656. */
  657. int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
  658. {
  659. int rc = 0;
  660. USARTDCB *dcb;
  661. RINGBUF *rbf;
  662. uint32_t *lvp = (uint32_t *) conf;
  663. uint32_t lv = *lvp;
  664. uint8_t bv = (uint8_t) lv;
  665. dcb = dev->dev_dcb;
  666. switch (req) {
  667. case UART_SETSPEED:
  668. rc = (*dcb->dcb_set_speed) (lv);
  669. break;
  670. case UART_GETSPEED:
  671. *lvp = (*dcb->dcb_get_speed) ();
  672. break;
  673. case UART_SETDATABITS:
  674. rc = (*dcb->dcb_set_data_bits) (bv);
  675. break;
  676. case UART_GETDATABITS:
  677. *lvp = (*dcb->dcb_get_data_bits) ();
  678. break;
  679. case UART_SETPARITY:
  680. rc = (*dcb->dcb_set_parity) (bv);
  681. break;
  682. case UART_GETPARITY:
  683. *lvp = (*dcb->dcb_get_parity) ();
  684. break;
  685. case UART_SETSTOPBITS:
  686. rc = (*dcb->dcb_set_stop_bits) (bv);
  687. break;
  688. case UART_GETSTOPBITS:
  689. *lvp = (*dcb->dcb_get_stop_bits) ();
  690. break;
  691. case UART_SETSTATUS:
  692. /*
  693. * We are not changing the buffer size. Thus, we can safely ignore the
  694. * result of UsartResetBuffer(). This way we found a work around for
  695. * the AVRGCC 4.1.1 bug, which appeared here previously.
  696. */
  697. if (lv & UART_RXBUFFEREMPTY) {
  698. rbf = &dcb->dcb_rx_rbf;
  699. UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
  700. (*dcb->dcb_rx_start) ();
  701. }
  702. if (lv & UART_TXBUFFEREMPTY) {
  703. rbf = &dcb->dcb_tx_rbf;
  704. UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
  705. }
  706. rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
  707. break;
  708. case UART_GETSTATUS:
  709. *lvp = (*dcb->dcb_get_status) ();
  710. /*
  711. * Determine buffer status.
  712. */
  713. if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
  714. *lvp |= UART_RXBUFFEREMPTY;
  715. }
  716. if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
  717. *lvp |= UART_TXBUFFEREMPTY;
  718. }
  719. break;
  720. case UART_SETREADTIMEOUT:
  721. dcb->dcb_rtimeout = lv;
  722. break;
  723. case UART_GETREADTIMEOUT:
  724. *lvp = dcb->dcb_rtimeout;
  725. break;
  726. case UART_SETWRITETIMEOUT:
  727. dcb->dcb_wtimeout = lv;
  728. break;
  729. case UART_GETWRITETIMEOUT:
  730. *lvp = dcb->dcb_wtimeout;
  731. break;
  732. case UART_SETLOCALECHO:
  733. lv = dcb->dcb_modeflags;
  734. if (bv) {
  735. lv |= USART_MF_LOCALECHO;
  736. } else {
  737. lv &= ~USART_MF_LOCALECHO;
  738. }
  739. rc = (dcb->dcb_set_flow_control) (lv);
  740. if (rc == 0) {
  741. dcb->dcb_modeflags = lv;
  742. }
  743. break;
  744. case UART_GETLOCALECHO:
  745. if (dcb->dcb_modeflags & USART_MF_LOCALECHO) {
  746. *lvp = 1;
  747. } else {
  748. *lvp = 0;
  749. }
  750. break;
  751. case UART_SETFLOWCONTROL:
  752. lv = dcb->dcb_modeflags;
  753. rc = (dcb->dcb_set_flow_control) (lv);
  754. if (rc == 0) {
  755. dcb->dcb_modeflags = lv;
  756. }
  757. break;
  758. case UART_GETFLOWCONTROL:
  759. *lvp = (*dcb->dcb_get_flow_control) ();
  760. break;
  761. case UART_SETBLOCKREAD:
  762. lv = dcb->dcb_modeflags;
  763. if (bv) {
  764. lv |= USART_MF_BLOCKREAD;
  765. } else {
  766. lv &= ~USART_MF_BLOCKREAD;
  767. }
  768. rc = (dcb->dcb_set_flow_control) (lv);
  769. if (rc == 0) {
  770. dcb->dcb_modeflags = lv;
  771. }
  772. break;
  773. case UART_GETBLOCKREAD:
  774. *lvp = (*dcb->dcb_get_flow_control) ();
  775. break;
  776. case UART_SETBLOCKWRITE:
  777. lv = dcb->dcb_modeflags;
  778. if (bv) {
  779. lv |= USART_MF_BLOCKWRITE;
  780. } else {
  781. lv &= ~USART_MF_BLOCKWRITE;
  782. }
  783. rc = (dcb->dcb_set_flow_control) (lv);
  784. if (rc == 0) {
  785. dcb->dcb_modeflags = lv;
  786. }
  787. break;
  788. case UART_GETBLOCKWRITE:
  789. *lvp = (*dcb->dcb_get_flow_control) ();
  790. break;
  791. case UART_SETCOOKEDMODE:
  792. if (bv) {
  793. dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
  794. } else {
  795. dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
  796. }
  797. break;
  798. case UART_GETCOOKEDMODE:
  799. if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
  800. *lvp = 1;
  801. } else {
  802. *lvp = 0;
  803. }
  804. break;
  805. case UART_SETHDPXMODE:
  806. lv = dcb->dcb_modeflags;
  807. if (bv) {
  808. lv |= USART_MF_HALFDUPLEX;
  809. } else {
  810. lv &= ~USART_MF_HALFDUPLEX;
  811. }
  812. rc = (dcb->dcb_set_flow_control) (lv);
  813. if (rc == 0) {
  814. dcb->dcb_modeflags = lv;
  815. }
  816. break;
  817. case UART_GETHDPXMODE:
  818. if (dcb->dcb_modeflags & USART_MF_HALFDUPLEX) {
  819. *lvp = 1;
  820. } else {
  821. *lvp = 0;
  822. }
  823. break;
  824. case UART_SETOWIMODE:
  825. lv = dcb->dcb_modeflags;
  826. if (bv) {
  827. lv |= USART_MF_OWIHALFDUPLEX;
  828. } else {
  829. lv &= ~USART_MF_OWIHALFDUPLEX;
  830. }
  831. rc = (dcb->dcb_set_flow_control) (lv);
  832. if (rc == 0) {
  833. dcb->dcb_modeflags = lv;
  834. }
  835. break;
  836. case UART_GETOWIMODE:
  837. if (dcb->dcb_modeflags & USART_MF_OWIHALFDUPLEX) {
  838. *lvp = 1;
  839. } else {
  840. *lvp = 0;
  841. }
  842. break;
  843. case UART_SETCLOCKMODE:
  844. rc = (*dcb->dcb_set_clock_mode) (lv);
  845. break;
  846. case UART_GETCLOCKMODE:
  847. *lvp = (*dcb->dcb_get_clock_mode) ();
  848. break;
  849. case UART_SETTXBUFSIZ:
  850. rbf = &dcb->dcb_tx_rbf;
  851. rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
  852. if (rc == 0) {
  853. (*dcb->dcb_rx_start) ();
  854. }
  855. break;
  856. case UART_GETTXBUFSIZ:
  857. *lvp = dcb->dcb_tx_rbf.rbf_siz;
  858. break;
  859. case UART_SETRXBUFSIZ:
  860. rbf = &dcb->dcb_rx_rbf;
  861. rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
  862. break;
  863. case UART_GETRXBUFSIZ:
  864. *lvp = dcb->dcb_rx_rbf.rbf_siz;
  865. break;
  866. case UART_SETTXBUFLWMARK:
  867. NutEnterCritical();
  868. dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
  869. NutExitCritical();
  870. break;
  871. case UART_GETTXBUFLWMARK:
  872. *lvp = dcb->dcb_tx_rbf.rbf_lwm;
  873. break;
  874. case UART_SETTXBUFHWMARK:
  875. NutEnterCritical();
  876. dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
  877. NutExitCritical();
  878. break;
  879. case UART_GETTXBUFHWMARK:
  880. *lvp = dcb->dcb_tx_rbf.rbf_hwm;
  881. break;
  882. case UART_SETRXBUFLWMARK:
  883. NutEnterCritical();
  884. dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
  885. NutExitCritical();
  886. break;
  887. case UART_GETRXBUFLWMARK:
  888. *lvp = dcb->dcb_rx_rbf.rbf_lwm;
  889. break;
  890. case UART_SETRXBUFHWMARK:
  891. NutEnterCritical();
  892. dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
  893. NutExitCritical();
  894. break;
  895. case UART_GETRXBUFHWMARK:
  896. *lvp = dcb->dcb_rx_rbf.rbf_hwm;
  897. break;
  898. default:
  899. rc = -1;
  900. break;
  901. }
  902. return rc;
  903. }
  904. /*!
  905. * \brief Retrieves the number of characters in input buffer.
  906. * \internal
  907. *
  908. * This function allows to query the number of bytes in the input buffer
  909. * by using standard C function for querying the size of an open file.
  910. *
  911. * This function is called by the low level _filelength() routine of
  912. * the C runtime library, using the _NUTDEVICE::dev_size entry.
  913. *
  914. * \note This is a Nut/OS specific extension and will most probably not
  915. * work on other systems.
  916. *
  917. * \param fp Pointer to a \ref _NUTFILE structure, obtained by a
  918. * previous call to UsartOpen().
  919. *
  920. * \return The number of bytes currently stored in input buffer.
  921. */
  922. long UsartSize (NUTFILE *fp)
  923. {
  924. long avail;
  925. NUTDEVICE *dev;
  926. USARTDCB *dcb;
  927. RINGBUF *rbf;
  928. NUTASSERT(fp != NULL && fp != NUTFILE_EOF);
  929. dev = fp->nf_dev;
  930. dcb = dev->dev_dcb;
  931. rbf = &dcb->dcb_rx_rbf;
  932. /* Atomic access to the ring buffer counter. */
  933. NutEnterCritical();
  934. avail = rbf->rbf_cnt;
  935. NutExitCritical();
  936. return avail;
  937. }
  938. #ifndef CRT_DISABLE_SELECT_POLL
  939. /*!
  940. * \brief Callback function called by select routine to check, if read
  941. * or write would block
  942. * \internal
  943. *
  944. * This function is called by select_scan routine of the C runtime library
  945. * as part of the select() implementation. If select if currently waiting
  946. * on a waitqueue, this function will be called to check the current state
  947. * as soon as the select waitqueues got signalled by the driver
  948. *
  949. * \param fp Pointer to a \ref _NUTFILE structure, obtained by a
  950. * previous call to UsartOpen().
  951. * \param flags Flags representing what we are waiting for (read / write / exception)
  952. * \param wq Waitqueue, which should be added to the drivers waitqueue list. The
  953. * thread that called select is waiting on this waitqueue
  954. * \param cmd Internal command, that is passed to NutSelectManageWq
  955. *
  956. * \return Flags representing the current filedescriptor state
  957. */
  958. int UsartSelect (NUTFILE *fp, int flags, HANDLE *wq, select_cmd_t cmd)
  959. {
  960. NUTDEVICE *dev;
  961. USARTDCB *dcb;
  962. RINGBUF *rx_rbf;
  963. RINGBUF *tx_rbf;
  964. int rflags = 0;
  965. dev = fp->nf_dev;
  966. dcb = dev->dev_dcb;
  967. rx_rbf = &dcb->dcb_rx_rbf;
  968. tx_rbf = &dcb->dcb_tx_rbf;
  969. /* Manage the wait queue lists for the select call */
  970. NutSelectManageWq(&rx_rbf->wq_list, wq, flags & WQ_FLAG_READ, cmd);
  971. NutSelectManageWq(&tx_rbf->wq_list, wq, flags & WQ_FLAG_WRITE, cmd);
  972. /* receive / transmit interrupt can change the buffer counts, so these
  973. checks will be done atomic.
  974. */
  975. NutEnterCritical();
  976. if (rx_rbf->rbf_cnt > 0) {
  977. rflags |= WQ_FLAG_READ;
  978. }
  979. if (tx_rbf->rbf_cnt < tx_rbf->rbf_siz) {
  980. rflags |= WQ_FLAG_WRITE;
  981. }
  982. NutExitCritical();
  983. rflags &= flags;
  984. return rflags;
  985. }
  986. #endif
  987. /*@}*/