scih8.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. /*
  2. * Copyright (C) 2004 by Jan Dubiec. 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 JAN DUBIEC 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 JAN DUBIEC
  21. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /*
  30. * $Log$
  31. * Revision 1.2 2005/10/19 09:34:25 hwmaier
  32. * Changed doxygen group to xgUartH8 so it doesn't
  33. * overload arch/avr/dev/usartavr.c's documentation
  34. *
  35. * Revision 1.1 2005/07/26 18:02:40 haraldkipp
  36. * Moved from dev.
  37. *
  38. * Revision 1.4 2005/01/24 21:12:02 freckle
  39. * renamed NutEventPostFromIRQ into NutEventPostFromIrq
  40. *
  41. * Revision 1.3 2005/01/21 16:49:46 freckle
  42. * Seperated calls to NutEventPostAsync between Threads and IRQs
  43. *
  44. * Revision 1.2 2004/03/18 14:06:52 haraldkipp
  45. * Deprecated header file replaced
  46. *
  47. * Revision 1.1 2004/03/16 16:48:27 haraldkipp
  48. * Added Jan Dubiec's H8/300 port.
  49. *
  50. */
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <sys/atom.h>
  54. #include <sys/heap.h>
  55. #include <sys/event.h>
  56. #include <sys/timer.h>
  57. #include <sys/device.h>
  58. #include <dev/irqreg.h>
  59. #include <dev/scih8.h>
  60. #include <fcntl.h>
  61. #include <h83068f.h>
  62. /* #include <sys/osdebug.h> */
  63. /*
  64. * Not nice because stdio already defined them. But in order to save memory,
  65. * we do the whole buffering and including stdio here would be more weird.
  66. */
  67. #ifndef _IOFBF
  68. #define _IOFBF 0x00
  69. #define _IOLBF 0x01
  70. #define _IONBF 0x02
  71. #endif
  72. /*!
  73. * \addtogroup xgUartH8
  74. */
  75. /*@{*/
  76. /* Baud rate defintions for a 18.432Mhz clock source. */
  77. #define BR_150 150UL
  78. #define BR_300 300UL
  79. #define BR_600 600UL
  80. #define BR_1200 1200UL
  81. #define BR_2400 2400UL
  82. #define BR_4800 4800UL
  83. #define BR_9600 9600UL
  84. #define BR_19200 19200UL
  85. #define BR_38400 38400UL
  86. #define BR_57600 57600UL
  87. #define BR_115200 115200UL
  88. #define BR_230400 230400UL
  89. /* SCR bit definitions. */
  90. #define TXI_ENABLE 0x80
  91. #define RXI_ENABLE 0x40
  92. #define TX_ENABLE 0x20
  93. #define RX_ENABLE 0x10
  94. #define MPI_ENABLE 0x08
  95. #define TXEI_ENABLE 0x04
  96. #define RXEI_ENABLE 0x02
  97. #define CK0_ENABLE 0x01
  98. /* SSR bit definitions. */
  99. #define TDRE 0x80
  100. #define RDRF 0x40
  101. #define ORER 0x20
  102. #define FER 0x10
  103. #define PER 0x08
  104. #define TEND 0x04
  105. /* SMR bit definitions. */
  106. #define DATABITS_8 0
  107. #define DATABITS_7 0x40
  108. #define NOPARITY 0
  109. #define EVENPARITY 0x20
  110. #define ODDPARITY 0x30
  111. #define STOP1BIT 0
  112. #define STOP2BITS 0x08
  113. #define NODIVIDE 0
  114. #define DIVIDEBY4 1
  115. #define DIVIDEBY16 2
  116. #define DIVIDEBY64 3
  117. /*
  118. * Returns H8/300H SCI structure pointer based on NUTDEVICE->dev_base
  119. * or NULL if there is no such device.
  120. */
  121. #define GET_SCI(p) ( ((p) == 0) ? &SCI0 : ( ((p) == 1) ? &SCI1 : \
  122. ( ((p) == 2) ? &SCI2 : NULL ) ) )
  123. /*
  124. * Handle H8/300H SCI transmit complete.
  125. */
  126. static void TxComplete(void *arg)
  127. {
  128. NUTDEVICE *dev = (NUTDEVICE *) arg;
  129. IFSTREAM *ifs = dev->dev_icb;
  130. UARTDCB *dcb;
  131. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  132. if (ifs->if_tx_idx != ifs->if_wr_idx) {
  133. sci->TDR = ifs->if_tx_buf[ifs->if_tx_idx];
  134. sci->SSR.BYTE &= ~TDRE;
  135. ifs->if_tx_idx++;
  136. } else {
  137. /* Disable SCI interrupts or they just keep coming */
  138. sci->SCR.BYTE &= ~TXI_ENABLE;
  139. ifs->if_tx_act = 0;
  140. dcb = dev->dev_dcb;
  141. NutEventPostFromIrq(&dcb->dcb_tx_rdy);
  142. }
  143. }
  144. /*
  145. * Handle H8/300H SCI receive complete.
  146. *
  147. * Note, that this function modifies the receive index in
  148. * interrupt context. This requires, that any non atomic
  149. * access of this index requires interrupts being disabled.
  150. * Thanks to Mike Cornelius, who pointed this out.
  151. */
  152. static void RxComplete(void *arg)
  153. {
  154. NUTDEVICE *dev = (NUTDEVICE *) arg;
  155. IFSTREAM *ifs = dev->dev_icb;
  156. UARTDCB *dcb;
  157. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  158. ifs->if_rx_buf[ifs->if_rx_idx] = sci->RDR;
  159. sci->SSR.BYTE &= ~RDRF;
  160. if (ifs->if_rd_idx == ifs->if_rx_idx++) {
  161. dcb = dev->dev_dcb;
  162. NutEventPostFromIrq(&dcb->dcb_rx_rdy);
  163. }
  164. }
  165. /*!
  166. * \brief Wait for input.
  167. *
  168. * This function checks the input buffer for any data. If
  169. * the buffer is empty, the calling \ref xrThread "thread"
  170. * will be blocked until at least one new character is
  171. * received or a timeout occurs.
  172. *
  173. * \param dev Indicates the SCI device.
  174. *
  175. * \return 0 on success, -1 on timeout.
  176. */
  177. int SciH8Input(NUTDEVICE * dev)
  178. {
  179. int rc = 0;
  180. IFSTREAM *ifs = dev->dev_icb;
  181. UARTDCB *dcb;
  182. NutEnterCritical();
  183. if (ifs->if_rd_idx == ifs->if_rx_idx) {
  184. dcb = dev->dev_dcb;
  185. /*
  186. * Changing if into a while loop fixes a serious bug:
  187. * Previous receiver events without any waiting thread
  188. * set the event handle to the signaled state. So the
  189. * wait returns immediately. Unfortunately the calling
  190. * routines rely on a filled buffer when we return 0.
  191. * Thanks to Mike Cornelius, who found this bug.
  192. */
  193. do {
  194. rc = NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout);
  195. } while (rc == 0 && ifs->if_rd_idx == ifs->if_rx_idx);
  196. }
  197. NutExitCritical();
  198. return rc;
  199. }
  200. /*!
  201. * \brief Initiate output.
  202. *
  203. * This function checks the output buffer for any data. If
  204. * the buffer contains at least one character, the transmitter
  205. * is started, if not already running. The function returns
  206. * immediately, without waiting for the character being
  207. * completely transmitted. Any remaining characters in the
  208. * output buffer are transmitted in the background.
  209. *
  210. * \param dev Indicates the SCI device.
  211. *
  212. * \return 0 on success, -1 otherwise.
  213. */
  214. int SciH8Output(NUTDEVICE * dev)
  215. {
  216. IFSTREAM *ifs = dev->dev_icb;
  217. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  218. NutEnterCritical();
  219. if (ifs->if_tx_act == 0 && ifs->if_tx_idx != ifs->if_wr_idx) {
  220. ifs->if_tx_act = 1;
  221. sci->TDR = ifs->if_tx_buf[ifs->if_tx_idx];
  222. sci->SCR.BYTE |= TXI_ENABLE;
  223. sci->SSR.BYTE &= ~TDRE;
  224. ifs->if_tx_idx++;
  225. }
  226. NutExitCritical();
  227. return 0;
  228. }
  229. /*!
  230. * \brief Wait for output buffer empty.
  231. *
  232. * If the output buffer contains any data, the calling
  233. * thread is suspended until all data has been transmitted.
  234. *
  235. * \param dev Indicates the SCI device.
  236. *
  237. * \return 0 on success, -1 otherwise.
  238. */
  239. int SciH8Flush(NUTDEVICE * dev)
  240. {
  241. IFSTREAM *ifs = dev->dev_icb;
  242. UARTDCB *dcb = dev->dev_dcb;
  243. /*
  244. * Start any pending output.
  245. */
  246. if (SciH8Output(dev))
  247. return -1;
  248. /*
  249. * Wait until output buffer empty.
  250. */
  251. NutEnterCritical();
  252. while (ifs->if_tx_idx != ifs->if_wr_idx)
  253. NutEventWait(&dcb->dcb_tx_rdy, 100);
  254. NutExitCritical();
  255. return 0;
  256. }
  257. /*
  258. *
  259. * \param dev Indicates the SCI device.
  260. *
  261. * \return 0 on success, -1 otherwise.
  262. */
  263. static int SciH8GetStatus(NUTDEVICE * dev, u_long * status)
  264. {
  265. IFSTREAM *ifs = dev->dev_icb;
  266. u_char us;
  267. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  268. *status = 0;
  269. us = sci->SSR.BYTE;
  270. if (us & FER)
  271. *status |= UART_FRAMINGERROR;
  272. if (us & ORER)
  273. *status |= UART_OVERRUNERROR;
  274. if (ifs->if_tx_idx == ifs->if_wr_idx)
  275. *status |= UART_TXBUFFEREMPTY;
  276. if (ifs->if_rd_idx == ifs->if_rx_idx)
  277. *status |= UART_RXBUFFEREMPTY;
  278. return 0;
  279. }
  280. /*
  281. * Carefully enable SCI functions.
  282. */
  283. static void SciH8Enable(u_short base)
  284. {
  285. volatile struct st_sci *sci = GET_SCI(base);
  286. NutEnterCritical();
  287. //sci->SCR.BYTE |= (TXI_ENABLE | /*RXI_ENABLE |*/ RX_ENABLE | TX_ENABLE);
  288. sci->SCR.BYTE |= (TXI_ENABLE | RXI_ENABLE | RX_ENABLE | TX_ENABLE);
  289. NutExitCritical();
  290. }
  291. /*
  292. * Carefully disable SCI functions.
  293. */
  294. static void SciH8Disable(u_short base)
  295. {
  296. volatile struct st_sci *sci = GET_SCI(base);
  297. /*
  298. * Disable SCI interrupts.
  299. */
  300. NutEnterCritical();
  301. sci->SCR.BYTE &= ~(TXI_ENABLE | RXI_ENABLE);
  302. NutExitCritical();
  303. /*
  304. * Allow incoming or outgoing character to finish.
  305. */
  306. NutDelay(10);
  307. /*
  308. * Now disable SCI functions.
  309. */
  310. sci->SCR.BYTE &= ~(RX_ENABLE | TX_ENABLE);
  311. }
  312. /*!
  313. * \brief Perform on-chip UART control functions.
  314. *
  315. * \param dev Identifies the device that receives the device-control
  316. * function.
  317. * \param req Requested control function. May be set to one of the
  318. * following constants:
  319. * - UART_SETSPEED, conf points to an u_long value containing the baudrate.
  320. * - UART_GETSPEED, conf points to an u_long value receiving the current baudrate.
  321. * - UART_SETDATABITS, conf points to an u_long value containing the number of data bits, 5, 6, 7 or 8.
  322. * - UART_GETDATABITS, conf points to an u_long value receiving the number of data bits, 5, 6, 7 or 8.
  323. * - UART_SETPARITY, conf points to an u_long value containing the parity, 0 (no), 1 (odd) or 2 (even).
  324. * - UART_GETPARITY, conf points to an u_long value receiving the parity, 0 (no), 1 (odd) or 2 (even).
  325. * - UART_SETSTOPBITS, conf points to an u_long value containing the number of stop bits 1 or 2.
  326. * - UART_GETSTOPBITS, conf points to an u_long value receiving the number of stop bits 1 or 2.
  327. * - UART_SETSTATUS
  328. * - UART_GETSTATUS
  329. * - UART_SETREADTIMEOUT, conf points to an u_long value containing the read timeout.
  330. * - UART_GETREADTIMEOUT, conf points to an u_long value receiving the read timeout.
  331. * - UART_SETWRITETIMEOUT, conf points to an u_long value containing the write timeout.
  332. * - UART_GETWRITETIMEOUT, conf points to an u_long value receiving the write timeout.
  333. * - UART_SETLOCALECHO, conf points to an u_long value containing 0 (off) or 1 (on).
  334. * - UART_GETLOCALECHO, conf points to an u_long value receiving 0 (off) or 1 (on).
  335. * - UART_SETFLOWCONTROL, conf points to an u_long value containing combined UART_FCTL_ values.
  336. * - UART_GETFLOWCONTROL, conf points to an u_long value containing receiving UART_FCTL_ values.
  337. * - UART_SETCOOKEDMODE, conf points to an u_long value containing 0 (off) or 1 (on).
  338. * - UART_GETCOOKEDMODE, conf points to an u_long value receiving 0 (off) or 1 (on).
  339. *
  340. * \param conf Points to a buffer that contains any data required for
  341. * the given control function or receives data from that
  342. * function.
  343. * \return 0 on success, -1 otherwise.
  344. *
  345. * \warning Timeout values are given in milliseconds and are limited to
  346. * the granularity of the system timer.
  347. *
  348. * \bug For ATmega103, only 8 data bits, 1 stop bit and no parity are allowed.
  349. *
  350. */
  351. int SciH8IOCtl(NUTDEVICE * dev, int req, void *conf)
  352. {
  353. int rc = 0;
  354. UARTDCB *dcb;
  355. u_long *lvp = (u_long *) conf;
  356. u_long lv = *lvp;
  357. u_char bv = (u_char) lv;
  358. u_char devnum;
  359. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  360. if (dev == 0)
  361. dev = &devSci0;
  362. devnum = dev->dev_base;
  363. dcb = dev->dev_dcb;
  364. switch (req) {
  365. case UART_SETSPEED:
  366. SciH8Disable(devnum);
  367. u_char cks = 0;
  368. u_long brr = ((NutGetCpuClock() / (64UL / 2UL)) / *lvp) - 1;
  369. if (brr > 0xff) {
  370. cks = 1;
  371. brr = ((NutGetCpuClock() / (64UL * 2UL)) / *lvp) - 1;
  372. if (brr > 0xff) {
  373. cks = 2;
  374. brr = ((NutGetCpuClock() / (64UL * 8UL)) / *lvp) - 1;
  375. if (brr > 0xff) {
  376. cks = 3;
  377. brr = ((NutGetCpuClock() / (64UL * 32UL)) / *lvp) - 1;
  378. }
  379. }
  380. }
  381. sci->SMR.BIT.CKS = cks;
  382. sci->BRR = (u_char) brr;
  383. dcb->dcb_baudSelect = brr;
  384. NutDelay(2); /* wait for a while */
  385. SciH8Enable(devnum);
  386. break;
  387. case UART_GETSPEED:
  388. switch (sci->SMR.BIT.CKS) {
  389. case 0:
  390. *lvp = NutGetCpuClock() / ((64UL / 2UL) * (u_long) (sci->BRR + 1));
  391. break;
  392. case 1:
  393. *lvp = NutGetCpuClock() / ((64UL * 2UL) * (u_long) (sci->BRR + 1));
  394. break;
  395. case 2:
  396. *lvp = NutGetCpuClock() / ((64UL * 8UL) * (u_long) (sci->BRR + 1));
  397. break;
  398. case 3:
  399. *lvp = NutGetCpuClock() / ((64UL * 32UL) * (u_long) (sci->BRR + 1));
  400. break;
  401. }
  402. break;
  403. case UART_SETDATABITS:
  404. SciH8Disable(devnum);
  405. switch (bv) {
  406. case 8: /* 8 data bits */
  407. sci->SMR.BIT.CHR = 0;
  408. break;
  409. case 7: /* 7 data bits */
  410. sci->SMR.BIT.CHR = 1;
  411. break;
  412. default:
  413. rc = -1;
  414. }
  415. SciH8Enable(devnum);
  416. break;
  417. case UART_GETDATABITS:
  418. switch (sci->SMR.BIT.CHR) {
  419. case 0: /* 8 data bits */
  420. *lvp = 8;
  421. break;
  422. case 1: /* 7 data bits */
  423. *lvp = 7;
  424. break;
  425. }
  426. break;
  427. case UART_SETPARITY:
  428. SciH8Disable(devnum);
  429. switch (bv) {
  430. case 'n': /* none */
  431. sci->SMR.BIT.PE = 0;
  432. break;
  433. case 'e': /* even */
  434. sci->SMR.BIT.PE = 1;
  435. sci->SMR.BIT.OE = 0;
  436. break;
  437. case 'o': /* odd */
  438. sci->SMR.BIT.PE = 1;
  439. sci->SMR.BIT.OE = 1;
  440. break;
  441. default:
  442. rc = -1;
  443. }
  444. SciH8Enable(devnum);
  445. break;
  446. case UART_GETPARITY:
  447. if (sci->SMR.BIT.PE == 0) { /* none */
  448. bv = 'n';
  449. } else if (sci->SMR.BIT.OE == 0) { /* even */
  450. bv = 'e';
  451. } else { /* odd */
  452. bv = 'o';
  453. }
  454. break;
  455. case UART_SETSTOPBITS:
  456. SciH8Disable(devnum);
  457. switch (bv) {
  458. case 1: /* 1 stop bit */
  459. sci->SMR.BIT.STOP = 0;
  460. break;
  461. case 2: /* 2 stop bits */
  462. sci->SMR.BIT.STOP = 1;
  463. break;
  464. default:
  465. rc = -1;
  466. }
  467. SciH8Enable(devnum);
  468. break;
  469. case UART_GETSTOPBITS:
  470. switch (sci->SMR.BIT.STOP) {
  471. case 0: /* 1 stop bit */
  472. *lvp = 1;
  473. break;
  474. case 1: /* 2 stop bits */
  475. *lvp = 2;
  476. break;
  477. }
  478. break;
  479. case UART_GETSTATUS:
  480. SciH8GetStatus(dev, lvp);
  481. break;
  482. case UART_SETSTATUS:
  483. rc = -1;
  484. break;
  485. case UART_SETREADTIMEOUT:
  486. dcb->dcb_rtimeout = lv;
  487. break;
  488. case UART_GETREADTIMEOUT:
  489. *lvp = dcb->dcb_rtimeout;
  490. break;
  491. case UART_SETWRITETIMEOUT:
  492. dcb->dcb_wtimeout = lv;
  493. break;
  494. case UART_GETWRITETIMEOUT:
  495. *lvp = dcb->dcb_wtimeout;
  496. break;
  497. case UART_SETLOCALECHO:
  498. if (bv)
  499. dcb->dcb_modeflags |= UART_MF_LOCALECHO;
  500. else
  501. dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
  502. break;
  503. case UART_GETLOCALECHO:
  504. if (dcb->dcb_modeflags & UART_MF_LOCALECHO)
  505. *lvp = 1;
  506. else
  507. *lvp = 0;
  508. break;
  509. case UART_SETFLOWCONTROL:
  510. if (bv)
  511. dcb->dcb_modeflags |= UART_MF_LOCALECHO;
  512. else
  513. dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
  514. break;
  515. case UART_GETFLOWCONTROL:
  516. break;
  517. case UART_SETCOOKEDMODE:
  518. if (bv)
  519. dcb->dcb_modeflags |= UART_MF_COOKEDMODE;
  520. else
  521. dcb->dcb_modeflags &= ~UART_MF_COOKEDMODE;
  522. break;
  523. case UART_GETCOOKEDMODE:
  524. if (dcb->dcb_modeflags & UART_MF_COOKEDMODE)
  525. *lvp = 1;
  526. else
  527. *lvp = 0;
  528. break;
  529. default:
  530. rc = -1;
  531. break;
  532. }
  533. return rc;
  534. }
  535. /*!
  536. * \brief Initialize on chip uart device.
  537. *
  538. * Prepares the device for subsequent reading or writing.
  539. * Enables SCI transmitter and receiver interrupts.
  540. *
  541. * \param dev Identifies the device to initialize.
  542. *
  543. * \return 0 on success, -1 otherwise.
  544. */
  545. int SciH8Init(NUTDEVICE * dev)
  546. {
  547. IFSTREAM *ifs;
  548. UARTDCB *dcb;
  549. u_long baudrate = 9600;
  550. volatile struct st_sci *sci = GET_SCI(dev->dev_base);
  551. /*
  552. * We only support character devices for on-chip SCIs.
  553. */
  554. if (dev->dev_type != IFTYP_STREAM || dev->dev_irq != 0 || (dev->dev_base != 0 && dev->dev_base != 1 && dev->dev_base != 2))
  555. return -1;
  556. /*
  557. * Initialize interface control block.
  558. */
  559. ifs = dev->dev_icb;
  560. memset(ifs, 0, sizeof(IFSTREAM));
  561. ifs->if_input = SciH8Input;
  562. ifs->if_output = SciH8Output;
  563. ifs->if_flush = SciH8Flush;
  564. /*
  565. * Initialize driver control block.
  566. */
  567. dcb = dev->dev_dcb;
  568. memset(dcb, 0, sizeof(UARTDCB));
  569. /* dcb->dcb_baudSelect = 7; */
  570. dcb->dcb_modeflags = UART_MF_NOBUFFER;
  571. /*
  572. * Register interrupt handler.
  573. */
  574. if (dev->dev_base == 2) {
  575. if (NutRegisterIrqHandler(&sig_RXI2, RxComplete, dev))
  576. return -1;
  577. if (NutRegisterIrqHandler(&sig_TXI2, TxComplete, dev))
  578. return -1;
  579. } else if (dev->dev_base == 1) {
  580. if (NutRegisterIrqHandler(&sig_RXI1, RxComplete, dev))
  581. return -1;
  582. if (NutRegisterIrqHandler(&sig_TXI1, TxComplete, dev))
  583. return -1;
  584. } else if (dev->dev_base == 0) {
  585. if (NutRegisterIrqHandler(&sig_RXI0, RxComplete, dev))
  586. return -1;
  587. if (NutRegisterIrqHandler(&sig_TXI0, TxComplete, dev))
  588. return -1;
  589. }
  590. sci->SCR.BYTE = 0;
  591. /* Set for Async, data bits, parity, stop bit and an undivided clock. */
  592. sci->SMR.BYTE = DATABITS_8 | NOPARITY | STOP1BIT | NODIVIDE;
  593. /* Clear relevant status bits. */
  594. sci->SSR.BYTE = ~(PER | FER | ORER | RDRF);
  595. sci->SCR.BYTE = (RXI_ENABLE | RX_ENABLE | TX_ENABLE);
  596. /*
  597. * Set baudrate and handshake default. This will also
  598. * enable the UART functions.
  599. */
  600. SciH8IOCtl(dev, UART_SETSPEED, &baudrate);
  601. return 0;
  602. }
  603. /*!
  604. * \brief Read from device.
  605. */
  606. int SciH8Read(NUTFILE * fp, void *buffer, int size)
  607. {
  608. int rc;
  609. NUTDEVICE *dev;
  610. IFSTREAM *ifs;
  611. UARTDCB *dcb;
  612. u_char elmode;
  613. u_char ch;
  614. u_char *cp = buffer;
  615. dev = fp->nf_dev;
  616. ifs = (IFSTREAM *) dev->dev_icb;
  617. dcb = dev->dev_dcb;
  618. if (dcb->dcb_modeflags & UART_MF_COOKEDMODE)
  619. elmode = 1;
  620. else
  621. elmode = 0;
  622. /*
  623. * Call without data pointer discards receive buffer.
  624. */
  625. if (buffer == 0) {
  626. ifs->if_rd_idx = ifs->if_rx_idx;
  627. return 0;
  628. }
  629. /*
  630. * Get characters from receive buffer.
  631. */
  632. for (rc = 0; rc < size;) {
  633. if (ifs->if_rd_idx == ifs->if_rx_idx) {
  634. if (rc)
  635. break;
  636. while (ifs->if_rd_idx == ifs->if_rx_idx) {
  637. if (SciH8Input(dev)) {
  638. return 0;
  639. }
  640. }
  641. }
  642. ch = ifs->if_rx_buf[ifs->if_rd_idx++];
  643. if (elmode && (ch == '\r' || ch == '\n')) {
  644. if (ifs->if_last_eol == 0 || ifs->if_last_eol == ch) {
  645. ifs->if_last_eol = ch;
  646. *cp++ = '\n';
  647. rc++;
  648. }
  649. } else {
  650. ifs->if_last_eol = 0;
  651. *cp++ = ch;
  652. rc++;
  653. }
  654. }
  655. return rc;
  656. }
  657. /*!
  658. * \brief Write to device.
  659. */
  660. int SciH8Put(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
  661. {
  662. int rc;
  663. IFSTREAM *ifs;
  664. UARTDCB *dcb;
  665. CONST u_char *cp;
  666. u_char lbmode;
  667. u_char elmode;
  668. u_char ch;
  669. ifs = dev->dev_icb;
  670. dcb = dev->dev_dcb;
  671. if (dcb->dcb_modeflags & UART_MF_LINEBUFFER)
  672. lbmode = 1;
  673. else
  674. lbmode = 0;
  675. if (dcb->dcb_modeflags & UART_MF_COOKEDMODE)
  676. elmode = 1;
  677. else
  678. elmode = 0;
  679. /*
  680. * Call without data pointer starts transmission.
  681. */
  682. if (buffer == 0) {
  683. rc = SciH8Flush(dev);
  684. return rc;
  685. }
  686. /*
  687. * Put characters in transmit buffer.
  688. */
  689. cp = buffer;
  690. for (rc = 0; rc < len;) {
  691. if ((u_char) (ifs->if_wr_idx + 1) == ifs->if_tx_idx) {
  692. if (SciH8Flush(dev)) {
  693. return -1;
  694. }
  695. }
  696. ch = pflg ? PRG_RDB(cp) : *cp;
  697. if (elmode == 1 && ch == '\n') {
  698. elmode = 2;
  699. if (lbmode == 1)
  700. lbmode = 2;
  701. ch = '\r';
  702. } else {
  703. if (elmode == 2)
  704. elmode = 1;
  705. cp++;
  706. rc++;
  707. }
  708. ifs->if_tx_buf[ifs->if_wr_idx++] = ch;
  709. }
  710. if (lbmode > 1 || (dcb->dcb_modeflags & UART_MF_NOBUFFER) != 0) {
  711. if (SciH8Flush(dev))
  712. rc = -1;
  713. }
  714. return rc;
  715. }
  716. int SciH8Write(NUTFILE * fp, CONST void *buffer, int len)
  717. {
  718. return SciH8Put(fp->nf_dev, buffer, len, 0);
  719. }
  720. /*!
  721. * \brief Open a device or file.
  722. */
  723. NUTFILE *SciH8Open(NUTDEVICE * dev, CONST char *name, int mode, int acc)
  724. {
  725. NUTFILE *fp = NutHeapAlloc(sizeof(NUTFILE));
  726. UARTDCB *dcb;
  727. if (fp == 0)
  728. return NUTFILE_EOF;
  729. dcb = dev->dev_dcb;
  730. if (mode & _O_BINARY)
  731. dcb->dcb_modeflags &= ~UART_MF_COOKEDMODE;
  732. else
  733. dcb->dcb_modeflags |= UART_MF_COOKEDMODE;
  734. fp->nf_dev = dev;
  735. fp->nf_fcb = NULL;
  736. return fp;
  737. }
  738. /*!
  739. * \brief Close a device or file.
  740. */
  741. int SciH8Close(NUTFILE * fp)
  742. {
  743. NutHeapFree(fp);
  744. return 0;
  745. }
  746. /*@}*/