at91_ahdlc.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. /*
  2. * Copyright (C) 2008 by Szemzo András. All rights reserved.
  3. * Copyright (C) 2003-2004 by egnite Software GmbH. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  25. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  28. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * For additional information see http://www.ethernut.de/
  32. *
  33. */
  34. /*
  35. * $Log$
  36. * Revision 1.3 2009/02/06 15:37:39 haraldkipp
  37. * Added stack space multiplier and addend. Adjusted stack space.
  38. *
  39. * Revision 1.2 2008/08/11 06:59:03 haraldkipp
  40. * BSD types replaced by stdint types (feature request #1282721).
  41. *
  42. * Revision 1.1 2008/04/18 13:27:41 haraldkipp
  43. * First ARM implementation, done by Szemzo Andras.
  44. *
  45. */
  46. // TODO -
  47. /*
  48. - add proper close function
  49. - add proper ioctrl
  50. - rewrite to enable uart0 as well
  51. */
  52. #define NUT_DEPRECATED
  53. #include <cfg/ahdlc.h>
  54. #include <string.h>
  55. #include <stdlib.h>
  56. #include <fcntl.h>
  57. #include <sys/nutconfig.h>
  58. #include <sys/atom.h>
  59. #include <sys/heap.h>
  60. #include <sys/event.h>
  61. #include <sys/timer.h>
  62. #include <sys/thread.h>
  63. #include <dev/irqreg.h>
  64. #include <dev/ppp.h>
  65. #include <netinet/if_ppp.h>
  66. #include <net/ppp.h>
  67. #include <net/if_var.h>
  68. #include <dev/usartat91.h>
  69. #include <dev/at91_ahdlc.h>
  70. #ifndef NUT_AHDLC_RECV_DMA_SIZE
  71. #define NUT_AHDLC_RECV_DMA_SIZE 64
  72. #endif
  73. // rxDMA buffer
  74. static unsigned char DMA_RxBuf0[NUT_AHDLC_RECV_DMA_SIZE];
  75. #define UART_RECEIVER_TIMEOUT 32 /* in bit-times */
  76. #define SIG_UART sig_UART1
  77. #define US_ID US1_ID
  78. #define US_GPIO_PINS 0x00000360
  79. /*!
  80. * \addtogroup xgAhdlcAvr
  81. */
  82. /*@{*/
  83. static AHDLCDCB dcb_ahdlc;
  84. /*!
  85. * \brief Device information structure.
  86. *
  87. * A pointer to this structure must be passed to NutRegisterDevice()
  88. * to bind this device driver to the Nut/OS kernel.
  89. */
  90. NUTDEVICE devAhdlc1 = {
  91. 0, /* Pointer to next device. */
  92. {'u', 'a', 'r', 't', '1', 0, 0, 0, 0}, /* Unique device name. */
  93. IFTYP_CHAR, /* Type of device. */
  94. 1, /* Base address. */
  95. 0, /* First interrupt number. */
  96. 0, /* Interface control block. */
  97. &dcb_ahdlc, /* Driver control block. */
  98. AhdlcAt91Init, /* Driver initialization routine, dev_init. */
  99. AhdlcAt91IOCtl, /* Driver specific control function, dev_ioctl. */
  100. AhdlcAt91Read, /* Read from device, dev_read. */
  101. AhdlcAt91Write, /* Write to device, dev_write. */
  102. AhdlcAt91Open, /* Open a device or file, dev_open. */
  103. AhdlcAt91Close, /* Close a device or file, dev_close. */
  104. 0, /* Request file size, dev_size. */
  105. 0, /* Select function, optional, not yet implemented */
  106. };
  107. /*
  108. * FCS lookup table located in program memory space.
  109. */
  110. static char fcstab[512] = {
  111. 0x00, 0x00, 0x11, 0x89, 0x23, 0x12, 0x32, 0x9b, 0x46, 0x24, 0x57, 0xad, 0x65, 0x36, 0x74, 0xbf,
  112. 0x8c, 0x48, 0x9d, 0xc1, 0xaf, 0x5a, 0xbe, 0xd3, 0xca, 0x6c, 0xdb, 0xe5, 0xe9, 0x7e, 0xf8, 0xf7,
  113. 0x10, 0x81, 0x01, 0x08, 0x33, 0x93, 0x22, 0x1a, 0x56, 0xa5, 0x47, 0x2c, 0x75, 0xb7, 0x64, 0x3e,
  114. 0x9c, 0xc9, 0x8d, 0x40, 0xbf, 0xdb, 0xae, 0x52, 0xda, 0xed, 0xcb, 0x64, 0xf9, 0xff, 0xe8, 0x76,
  115. 0x21, 0x02, 0x30, 0x8b, 0x02, 0x10, 0x13, 0x99, 0x67, 0x26, 0x76, 0xaf, 0x44, 0x34, 0x55, 0xbd,
  116. 0xad, 0x4a, 0xbc, 0xc3, 0x8e, 0x58, 0x9f, 0xd1, 0xeb, 0x6e, 0xfa, 0xe7, 0xc8, 0x7c, 0xd9, 0xf5,
  117. 0x31, 0x83, 0x20, 0x0a, 0x12, 0x91, 0x03, 0x18, 0x77, 0xa7, 0x66, 0x2e, 0x54, 0xb5, 0x45, 0x3c,
  118. 0xbd, 0xcb, 0xac, 0x42, 0x9e, 0xd9, 0x8f, 0x50, 0xfb, 0xef, 0xea, 0x66, 0xd8, 0xfd, 0xc9, 0x74,
  119. 0x42, 0x04, 0x53, 0x8d, 0x61, 0x16, 0x70, 0x9f, 0x04, 0x20, 0x15, 0xa9, 0x27, 0x32, 0x36, 0xbb,
  120. 0xce, 0x4c, 0xdf, 0xc5, 0xed, 0x5e, 0xfc, 0xd7, 0x88, 0x68, 0x99, 0xe1, 0xab, 0x7a, 0xba, 0xf3,
  121. 0x52, 0x85, 0x43, 0x0c, 0x71, 0x97, 0x60, 0x1e, 0x14, 0xa1, 0x05, 0x28, 0x37, 0xb3, 0x26, 0x3a,
  122. 0xde, 0xcd, 0xcf, 0x44, 0xfd, 0xdf, 0xec, 0x56, 0x98, 0xe9, 0x89, 0x60, 0xbb, 0xfb, 0xaa, 0x72,
  123. 0x63, 0x06, 0x72, 0x8f, 0x40, 0x14, 0x51, 0x9d, 0x25, 0x22, 0x34, 0xab, 0x06, 0x30, 0x17, 0xb9,
  124. 0xef, 0x4e, 0xfe, 0xc7, 0xcc, 0x5c, 0xdd, 0xd5, 0xa9, 0x6a, 0xb8, 0xe3, 0x8a, 0x78, 0x9b, 0xf1,
  125. 0x73, 0x87, 0x62, 0x0e, 0x50, 0x95, 0x41, 0x1c, 0x35, 0xa3, 0x24, 0x2a, 0x16, 0xb1, 0x07, 0x38,
  126. 0xff, 0xcf, 0xee, 0x46, 0xdc, 0xdd, 0xcd, 0x54, 0xb9, 0xeb, 0xa8, 0x62, 0x9a, 0xf9, 0x8b, 0x70,
  127. 0x84, 0x08, 0x95, 0x81, 0xa7, 0x1a, 0xb6, 0x93, 0xc2, 0x2c, 0xd3, 0xa5, 0xe1, 0x3e, 0xf0, 0xb7,
  128. 0x08, 0x40, 0x19, 0xc9, 0x2b, 0x52, 0x3a, 0xdb, 0x4e, 0x64, 0x5f, 0xed, 0x6d, 0x76, 0x7c, 0xff,
  129. 0x94, 0x89, 0x85, 0x00, 0xb7, 0x9b, 0xa6, 0x12, 0xd2, 0xad, 0xc3, 0x24, 0xf1, 0xbf, 0xe0, 0x36,
  130. 0x18, 0xc1, 0x09, 0x48, 0x3b, 0xd3, 0x2a, 0x5a, 0x5e, 0xe5, 0x4f, 0x6c, 0x7d, 0xf7, 0x6c, 0x7e,
  131. 0xa5, 0x0a, 0xb4, 0x83, 0x86, 0x18, 0x97, 0x91, 0xe3, 0x2e, 0xf2, 0xa7, 0xc0, 0x3c, 0xd1, 0xb5,
  132. 0x29, 0x42, 0x38, 0xcb, 0x0a, 0x50, 0x1b, 0xd9, 0x6f, 0x66, 0x7e, 0xef, 0x4c, 0x74, 0x5d, 0xfd,
  133. 0xb5, 0x8b, 0xa4, 0x02, 0x96, 0x99, 0x87, 0x10, 0xf3, 0xaf, 0xe2, 0x26, 0xd0, 0xbd, 0xc1, 0x34,
  134. 0x39, 0xc3, 0x28, 0x4a, 0x1a, 0xd1, 0x0b, 0x58, 0x7f, 0xe7, 0x6e, 0x6e, 0x5c, 0xf5, 0x4d, 0x7c,
  135. 0xc6, 0x0c, 0xd7, 0x85, 0xe5, 0x1e, 0xf4, 0x97, 0x80, 0x28, 0x91, 0xa1, 0xa3, 0x3a, 0xb2, 0xb3,
  136. 0x4a, 0x44, 0x5b, 0xcd, 0x69, 0x56, 0x78, 0xdf, 0x0c, 0x60, 0x1d, 0xe9, 0x2f, 0x72, 0x3e, 0xfb,
  137. 0xd6, 0x8d, 0xc7, 0x04, 0xf5, 0x9f, 0xe4, 0x16, 0x90, 0xa9, 0x81, 0x20, 0xb3, 0xbb, 0xa2, 0x32,
  138. 0x5a, 0xc5, 0x4b, 0x4c, 0x79, 0xd7, 0x68, 0x5e, 0x1c, 0xe1, 0x0d, 0x68, 0x3f, 0xf3, 0x2e, 0x7a,
  139. 0xe7, 0x0e, 0xf6, 0x87, 0xc4, 0x1c, 0xd5, 0x95, 0xa1, 0x2a, 0xb0, 0xa3, 0x82, 0x38, 0x93, 0xb1,
  140. 0x6b, 0x46, 0x7a, 0xcf, 0x48, 0x54, 0x59, 0xdd, 0x2d, 0x62, 0x3c, 0xeb, 0x0e, 0x70, 0x1f, 0xf9,
  141. 0xf7, 0x8f, 0xe6, 0x06, 0xd4, 0x9d, 0xc5, 0x14, 0xb1, 0xab, 0xa0, 0x22, 0x92, 0xb9, 0x83, 0x30,
  142. 0x7b, 0xc7, 0x6a, 0x4e, 0x58, 0xd5, 0x49, 0x5c, 0x3d, 0xe3, 0x2c, 0x6a, 0x1e, 0xf1, 0x0f, 0x78
  143. };
  144. /*!
  145. * Checks the 32-bit ACCM to see if the byte needs un-escaping
  146. */
  147. #define IN_ACC_MAP(c, m) (( ((uint8_t) (c)) < 0x20) && ((m) & (1UL << (c))) != 0)
  148. #ifndef NUT_THREAD_AHDLCRXSTACK
  149. #define NUT_THREAD_AHDLCRXSTACK 2048
  150. #endif
  151. /*!
  152. * \brief USART interrupt handler.
  153. *
  154. * \param arg Pointer to the device specific control block.
  155. */
  156. static void At91UsartInterrupt(void *arg)
  157. {
  158. AHDLCDCB *dcb = arg;
  159. uint16_t count, i;
  160. ureg_t csr = inr(US1_CSR);
  161. if (csr & (US_ENDRX | US_RXBUFF | US_TIMEOUT)) {
  162. // Todo, handle error flags
  163. if (csr & US_TIMEOUT) {
  164. count = NUT_AHDLC_RECV_DMA_SIZE - inr(USART1_BASE + PERIPH_RCR_OFF);
  165. } else {
  166. count = NUT_AHDLC_RECV_DMA_SIZE;
  167. }
  168. for (i = 0; i < count; i++) {
  169. dcb->dcb_rx_buf[dcb->dcb_rx_idx] = DMA_RxBuf0[i];
  170. dcb->dcb_rx_idx++;
  171. }
  172. outr(USART1_BASE + PERIPH_RPR_OFF, (unsigned int) DMA_RxBuf0);
  173. outr(USART1_BASE + PERIPH_RCR_OFF, NUT_AHDLC_RECV_DMA_SIZE);
  174. outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN);
  175. outr(US1_CR, inr(US1_CR) | US_STTTO);
  176. NutEventPostFromIrq(&dcb->dcb_rx_rdy);
  177. }
  178. if (csr & US_TXRDY) {
  179. if (dcb->dcb_tx_idx != dcb->dcb_wr_idx) {
  180. outr(US1_THR, dcb->dcb_tx_buf[dcb->dcb_tx_idx]);
  181. dcb->dcb_tx_idx++;
  182. } else {
  183. outr(US1_IDR, US_TXRDY);
  184. NutEventPostFromIrq(&dcb->dcb_tx_rdy);
  185. }
  186. }
  187. }
  188. /*
  189. * \return 0 on success, -1 in case of any errors.
  190. */
  191. static int SendRawByte(AHDLCDCB * dcb, uint8_t ch, uint8_t flush)
  192. {
  193. /*
  194. * If transmit buffer is full, wait until interrupt routine
  195. * signals an empty buffer or until a timeout occurs.
  196. */
  197. while ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
  198. if (NutEventWait(&dcb->dcb_tx_rdy, dcb->dcb_wtimeout))
  199. break;
  200. }
  201. /*
  202. * If transmit buffer is still full, we have a write timeout.
  203. */
  204. if ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
  205. return -1;
  206. }
  207. /*
  208. * Buffer has room for more data. Put the byte in the buffer
  209. * and increment the write index.
  210. */
  211. dcb->dcb_tx_buf[dcb->dcb_wr_idx] = ch;
  212. dcb->dcb_wr_idx++;
  213. /*
  214. * If transmit buffer has become full and the transmitter
  215. * is not active, then activate it.
  216. */
  217. if (flush || (uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
  218. NutEnterCritical();
  219. outr(US1_IER, US_TXRDY);
  220. NutExitCritical();
  221. }
  222. return 0;
  223. }
  224. /*
  225. * Characters are properly escaped and checksum is updated.
  226. *
  227. * \return 0 on success, -1 in case of any errors.
  228. */
  229. static int SendHdlcData(AHDLCDCB * dcb, const uint8_t * data, uint16_t len, uint16_t * txfcs)
  230. {
  231. uint16_t tbx;
  232. uint16_t fcs;
  233. if (txfcs)
  234. fcs = *txfcs;
  235. else
  236. fcs = 0;
  237. while (len) {
  238. tbx = (uint16_t) ((uint8_t) fcs ^ *data) << 1;
  239. fcs >>= 8;
  240. fcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
  241. if (IN_ACC_MAP(*data, dcb->dcb_tx_accm) || *data == AHDLC_FLAG || *data == AHDLC_ESCAPE) {
  242. if (SendRawByte(dcb, AHDLC_ESCAPE, 0)) {
  243. return -1;
  244. }
  245. if (SendRawByte(dcb, *data ^ AHDLC_TRANS, 0)) {
  246. return -1;
  247. }
  248. } else if (SendRawByte(dcb, *data, 0)) {
  249. return -1;
  250. }
  251. data++;
  252. len--;
  253. }
  254. if (txfcs)
  255. *txfcs = fcs;
  256. return 0;
  257. }
  258. /*!
  259. * \brief Send HDLC frame.
  260. *
  261. * \param dev Identifies the device to use.
  262. * \param nb Network buffer structure containing the packet to be sent.
  263. * The structure must have been allocated by a previous
  264. * call NutNetBufAlloc().
  265. *
  266. * \return 0 on success, -1 in case of any errors.
  267. */
  268. int AhdlcOutput(NUTDEVICE * dev, NETBUF * nb)
  269. {
  270. uint16_t txfcs;
  271. AHDLCDCB *dcb = dev->dev_dcb;
  272. uint16_t sz;
  273. /*
  274. * If we are in RAW mode we are not allowed to send AHDLC output.
  275. * We just emulate packet loss behaviour in here.
  276. */
  277. if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
  278. return 0;
  279. }
  280. /*
  281. * Calculate the number of bytes to be send. Do not
  282. * send packets larger than transmit mru.
  283. */
  284. sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
  285. if (sz > dcb->dcb_tx_mru) {
  286. return -1;
  287. }
  288. /*
  289. * TODO: If transmitter is running, we may omit the flag.
  290. */
  291. SendRawByte(dcb, AHDLC_FLAG, 0);
  292. /* Initialize the checksum and send the NETBUF. */
  293. txfcs = AHDLC_INITFCS;
  294. if (SendHdlcData(dcb, nb->nb_dl.vp, nb->nb_dl.sz, &txfcs))
  295. return -1;
  296. if (SendHdlcData(dcb, nb->nb_nw.vp, nb->nb_nw.sz, &txfcs))
  297. return -1;
  298. if (SendHdlcData(dcb, nb->nb_tp.vp, nb->nb_tp.sz, &txfcs))
  299. return -1;
  300. if (SendHdlcData(dcb, nb->nb_ap.vp, nb->nb_ap.sz, &txfcs))
  301. return -1;
  302. /* Send the checksum and the final flag. */
  303. txfcs ^= 0xffff;
  304. if (SendHdlcData(dcb, (uint8_t *) & txfcs, 2, 0))
  305. return -1;
  306. SendRawByte(dcb, AHDLC_FLAG, 1);
  307. return 0;
  308. }
  309. /*! \fn AhdlcRx(void *arg)
  310. * \brief Asynchronous HDLC receiver thread.
  311. *
  312. *
  313. * Running at high priority.
  314. */
  315. THREAD(AhdlcRx, arg)
  316. {
  317. NUTDEVICE *dev = arg;
  318. NUTDEVICE *netdev;
  319. AHDLCDCB *dcb = dev->dev_dcb;
  320. IFNET *ifn;
  321. NETBUF *nb;
  322. uint8_t *rxbuf;
  323. uint8_t *rxptr;
  324. uint16_t rxcnt;
  325. uint8_t ch;
  326. uint16_t tbx;
  327. uint8_t inframe;
  328. uint8_t escaped;
  329. uint16_t rxfcs;
  330. NutThreadSetPriority(9);
  331. for (;;) {
  332. /*
  333. * Reset variables to their initial state
  334. */
  335. rxptr = 0;
  336. rxcnt = 0;
  337. escaped = 0;
  338. rxfcs = AHDLC_INITFCS;
  339. inframe = 0;
  340. for (;;) {
  341. /*
  342. * Wait until the network interface has been attached.
  343. * This will be initiated by the application calling
  344. * NutNetIfConfig(), which in turn calls a HDLC_SETIFNET
  345. * ioctl() to store the NUTDEVICE pointer of the network
  346. * device in dev_icb and trigger an event on dcb_mf_evt.
  347. */
  348. while ((netdev = dev->dev_icb) == 0) {
  349. if (NutEventWait(&dcb->dcb_mf_evt, 1000) == 0) {
  350. NutSleep(100);
  351. }
  352. }
  353. ifn = netdev->dev_icb;
  354. dcb->dcb_rtimeout = 1000;
  355. inframe = 0;
  356. /*
  357. * Allocate the receive buffer, if this fails, we are in a
  358. * low memory situation. Take a nap and see, if the
  359. * situation improved.
  360. */
  361. if ((rxbuf = NutHeapAlloc(dcb->dcb_rx_mru)) != 0) {
  362. break;
  363. }
  364. NutSleep(1000);
  365. }
  366. /*
  367. * Signal the link driver that we are up.
  368. */
  369. ifn->if_send = AhdlcOutput;
  370. netdev->dev_ioctl(netdev, LCP_LOWERUP, 0);
  371. for (;;) {
  372. /*
  373. * If we are still connected to a network, fetch the next
  374. * character from the buffer.
  375. */
  376. while (dcb->dcb_rd_idx == dcb->dcb_rx_idx) {
  377. if (dev->dev_icb == 0)
  378. break;
  379. // TODO: Check for idle timeout.
  380. if (NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout)) {
  381. continue;
  382. }
  383. }
  384. /*
  385. * Leave loop if network interface is detached
  386. */
  387. if (dev->dev_icb == 0)
  388. break;
  389. /*
  390. * If RAW mode is active, we are not allowing any data encapsulation
  391. * processing. So we just sleep for a while.
  392. */
  393. if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
  394. /*
  395. * It is a must to sleep here, because if we just yield it could create
  396. * too much processing in here and stall processing elsewhere. This gives
  397. * opportunity to other threads to process incoming data from USART.
  398. */
  399. NutSleep(100);
  400. continue;
  401. }
  402. /*
  403. * Read next character from input buffer
  404. */
  405. ch = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
  406. if (inframe) {
  407. if (ch != AHDLC_FLAG) {
  408. if (ch == AHDLC_ESCAPE) {
  409. escaped = 1;
  410. continue;
  411. }
  412. if (escaped) {
  413. ch ^= AHDLC_TRANS;
  414. escaped = 0;
  415. }
  416. /*
  417. * Unless the peer lied to us about the negotiated MRU,
  418. * we should never get a frame which is too long. If it
  419. * happens, toss it away and grab the next incoming one.
  420. */
  421. if (rxcnt++ < dcb->dcb_rx_mru) {
  422. /* Update calculated checksum and store character in buffer. */
  423. tbx = (uint16_t) ((uint8_t) rxfcs ^ ch) << 1;
  424. rxfcs >>= 8;
  425. rxfcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
  426. *rxptr++ = ch;
  427. } else
  428. inframe = 0;
  429. continue;
  430. }
  431. if (rxcnt > 6 && rxfcs == AHDLC_GOODFCS) {
  432. /*
  433. * If the frame checksum is valid, create a NETBUF
  434. * and pass it to the network specific receive handler.
  435. */
  436. rxcnt -= 2;
  437. if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, rxcnt)) != 0) {
  438. memcpy(nb->nb_dl.vp, rxbuf, rxcnt);
  439. (*ifn->if_recv) (netdev, nb);
  440. }
  441. }
  442. }
  443. /*
  444. * If frame flag is received, resync frame processing
  445. */
  446. if (ch == AHDLC_FLAG) {
  447. inframe = 1;
  448. escaped = 0;
  449. rxptr = rxbuf;
  450. rxcnt = 0;
  451. rxfcs = AHDLC_INITFCS;
  452. }
  453. }
  454. /* Signal the link driver that we are down. */
  455. netdev->dev_ioctl(netdev, LCP_LOWERDOWN, 0);
  456. /* Disconnected, clean up. */
  457. if (rxbuf) {
  458. NutHeapFree(rxbuf);
  459. rxbuf = 0;
  460. }
  461. }
  462. }
  463. /*
  464. * \param dev Indicates the UART device.
  465. *
  466. * \return 0 on success, -1 otherwise.
  467. */
  468. static int AhdlcAt91GetStatus(NUTDEVICE * dev, uint32_t * status)
  469. {
  470. AHDLCDCB *dcb = dev->dev_dcb;
  471. //SAAM u_char us;
  472. *status = 0;
  473. #ifdef __AVR_ENHANCED__
  474. if (dev->dev_base) {
  475. #ifdef UART1_CTS_BIT
  476. if (bit_is_set(UART1_CTS_PIN, UART1_CTS_BIT))
  477. *status |= UART_CTSDISABLED;
  478. else
  479. *status |= UART_CTSENABLED;
  480. #endif
  481. #ifdef UART1_RTS_BIT
  482. if (bit_is_set(UART1_RTS_PORT, UART1_RTS_BIT))
  483. *status |= UART_RTSDISABLED;
  484. else
  485. *status |= UART_RTSENABLED;
  486. #endif
  487. #ifdef UART1_DTR_BIT
  488. if (bit_is_set(UART1_DTR_PORT, UART1_DTR_BIT))
  489. *status |= UART_DTRDISABLED;
  490. else
  491. *status |= UART_DTRENABLED;
  492. #endif
  493. us = inb(UCSR1A);
  494. } else
  495. #endif /* __AVR_ENHANCED__ */
  496. {
  497. #ifdef UART0_CTS_BIT
  498. if (bit_is_set(UART0_CTS_PIN, UART0_CTS_BIT))
  499. *status |= UART_CTSDISABLED;
  500. else
  501. *status |= UART_CTSENABLED;
  502. #endif
  503. #ifdef UART0_RTS_BIT
  504. if (bit_is_set(UART0_RTS_PORT, UART0_RTS_BIT))
  505. *status |= UART_RTSDISABLED;
  506. else
  507. *status |= UART_RTSENABLED;
  508. #endif
  509. #ifdef UART0_DTR_BIT
  510. if (bit_is_set(UART0_DTR_PORT, UART0_DTR_BIT))
  511. *status |= UART_DTRDISABLED;
  512. else
  513. *status |= UART_DTRENABLED;
  514. #endif
  515. //SAAM us = inb(USR);
  516. }
  517. //SAAM if (us & FE)
  518. //SAAM *status |= UART_FRAMINGERROR;
  519. //SAAM if (us & DOR)
  520. //SAAM *status |= UART_OVERRUNERROR;
  521. if (dcb->dcb_tx_idx == dcb->dcb_wr_idx)
  522. *status |= UART_TXBUFFEREMPTY;
  523. if (dcb->dcb_rd_idx == dcb->dcb_rx_idx)
  524. *status |= UART_RXBUFFEREMPTY;
  525. return 0;
  526. }
  527. /*
  528. * \param dev Indicates the UART device.
  529. *
  530. * \return 0 on success, -1 otherwise.
  531. */
  532. static int AhdlcAt91SetStatus(NUTDEVICE * dev, uint32_t status)
  533. {
  534. #ifdef __AVR_ENHANCED__
  535. if (dev->dev_base) {
  536. #ifdef UART1_RTS_BIT
  537. if (status & UART_RTSDISABLED)
  538. sbi(UART1_RTS_PORT, UART1_RTS_BIT);
  539. else if (status & UART_RTSENABLED)
  540. cbi(UART1_RTS_PORT, UART1_RTS_BIT);
  541. #endif
  542. #ifdef UART1_DTR_BIT
  543. if (status & UART_DTRDISABLED)
  544. sbi(UART1_DTR_PORT, UART1_DTR_BIT);
  545. else if (status & UART_DTRENABLED)
  546. cbi(UART1_DTR_PORT, UART1_DTR_BIT);
  547. #endif
  548. } else
  549. #endif /* __AVR_ENHANCED__ */
  550. {
  551. #ifdef UART0_RTS_BIT
  552. if (status & UART_RTSDISABLED)
  553. sbi(UART0_RTS_PORT, UART0_RTS_BIT);
  554. else if (status & UART_RTSENABLED)
  555. cbi(UART0_RTS_PORT, UART0_RTS_BIT);
  556. #endif
  557. #ifdef UART0_DTR_BIT
  558. if (status & UART_DTRDISABLED)
  559. sbi(UART0_DTR_PORT, UART0_DTR_BIT);
  560. else if (status & UART_DTRENABLED)
  561. cbi(UART0_DTR_PORT, UART0_DTR_BIT);
  562. #endif
  563. }
  564. return 0;
  565. }
  566. /*
  567. * Carefully enable UART functions.
  568. */
  569. static void AhdlcAt91Enable(uint16_t base)
  570. {
  571. NutEnterCritical();
  572. outr(US1_RTOR, UART_RECEIVER_TIMEOUT);
  573. outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN); // enable Rx DMA
  574. outr(US1_CR, US_TXEN | US_RXEN | US_STTTO); /* Enable UART receiver and transmitter. */
  575. /* Enable UART receiver interrupts. */
  576. outr(US1_IER, US_ENDRX | US_RXBUFF | US_TIMEOUT);
  577. NutIrqEnable(&SIG_UART);
  578. NutExitCritical();
  579. }
  580. /*
  581. * Carefully disable UART functions.
  582. */
  583. static void AhdlcAt91Disable(uint16_t base)
  584. {
  585. NutEnterCritical();
  586. NutIrqDisable(&SIG_UART);
  587. outr(US1_IDR, -1);
  588. outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTDIS);
  589. NutExitCritical();
  590. /*
  591. * Allow incoming or outgoing character to finish.
  592. */
  593. NutDelay(10);
  594. /*
  595. * Disable USART transmit and receive.
  596. */
  597. outr(US1_CR, US_RXDIS | US_TXDIS);
  598. }
  599. /*!
  600. * \brief Perform on-chip UART control functions.
  601. *
  602. * \param dev Identifies the device that receives the device-control
  603. * function.
  604. * \param req Requested control function. May be set to one of the
  605. * following constants:
  606. * - UART_SETSPEED, conf points to an uint32_t value containing the baudrate.
  607. * - UART_GETSPEED, conf points to an uint32_t value receiving the current baudrate.
  608. * - UART_SETSTATUS, conf points to an uint32_t value containing the changes for the control lines.
  609. * - UART_GETSTATUS, conf points to an uint32_t value receiving the state of the control lines and the device.
  610. * - UART_SETREADTIMEOUT, conf points to an uint32_t value containing the read timeout.
  611. * - UART_GETREADTIMEOUT, conf points to an uint32_t value receiving the read timeout.
  612. * - UART_SETWRITETIMEOUT, conf points to an uint32_t value containing the write timeout.
  613. * - UART_GETWRITETIMEOUT, conf points to an uint32_t value receiving the write timeout.
  614. * - UART_SETLOCALECHO, conf points to an uint32_t value containing 0 (off) or 1 (on).
  615. * - UART_GETLOCALECHO, conf points to an uint32_t value receiving 0 (off) or 1 (on).
  616. * - UART_SETFLOWCONTROL, conf points to an uint32_t value containing combined UART_FCTL_ values.
  617. * - UART_GETFLOWCONTROL, conf points to an uint32_t value containing receiving UART_FCTL_ values.
  618. * - UART_SETCOOKEDMODE, conf points to an uint32_t value containing 0 (off) or 1 (on).
  619. * - UART_GETCOOKEDMODE, conf points to an uint32_t value receiving 0 (off) or 1 (on).
  620. * - UART_SETRAWMODE, conf points to an uint32_t value containing 0 (off) or 1 (on).
  621. * - UART_GETRAWMODE, conf points to an uint32_t value receiving 0 (off) or 1 (on).
  622. * - HDLC_SETIFNET, conf points to a pointer containing the address of the network device's NUTDEVICE structure.
  623. * - HDLC_GETIFNET, conf points to a pointer receiving the address of the network device's NUTDEVICE structure.
  624. *
  625. * \param conf Points to a buffer that contains any data required for
  626. * the given control function or receives data from that
  627. * function.
  628. * \return 0 on success, -1 otherwise.
  629. *
  630. * \warning Timeout values are given in milliseconds and are limited to
  631. * the granularity of the system timer.
  632. *
  633. * \note For ATmega103, only 8 data bits, 1 stop bit and no parity are allowed.
  634. *
  635. */
  636. int AhdlcAt91IOCtl(NUTDEVICE * dev, int req, void *conf)
  637. {
  638. int rc = 0;
  639. AHDLCDCB *dcb;
  640. void **ppv = (void **) conf;
  641. uint32_t *lvp = (uint32_t *) conf;
  642. uint8_t bv;
  643. ureg_t cs;
  644. if (dev == 0) {
  645. dev = &devUsartAt910;
  646. }
  647. dcb = dev->dev_dcb;
  648. switch (req) {
  649. case UART_SETSPEED:
  650. AhdlcAt91Disable(dcb->dcb_base);
  651. #if defined(AT91_PLL_MAINCK)
  652. outr(USART1_BASE + US_BRGR_OFF, (At91GetMasterClock() / (8 * (*lvp)) + 1) / 2);
  653. #else
  654. outr(USART1_BASE + US_BRGR_OFF, (NutGetCpuClock() / (8 * (*lvp)) + 1) / 2);
  655. #endif
  656. AhdlcAt91Enable(dcb->dcb_base);
  657. break;
  658. case UART_GETSPEED:
  659. cs = inr(USART1_BASE + US_MR_OFF);
  660. uint32_t clk;
  661. #if defined(AT91_PLL_MAINCK)
  662. clk = At91GetMasterClock();
  663. #else
  664. clk = NutGetCpuClock();
  665. #endif
  666. if ((cs & US_CLKS) == US_CLKS_MCK8) {
  667. clk /= 8;
  668. } else if ((cs & US_CLKS) != US_CLKS_MCK) {
  669. clk = 0;
  670. }
  671. *lvp = (clk / (16UL * (inr(USART1_BASE + US_BRGR_OFF) & 0xFFFF)));
  672. break;
  673. case UART_GETSTATUS:
  674. AhdlcAt91GetStatus(dev, lvp);
  675. break;
  676. case UART_SETSTATUS:
  677. AhdlcAt91SetStatus(dev, *lvp);
  678. break;
  679. case UART_SETREADTIMEOUT:
  680. dcb->dcb_rtimeout = *lvp;
  681. break;
  682. case UART_GETREADTIMEOUT:
  683. *lvp = dcb->dcb_rtimeout;
  684. break;
  685. case UART_SETWRITETIMEOUT:
  686. dcb->dcb_wtimeout = *lvp;
  687. break;
  688. case UART_GETWRITETIMEOUT:
  689. *lvp = dcb->dcb_wtimeout;
  690. break;
  691. case UART_SETLOCALECHO:
  692. bv = (uint8_t) (*lvp);
  693. if (bv)
  694. dcb->dcb_modeflags |= UART_MF_LOCALECHO;
  695. else
  696. dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
  697. break;
  698. case UART_GETLOCALECHO:
  699. if (dcb->dcb_modeflags & UART_MF_LOCALECHO)
  700. *lvp = 1;
  701. else
  702. *lvp = 0;
  703. break;
  704. case UART_SETFLOWCONTROL:
  705. bv = (uint8_t) (*lvp);
  706. if (bv)
  707. dcb->dcb_modeflags |= UART_MF_LOCALECHO;
  708. else
  709. dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
  710. break;
  711. case UART_GETFLOWCONTROL:
  712. break;
  713. case UART_SETRAWMODE:
  714. bv = (uint8_t) (*lvp);
  715. if (bv)
  716. dcb->dcb_modeflags |= UART_MF_RAWMODE;
  717. else
  718. dcb->dcb_modeflags &= ~UART_MF_RAWMODE;
  719. break;
  720. case UART_GETRAWMODE:
  721. if (dcb->dcb_modeflags & UART_MF_RAWMODE)
  722. *lvp = 1;
  723. else
  724. *lvp = 0;
  725. break;
  726. case HDLC_SETIFNET:
  727. if (ppv && (*ppv != 0)) {
  728. dev->dev_icb = *ppv;
  729. dev->dev_type = IFTYP_NET;
  730. NutEventPost(&dcb->dcb_mf_evt);
  731. } else {
  732. dev->dev_type = IFTYP_CHAR;
  733. if (dev->dev_icb != 0) {
  734. dev->dev_icb = 0;
  735. /*
  736. * Signal AHDLC Thread, so it can change it's state instantly
  737. */
  738. NutEventPost(&dcb->dcb_rx_rdy);
  739. }
  740. }
  741. break;
  742. case HDLC_GETIFNET:
  743. *ppv = dev->dev_icb;
  744. break;
  745. default:
  746. rc = -1;
  747. break;
  748. }
  749. return rc;
  750. }
  751. /*!
  752. * \brief Initialize asynchronous HDLC device.
  753. *
  754. * This function will be called during device registration. It
  755. * initializes the hardware, registers all required interrupt
  756. * handlers and initializes all internal data structures used by
  757. * this driver.
  758. *
  759. * \param dev Identifies the device to initialize.
  760. *
  761. * \return 0 on success, -1 otherwise.
  762. */
  763. int AhdlcAt91Init(NUTDEVICE * dev)
  764. {
  765. int rc = 0;
  766. AHDLCDCB *dcb;
  767. // u_long baudrate = 9600;
  768. /* Disable UART. */
  769. AhdlcAt91Disable(dev->dev_base);
  770. /* Initialize driver control block. */
  771. dcb = dev->dev_dcb;
  772. memset(dcb, 0, sizeof(AHDLCDCB));
  773. dcb->dcb_base = dev->dev_base;
  774. dcb->dcb_rx_buf = NutHeapAlloc(256);
  775. dcb->dcb_tx_buf = NutHeapAlloc(256);
  776. dcb->dcb_rx_mru = 1500;
  777. dcb->dcb_tx_mru = 1500;
  778. dcb->dcb_tx_accm = 0xFFFFFFFF;
  779. if (NutRegisterIrqHandler(&SIG_UART, At91UsartInterrupt, dcb)) {
  780. return -1;
  781. }
  782. outr(PMC_PCER, _BV(US1_ID));
  783. // outr(PIOA_PDR, _BV(5) | _BV(6) | _BV(8) | _BV(9));
  784. outr(PIOA_PDR, US_GPIO_PINS);
  785. /* Reset UART. */
  786. outr(US1_CR, US_RSTRX | US_RSTTX | US_RXDIS | US_TXDIS);
  787. /* Disable all UART interrupts. */
  788. outr(US1_IDR, 0xFFFFFFFF);
  789. /* Clear UART counter registers. */
  790. #if defined (US_RCR_OFF)
  791. outr(US1_RCR, 0);
  792. #endif
  793. #if defined (US_TCR_OFF)
  794. outr(US1_TCR, 0);
  795. #endif
  796. /* Set UART baud rate generator register. */
  797. #if defined(AT91_PLL_MAINCK)
  798. outr(US1_BRGR, (At91GetMasterClock() / (8 * (115200)) + 1) / 2);
  799. #else
  800. outr(US1_BRGR, (NutGetCpuClock() / (8 * (115200)) + 1) / 2);
  801. #endif
  802. /* Set UART mode to 8 data bits, no parity and 1 stop bit, in hw handshake mode */
  803. outr(US1_MR, US_CHMODE_NORMAL | US_CHRL_8 | US_PAR_NO | US_NBSTOP_1 | US_MODE_HWHANDSHAKE);
  804. // setup DMA controller for receive
  805. outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTDIS); // disable Rx DMA
  806. outr(USART1_BASE + PERIPH_RPR_OFF, (unsigned int) DMA_RxBuf0);
  807. outr(USART1_BASE + PERIPH_RCR_OFF, NUT_AHDLC_RECV_DMA_SIZE);
  808. outr(USART1_BASE + PERIPH_RNPR_OFF, 0);
  809. outr(USART1_BASE + PERIPH_RNCR_OFF, 0);
  810. /*
  811. * If we have been successful so far, start the HDLC receiver thread,
  812. * set the initial baudrate and enable the UART.
  813. */
  814. if (rc == 0 && NutThreadCreate("ahdlcrx", AhdlcRx, dev,
  815. (NUT_THREAD_AHDLCRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) {
  816. // AhdlcAvrIOCtl(dev, UART_SETSPEED, &baudrate);
  817. return 0;
  818. }
  819. /* We failed, clean up. */
  820. if (dcb->dcb_rx_buf)
  821. NutHeapFree((void *) dcb->dcb_rx_buf);
  822. if (dcb->dcb_tx_buf)
  823. NutHeapFree((void *) dcb->dcb_tx_buf);
  824. return -1;
  825. }
  826. /*!
  827. * \brief Read from the asynchronous HDLC device.
  828. *
  829. * This function is called by the low level input routines of the
  830. * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_read
  831. * entry.
  832. *
  833. * The function may block the calling thread until at least one
  834. * character has been received or a timeout occurs.
  835. *
  836. * It is recommended to set a proper read timeout with software handshake.
  837. * In this case a timeout may occur, if the communication peer lost our
  838. * last XON character. The application may then use ioctl() to disable the
  839. * receiver and do the read again. This will send out another XON.
  840. *
  841. * \param fp Pointer to a \ref _NUTFILE structure, obtained by a
  842. * previous call to AhdlcOpen().
  843. * \param buffer Pointer to the buffer that receives the data. If zero,
  844. * then all characters in the input buffer will be
  845. * removed.
  846. * \param size Maximum number of bytes to read.
  847. *
  848. * \return The number of bytes read, which may be less than the number
  849. * of bytes specified. A return value of -1 indicates an error,
  850. * while zero is returned in case of a timeout.
  851. */
  852. int AhdlcAt91Read(NUTFILE * fp, void *buffer, int size)
  853. {
  854. int rc = 0;
  855. AHDLCDCB *dcb = fp->nf_dev->dev_dcb;
  856. uint8_t *cp = buffer;
  857. /*
  858. * Get characters from receive buffer.
  859. */
  860. if (buffer) {
  861. while (rc < size) {
  862. if (dcb->dcb_rd_idx != dcb->dcb_rx_idx) {
  863. *cp++ = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
  864. rc++;
  865. } else if (rc || NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout))
  866. break;
  867. }
  868. }
  869. /*
  870. * Call without data buffer discards receive buffer.
  871. */
  872. else
  873. dcb->dcb_rd_idx = dcb->dcb_rx_idx;
  874. return rc;
  875. }
  876. /*!
  877. * \brief Write to the asynchronous HDLC device.
  878. *
  879. * \param dev Pointer to a previously registered NUTDEVICE structure.
  880. * \param buffer Pointer the data to write.
  881. * \param len Number of data bytes to write.
  882. * \param pflg If this flag is set, then the buffer is located in program
  883. * space.
  884. *
  885. * \return The number of bytes written. In case of a write timeout, this
  886. * may be less than the specified length.
  887. */
  888. int AhdlcAt91Put(NUTDEVICE * dev, const void *buffer, int len, int pflg)
  889. {
  890. int rc = 0;
  891. AHDLCDCB *dcb = dev->dev_dcb;
  892. const uint8_t *cp = buffer;
  893. /*
  894. * Put characters in transmit buffer.
  895. */
  896. if (buffer) {
  897. while (rc < len) {
  898. if (SendRawByte(dcb, pflg ? PRG_RDB(cp) : *cp, 0))
  899. break;
  900. cp++;
  901. rc++;
  902. }
  903. }
  904. /*
  905. * Call without data pointer starts transmission.
  906. */
  907. else {
  908. NutEnterCritical();
  909. outr(US1_IER, US_TXRDY);
  910. NutExitCritical();
  911. }
  912. return rc;
  913. }
  914. /*!
  915. * \brief Write to the asynchronous HDLC device.
  916. *
  917. * This function is called by the low level output routines of the
  918. * \ref xrCrtLowio "C runtime library", using the
  919. * \ref _NUTDEVICE::dev_write entry.
  920. *
  921. * The function may block the calling thread.
  922. *
  923. * \param fp Pointer to a _NUTFILE structure, obtained by a previous
  924. * call to AhldcOpen().
  925. * \param buffer Pointer to the data to be written. If zero, then the
  926. * output buffer will be flushed.
  927. * \param len Number of bytes to write.
  928. *
  929. * \return The number of bytes written, which may be less than the number
  930. * of bytes specified if a timeout occured. A return value of -1
  931. * indicates an error.
  932. */
  933. int AhdlcAt91Write(NUTFILE * fp, const void *buffer, int len)
  934. {
  935. return AhdlcAt91Put(fp->nf_dev, buffer, len, 0);
  936. }
  937. /*!
  938. * \brief Open the asynchronous HDLC device.
  939. *
  940. * This function is called by the low level open routine of the C runtime
  941. * library, using the _NUTDEVICE::dev_open entry.
  942. *
  943. * \param dev Pointer to the NUTDEVICE structure.
  944. * \param name Ignored, should point to an empty string.
  945. * \param mode Operation mode. Any of the following values may be or-ed:
  946. * - \ref _O_BINARY
  947. * - \ref _O_RDONLY
  948. * - \ref _O_WRONLY
  949. * \param acc Ignored, should be zero.
  950. *
  951. * \return Pointer to a NUTFILE structure if successful or NUTFILE_EOF otherwise.
  952. */
  953. NUTFILE *AhdlcAt91Open(NUTDEVICE * dev, const char *name, int mode, int acc)
  954. {
  955. NUTFILE *fp;
  956. if ((fp = NutHeapAlloc(sizeof(NUTFILE))) == 0)
  957. return NUTFILE_EOF;
  958. fp->nf_dev = dev;
  959. fp->nf_fcb = NULL;
  960. outr(US1_RTOR, UART_RECEIVER_TIMEOUT);
  961. outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN); /* enable rx DMA */
  962. outr(US1_CR, US_TXEN | US_RXEN | US_STTTO); /* Enable UART receiver and transmitter. */
  963. /* Enable UART receiver and transmitter interrupts. */
  964. outr(US1_IER, US_ENDRX | US_RXBUFF | US_TIMEOUT);
  965. NutEnterCritical();
  966. NutIrqEnable(&SIG_UART);
  967. NutExitCritical();
  968. return fp;
  969. }
  970. /*!
  971. * \brief Close the asynchronous HDLC device.
  972. *
  973. * This function is called by the low level close routine of the C runtime
  974. * library, using the _NUTDEVICE::dev_close entry.
  975. *
  976. * \param fp Pointer to a _NUTFILE structure, obtained by a previous call
  977. * to UsartOpen().
  978. *
  979. * \return 0 on success or -1 otherwise.
  980. *
  981. * \todo We may support shared open and use dev_irq as an open counter.
  982. */
  983. int AhdlcAt91Close(NUTFILE * fp)
  984. {
  985. if (fp && fp != NUTFILE_EOF) {
  986. NutHeapFree(fp);
  987. return 0;
  988. }
  989. return -1;
  990. }
  991. /*@}*/