| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537 |
- /*
- * Copyright (C) 2003-2004 by egnite Software GmbH. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*!
- * \file arch/avr/dev/ahdlcavr.c
- * \brief AVR AHDLC driver.
- *
- * \verbatim
- * $Id: ahdlcavr.c 5472 2013-12-06 00:16:28Z olereinhardt $
- * \endverbatim
- */
- #include <cfg/ahdlc.h>
- #include <cfg/arch/avr.h>
- #include <toolchain.h>
- #include <sys/atom.h>
- #include <sys/heap.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/thread.h>
- #include <dev/irqreg.h>
- #include <dev/uartavr.h>
- #include <dev/ppp.h>
- #include <dev/ahdlcavr.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <fcntl.h>
- /*!
- * \addtogroup xgAhdlcAvr
- */
- /*@{*/
- /*!
- * \name UART0 RTS Handshake Control
- *
- * UART0_RTS_BIT must be defined in arch/avr.h
- */
- #ifdef UART0_RTS_BIT
- #if (UART0_RTS_AVRPORT == AVRPORTB)
- #define UART0_RTS_PORT PORTB
- #define UART0_RTS_DDR DDRB
- #elif (UART0_RTS_AVRPORT == AVRPORTD)
- #define UART0_RTS_PORT PORTD
- #define UART0_RTS_DDR DDRD
- #elif (UART0_RTS_AVRPORT == AVRPORTE)
- #define UART0_RTS_PORT PORTE
- #define UART0_RTS_DDR DDRE
- #elif (UART0_RTS_AVRPORT == AVRPORTF)
- #define UART0_RTS_PORT PORTF
- #define UART0_RTS_DDR DDRF
- #elif (UART0_RTS_AVRPORT == AVRPORTG)
- #define UART0_RTS_PORT PORTG
- #define UART0_RTS_DDR DDRG
- #elif (UART0_RTS_AVRPORT == AVRPORTH)
- #define UART0_RTS_PORT PORTH
- #define UART0_RTS_DDR DDRH
- #endif
- #endif /* UART0_RTS_BIT */
- #ifdef UART0_DTR_BIT
- #if (UART0_DTR_AVRPORT == AVRPORTB)
- #define UART0_DTR_PORT PORTB
- #define UART0_DTR_DDR DDRB
- #elif (UART0_DTR_AVRPORT == AVRPORTD)
- #define UART0_DTR_PORT PORTD
- #define UART0_DTR_DDR DDRD
- #elif (UART0_DTR_AVRPORT == AVRPORTE)
- #define UART0_DTR_PORT PORTE
- #define UART0_DTR_DDR DDRE
- #elif (UART0_DTR_AVRPORT == AVRPORTF)
- #define UART0_DTR_PORT PORTF
- #define UART0_DTR_DDR DDRF
- #elif (UART0_DTR_AVRPORT == AVRPORTG)
- #define UART0_DTR_PORT PORTG
- #define UART0_DTR_DDR DDRG
- #elif (UART0_DTR_AVRPORT == AVRPORTH)
- #define UART0_DTR_PORT PORTH
- #define UART0_DTR_DDR DDRH
- #endif
- #endif /* UART0_DTR_BIT */
- /*!
- * \name UART1 RTS Handshake Control
- *
- * UART1_RTS_BIT must be defined in arch/avr.h
- */
- #ifdef UART1_RTS_BIT
- #if (UART1_RTS_AVRPORT == AVRPORTB)
- #define UART1_RTS_PORT PORTB
- #define UART1_RTS_DDR DDRB
- #elif (UART1_RTS_AVRPORT == AVRPORTD)
- #define UART1_RTS_PORT PORTD
- #define UART1_RTS_DDR DDRD
- #elif (UART1_RTS_AVRPORT == AVRPORTE)
- #define UART1_RTS_PORT PORTE
- #define UART1_RTS_DDR DDRE
- #elif (UART1_RTS_AVRPORT == AVRPORTF)
- #define UART1_RTS_PORT PORTF
- #define UART1_RTS_DDR DDRF
- #elif (UART1_RTS_AVRPORT == AVRPORTG)
- #define UART1_RTS_PORT PORTG
- #define UART1_RTS_DDR DDRG
- #elif (UART1_RTS_AVRPORT == AVRPORTH)
- #define UART1_RTS_PORT PORTH
- #define UART1_RTS_DDR DDRH
- #endif
- #endif /* UART1_RTS_BIT */
- #ifdef UART1_DTR_BIT
- #if (UART1_DTR_AVRPORT == AVRPORTB)
- #define UART1_DTR_PORT PORTB
- #define UART1_DTR_DDR DDRB
- #elif (UART1_DTR_AVRPORT == AVRPORTD)
- #define UART1_DTR_PORT PORTD
- #define UART1_DTR_DDR DDRD
- #elif (UART1_DTR_AVRPORT == AVRPORTE)
- #define UART1_DTR_PORT PORTE
- #define UART1_DTR_DDR DDRE
- #elif (UART1_DTR_AVRPORT == AVRPORTF)
- #define UART1_DTR_PORT PORTF
- #define UART1_DTR_DDR DDRF
- #elif (UART1_DTR_AVRPORT == AVRPORTG)
- #define UART1_DTR_PORT PORTG
- #define UART1_DTR_DDR DDRG
- #elif (UART1_DTR_AVRPORT == AVRPORTH)
- #define UART1_DTR_PORT PORTH
- #define UART1_DTR_DDR DDRH
- #endif
- #endif /* UART1_DTR_BIT */
- /*
- * FCS lookup table located in program memory space.
- */
- static const char fcstab[512] PROGMEM = {
- 0x00, 0x00, 0x11, 0x89, 0x23, 0x12, 0x32, 0x9b, 0x46, 0x24, 0x57, 0xad, 0x65, 0x36, 0x74, 0xbf,
- 0x8c, 0x48, 0x9d, 0xc1, 0xaf, 0x5a, 0xbe, 0xd3, 0xca, 0x6c, 0xdb, 0xe5, 0xe9, 0x7e, 0xf8, 0xf7,
- 0x10, 0x81, 0x01, 0x08, 0x33, 0x93, 0x22, 0x1a, 0x56, 0xa5, 0x47, 0x2c, 0x75, 0xb7, 0x64, 0x3e,
- 0x9c, 0xc9, 0x8d, 0x40, 0xbf, 0xdb, 0xae, 0x52, 0xda, 0xed, 0xcb, 0x64, 0xf9, 0xff, 0xe8, 0x76,
- 0x21, 0x02, 0x30, 0x8b, 0x02, 0x10, 0x13, 0x99, 0x67, 0x26, 0x76, 0xaf, 0x44, 0x34, 0x55, 0xbd,
- 0xad, 0x4a, 0xbc, 0xc3, 0x8e, 0x58, 0x9f, 0xd1, 0xeb, 0x6e, 0xfa, 0xe7, 0xc8, 0x7c, 0xd9, 0xf5,
- 0x31, 0x83, 0x20, 0x0a, 0x12, 0x91, 0x03, 0x18, 0x77, 0xa7, 0x66, 0x2e, 0x54, 0xb5, 0x45, 0x3c,
- 0xbd, 0xcb, 0xac, 0x42, 0x9e, 0xd9, 0x8f, 0x50, 0xfb, 0xef, 0xea, 0x66, 0xd8, 0xfd, 0xc9, 0x74,
- 0x42, 0x04, 0x53, 0x8d, 0x61, 0x16, 0x70, 0x9f, 0x04, 0x20, 0x15, 0xa9, 0x27, 0x32, 0x36, 0xbb,
- 0xce, 0x4c, 0xdf, 0xc5, 0xed, 0x5e, 0xfc, 0xd7, 0x88, 0x68, 0x99, 0xe1, 0xab, 0x7a, 0xba, 0xf3,
- 0x52, 0x85, 0x43, 0x0c, 0x71, 0x97, 0x60, 0x1e, 0x14, 0xa1, 0x05, 0x28, 0x37, 0xb3, 0x26, 0x3a,
- 0xde, 0xcd, 0xcf, 0x44, 0xfd, 0xdf, 0xec, 0x56, 0x98, 0xe9, 0x89, 0x60, 0xbb, 0xfb, 0xaa, 0x72,
- 0x63, 0x06, 0x72, 0x8f, 0x40, 0x14, 0x51, 0x9d, 0x25, 0x22, 0x34, 0xab, 0x06, 0x30, 0x17, 0xb9,
- 0xef, 0x4e, 0xfe, 0xc7, 0xcc, 0x5c, 0xdd, 0xd5, 0xa9, 0x6a, 0xb8, 0xe3, 0x8a, 0x78, 0x9b, 0xf1,
- 0x73, 0x87, 0x62, 0x0e, 0x50, 0x95, 0x41, 0x1c, 0x35, 0xa3, 0x24, 0x2a, 0x16, 0xb1, 0x07, 0x38,
- 0xff, 0xcf, 0xee, 0x46, 0xdc, 0xdd, 0xcd, 0x54, 0xb9, 0xeb, 0xa8, 0x62, 0x9a, 0xf9, 0x8b, 0x70,
- 0x84, 0x08, 0x95, 0x81, 0xa7, 0x1a, 0xb6, 0x93, 0xc2, 0x2c, 0xd3, 0xa5, 0xe1, 0x3e, 0xf0, 0xb7,
- 0x08, 0x40, 0x19, 0xc9, 0x2b, 0x52, 0x3a, 0xdb, 0x4e, 0x64, 0x5f, 0xed, 0x6d, 0x76, 0x7c, 0xff,
- 0x94, 0x89, 0x85, 0x00, 0xb7, 0x9b, 0xa6, 0x12, 0xd2, 0xad, 0xc3, 0x24, 0xf1, 0xbf, 0xe0, 0x36,
- 0x18, 0xc1, 0x09, 0x48, 0x3b, 0xd3, 0x2a, 0x5a, 0x5e, 0xe5, 0x4f, 0x6c, 0x7d, 0xf7, 0x6c, 0x7e,
- 0xa5, 0x0a, 0xb4, 0x83, 0x86, 0x18, 0x97, 0x91, 0xe3, 0x2e, 0xf2, 0xa7, 0xc0, 0x3c, 0xd1, 0xb5,
- 0x29, 0x42, 0x38, 0xcb, 0x0a, 0x50, 0x1b, 0xd9, 0x6f, 0x66, 0x7e, 0xef, 0x4c, 0x74, 0x5d, 0xfd,
- 0xb5, 0x8b, 0xa4, 0x02, 0x96, 0x99, 0x87, 0x10, 0xf3, 0xaf, 0xe2, 0x26, 0xd0, 0xbd, 0xc1, 0x34,
- 0x39, 0xc3, 0x28, 0x4a, 0x1a, 0xd1, 0x0b, 0x58, 0x7f, 0xe7, 0x6e, 0x6e, 0x5c, 0xf5, 0x4d, 0x7c,
- 0xc6, 0x0c, 0xd7, 0x85, 0xe5, 0x1e, 0xf4, 0x97, 0x80, 0x28, 0x91, 0xa1, 0xa3, 0x3a, 0xb2, 0xb3,
- 0x4a, 0x44, 0x5b, 0xcd, 0x69, 0x56, 0x78, 0xdf, 0x0c, 0x60, 0x1d, 0xe9, 0x2f, 0x72, 0x3e, 0xfb,
- 0xd6, 0x8d, 0xc7, 0x04, 0xf5, 0x9f, 0xe4, 0x16, 0x90, 0xa9, 0x81, 0x20, 0xb3, 0xbb, 0xa2, 0x32,
- 0x5a, 0xc5, 0x4b, 0x4c, 0x79, 0xd7, 0x68, 0x5e, 0x1c, 0xe1, 0x0d, 0x68, 0x3f, 0xf3, 0x2e, 0x7a,
- 0xe7, 0x0e, 0xf6, 0x87, 0xc4, 0x1c, 0xd5, 0x95, 0xa1, 0x2a, 0xb0, 0xa3, 0x82, 0x38, 0x93, 0xb1,
- 0x6b, 0x46, 0x7a, 0xcf, 0x48, 0x54, 0x59, 0xdd, 0x2d, 0x62, 0x3c, 0xeb, 0x0e, 0x70, 0x1f, 0xf9,
- 0xf7, 0x8f, 0xe6, 0x06, 0xd4, 0x9d, 0xc5, 0x14, 0xb1, 0xab, 0xa0, 0x22, 0x92, 0xb9, 0x83, 0x30,
- 0x7b, 0xc7, 0x6a, 0x4e, 0x58, 0xd5, 0x49, 0x5c, 0x3d, 0xe3, 0x2c, 0x6a, 0x1e, 0xf1, 0x0f, 0x78
- };
- /*!
- * Checks the 32-bit ACCM to see if the byte needs un-escaping
- */
- #define IN_ACC_MAP(c, m) in_acc_map(c, &(m))
- /* Trust me, this is a whole lot smaller when compiled than it looks in C.
- * It is written explicitly so that gcc can make good AVR asm out of it. */
- static NUT_INLINE_FUNC uint8_t in_acc_map(u_char ch, void * esc_mask) NUT_FORCE_INLINE; /* gcc specific attribute */
- static NUT_INLINE_FUNC uint8_t in_acc_map(u_char ch, void * esc_mask)
- {
- const uint8_t shift_mask = 0x07;
- const uint8_t index_mask = 0x18;
- const uint8_t over_mask = ~(shift_mask|index_mask);
- uint8_t shift, index, emask;
- uint8_t * emskp = esc_mask;
- if (over_mask & ch) {
- return 0;
- }
- shift = shift_mask & ch;
- index = ch >> (uint8_t)3;
- /* NOTE: This assumes that the esc bit field is little endian,
- * which it should have been switched to before being set. */
- emask = emskp[index];
- return emask & ( ((uint8_t)1) << shift );
- }
- #ifndef NUT_THREAD_AHDLCRXSTACK
- #define NUT_THREAD_AHDLCRXSTACK 512
- #endif
- #if !defined(MCU_AT90USB1287)
- /*
- * Handle AVR UART0 transmit complete interrupts.
- */
- static void Tx0Complete(void *arg)
- {
- AHDLCDCB *dcb = arg;
- if (dcb->dcb_tx_idx != dcb->dcb_wr_idx) {
- #ifdef UART0_CTS_BIT
- if (bit_is_set(UART0_CTS_PIN, UART0_CTS_BIT)) {
- cbi(UCR, UDRIE);
- return;
- }
- #endif
- outb(UDR, dcb->dcb_tx_buf[dcb->dcb_tx_idx]);
- dcb->dcb_tx_idx++;
- } else {
- cbi(UCR, UDRIE);
- NutEventPostFromIrq(&dcb->dcb_tx_rdy);
- }
- }
- #ifdef UART0_CTS_BIT
- /*
- * Handle AVR UART0 transmit handshake interrupts.
- */
- static void Cts0Interrupt(void *arg)
- {
- sbi(UCR, UDRIE);
- }
- #endif
- #endif /*!USB1287*/
- #ifdef __AVR_ENHANCED__
- /*
- * Handle AVR UART1 transmit complete interrupts.
- */
- static void Tx1Complete(void *arg)
- {
- register AHDLCDCB *dcb = arg;
- if (dcb->dcb_tx_idx != dcb->dcb_wr_idx) {
- #ifdef UART1_CTS_BIT
- if (bit_is_set(UART1_CTS_PIN, UART1_CTS_BIT)) {
- cbi(UCSR1B, UDRIE);
- return;
- }
- #endif
- outb(UDR1, dcb->dcb_tx_buf[dcb->dcb_tx_idx]);
- dcb->dcb_tx_idx++;
- } else {
- cbi(UCSR1B, UDRIE);
- NutEventPostFromIrq(&dcb->dcb_tx_rdy);
- }
- }
- #ifdef UART1_CTS_BIT
- /*
- * Handle AVR UART1 transmit handshake interrupts.
- */
- static void Cts1Interrupt(void *arg)
- {
- sbi(UCSR1B, UDRIE);
- }
- #endif
- #endif /* __AVR_ENHANCED__ */
- #if !defined(MCU_AT90USB1287)
- /*
- * Handle AVR UART0 receive complete interrupts.
- */
- static void Rx0Complete(void *arg)
- {
- AHDLCDCB *dcb = arg;
- dcb->dcb_rx_buf[dcb->dcb_rx_idx] = inb(UDR);
- if (dcb->dcb_rd_idx == dcb->dcb_rx_idx)
- NutEventPostFromIrq(&dcb->dcb_rx_rdy);
- /* Late increment fixes ICCAVR bug on volatile variables. */
- dcb->dcb_rx_idx++;
- }
- #endif /*!USB1287*/
- #ifdef __AVR_ENHANCED__
- /*
- * Handle AVR UART1 receive complete interrupts.
- */
- static void Rx1Complete(void *arg)
- {
- AHDLCDCB *dcb = arg;
- dcb->dcb_rx_buf[dcb->dcb_rx_idx] = inb(UDR1);
- if (dcb->dcb_rd_idx == dcb->dcb_rx_idx)
- NutEventPostFromIrq(&dcb->dcb_rx_rdy);
- /* Late increment fixes ICCAVR bug on volatile variables. */
- dcb->dcb_rx_idx++;
- }
- #endif /* __AVR_ENHANCED__ */
- /*
- * \return 0 on success, -1 in case of any errors.
- */
- static int SendRawByte(AHDLCDCB * dcb, uint8_t ch, uint8_t flush)
- {
- /*
- * If transmit buffer is full, wait until interrupt routine
- * signals an empty buffer or until a timeout occurs.
- */
- while ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
- if (NutEventWait(&dcb->dcb_tx_rdy, dcb->dcb_wtimeout))
- break;
- }
- /*
- * If transmit buffer is still full, we have a write timeout.
- */
- if ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
- return -1;
- }
- /*
- * Buffer has room for more data. Put the byte in the buffer
- * and increment the write index.
- */
- dcb->dcb_tx_buf[dcb->dcb_wr_idx] = ch;
- dcb->dcb_wr_idx++;
- /*
- * If transmit buffer has become full and the transmitter
- * is not active, then activate it.
- */
- if (flush || (uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
- /*
- * TODO: Check handshake.
- */
- NutEnterCritical();
- #ifdef __AVR_ENHANCED__
- if (dcb->dcb_base)
- sbi(UCSR1B, UDRIE);
- else
- #endif
- sbi(UCR, UDRIE);
- NutExitCritical();
- }
- return 0;
- }
- /*
- * Characters are properly escaped and checksum is updated.
- *
- * \return 0 on success, -1 in case of any errors.
- */
- static int SendHdlcData(AHDLCDCB * dcb, const uint8_t * data, uint16_t len, uint16_t * txfcs)
- {
- uint16_t tbx;
- register uint16_t fcs;
- if (txfcs)
- fcs = *txfcs;
- else
- fcs = 0;
- while (len) {
- tbx = (uint16_t) ((uint8_t) fcs ^ *data) << 1;
- fcs >>= 8;
- fcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
- if (IN_ACC_MAP(*data, dcb->dcb_tx_accm) || *data == AHDLC_FLAG || *data == AHDLC_ESCAPE) {
- if (SendRawByte(dcb, AHDLC_ESCAPE, 0))
- return -1;
- if (SendRawByte(dcb, *data ^ AHDLC_TRANS, 0))
- return -1;
- } else if (SendRawByte(dcb, *data, 0))
- return -1;
- data++;
- len--;
- }
- if (txfcs)
- *txfcs = fcs;
- return 0;
- }
- /*!
- * \brief Send HDLC frame.
- *
- * \param dev Identifies the device to use.
- * \param nb Network buffer structure containing the packet to be sent.
- * The structure must have been allocated by a previous
- * call NutNetBufAlloc().
- *
- * \return 0 on success, -1 in case of any errors.
- */
- int AhdlcOutput(NUTDEVICE * dev, NETBUF * nb)
- {
- uint16_t txfcs;
- AHDLCDCB *dcb = dev->dev_dcb;
- uint16_t sz;
- /*
- * If we are in RAW mode we are not allowed to send AHDLC output.
- * We just emulate packet loss behaviour in here.
- */
- if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
- return 0;
- }
- /*
- * Calculate the number of bytes to be send. Do not
- * send packets larger than transmit mru.
- */
- sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
- if (sz > dcb->dcb_tx_mru) {
- return -1;
- }
- /*
- * TODO: If transmitter is running, we may omit the flag.
- */
- SendRawByte(dcb, AHDLC_FLAG, 0);
- /* Initialize the checksum and send the NETBUF. */
- txfcs = AHDLC_INITFCS;
- if (SendHdlcData(dcb, nb->nb_dl.vp, nb->nb_dl.sz, &txfcs))
- return -1;
- if (SendHdlcData(dcb, nb->nb_nw.vp, nb->nb_nw.sz, &txfcs))
- return -1;
- if (SendHdlcData(dcb, nb->nb_tp.vp, nb->nb_tp.sz, &txfcs))
- return -1;
- if (SendHdlcData(dcb, nb->nb_ap.vp, nb->nb_ap.sz, &txfcs))
- return -1;
- /* Send the checksum and the final flag. */
- txfcs ^= 0xffff;
- if (SendHdlcData(dcb, (uint8_t *) & txfcs, 2, 0))
- return -1;
- SendRawByte(dcb, AHDLC_FLAG, 1);
- return 0;
- }
- /*! \fn AhdlcRx(void *arg)
- * \brief Asynchronous HDLC receiver thread.
- *
- *
- * Running at high priority.
- */
- THREAD(AhdlcRx, arg)
- {
- NUTDEVICE *dev = arg;
- NUTDEVICE *netdev;
- AHDLCDCB *dcb = dev->dev_dcb;
- IFNET *ifn;
- NETBUF *nb;
- uint8_t *rxbuf;
- uint8_t *rxptr;
- uint16_t rxcnt;
- uint8_t ch;
- uint16_t tbx;
- uint8_t inframe;
- uint8_t escaped;
- uint16_t rxfcs;
- NutThreadSetPriority(9);
- for (;;) {
- /*
- * Reset variables to their initial state
- */
- rxptr = 0;
- rxcnt = 0;
- escaped = 0;
- rxfcs = AHDLC_INITFCS;
- inframe = 0;
- for (;;) {
- /*
- * Wait until the network interface has been attached.
- * This will be initiated by the application calling
- * NutNetIfConfig(), which in turn calls a HDLC_SETIFNET
- * ioctl() to store the NUTDEVICE pointer of the network
- * device in dev_icb and trigger an event on dcb_mf_evt.
- */
- while ((netdev = dev->dev_icb) == 0) {
- NutEventWait(&dcb->dcb_mf_evt, 1000);
- }
- ifn = netdev->dev_icb;
- dcb->dcb_rtimeout = 1000;
- inframe = 0;
- /*
- * Allocate the receive buffer, if this fails, we are in a
- * low memory situation. Take a nap and see, if the
- * situation improved.
- * Note that we also put the FCS into the receive buffer.
- */
- if ((rxbuf = NutHeapAlloc(dcb->dcb_rx_mru + 2)) != 0) {
- break;
- }
- NutSleep(1000);
- }
- /*
- * Signal the link driver that we are up.
- */
- ifn->if_send = AhdlcOutput;
- netdev->dev_ioctl(netdev, LCP_LOWERUP, 0);
- for (;;) {
- /*
- * If we are still connected to a network, fetch the next
- * character from the buffer.
- */
- while (dcb->dcb_rd_idx == dcb->dcb_rx_idx) {
- if (dev->dev_icb == 0)
- break;
- /* TODO: Check for idle timeout. */
- if (NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout)) {
- continue;
- }
- }
- /*
- * Leave loop if network interface is detached
- */
- if (dev->dev_icb == 0)
- break;
- /*
- * If RAW mode is active, we are not allowing any data encapsulation
- * processing. So we just sleep for a while.
- */
- if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
- /*
- * It is a must to sleep here, because if we just yield it could create
- * too much processing in here and stall processing elsewhere. This gives
- * opportunity to other threads to process incoming data from USART.
- */
- NutSleep(100);
- continue;
- }
- /*
- * Read next character from input buffer
- */
- ch = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
- if (inframe) {
- if (ch != AHDLC_FLAG) {
- if (ch == AHDLC_ESCAPE) {
- escaped = 1;
- continue;
- }
- if (escaped) {
- ch ^= AHDLC_TRANS;
- escaped = 0;
- }
- /*
- * Unless the peer lied to us about the negotiated MRU,
- * we should never get a frame which is too long. If it
- * happens, toss it away and grab the next incoming one.
- */
- if (rxcnt++ < dcb->dcb_rx_mru + 2) {
- /* Update calculated checksum and store character in buffer. */
- tbx = (uint16_t) ((uint8_t) rxfcs ^ ch) << 1;
- rxfcs >>= 8;
- rxfcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
- *rxptr++ = ch;
- } else
- inframe = 0;
- continue;
- }
- if (rxcnt >= 2 && rxfcs == AHDLC_GOODFCS) {
- /*
- * If the frame checksum is valid, create a NETBUF
- * and pass it to the network specific receive handler.
- */
- rxcnt -= 2;
- if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, rxcnt)) != 0) {
- memcpy(nb->nb_dl.vp, rxbuf, rxcnt);
- (*ifn->if_recv) (netdev, nb);
- }
- }
- }
- /*
- * If frame flag is received, resync frame processing
- */
- if (ch == AHDLC_FLAG) {
- inframe = 1;
- escaped = 0;
- rxptr = rxbuf;
- rxcnt = 0;
- rxfcs = AHDLC_INITFCS;
- }
- }
- /* Signal the link driver that we are down. */
- netdev->dev_ioctl(netdev, LCP_LOWERDOWN, 0);
- /* Disconnected, clean up. */
- if (rxbuf) {
- NutHeapFree(rxbuf);
- rxbuf = 0;
- }
- }
- }
- /*
- * \param dev Indicates the UART device.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AhdlcAvrGetStatus(NUTDEVICE * dev, uint32_t * status)
- {
- AHDLCDCB *dcb = dev->dev_dcb;
- uint8_t us;
- *status = 0;
- #ifdef __AVR_ENHANCED__
- if (dev->dev_base) {
- #ifdef UART1_CTS_BIT
- if (bit_is_set(UART1_CTS_PIN, UART1_CTS_BIT))
- *status |= UART_CTSDISABLED;
- else
- *status |= UART_CTSENABLED;
- #endif
- #ifdef UART1_RTS_BIT
- if (bit_is_set(UART1_RTS_PORT, UART1_RTS_BIT))
- *status |= UART_RTSDISABLED;
- else
- *status |= UART_RTSENABLED;
- #endif
- #ifdef UART1_DTR_BIT
- if (bit_is_set(UART1_DTR_PORT, UART1_DTR_BIT))
- *status |= UART_DTRDISABLED;
- else
- *status |= UART_DTRENABLED;
- #endif
- us = inb(UCSR1A);
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_CTS_BIT
- if (bit_is_set(UART0_CTS_PIN, UART0_CTS_BIT))
- *status |= UART_CTSDISABLED;
- else
- *status |= UART_CTSENABLED;
- #endif
- #ifdef UART0_RTS_BIT
- if (bit_is_set(UART0_RTS_PORT, UART0_RTS_BIT))
- *status |= UART_RTSDISABLED;
- else
- *status |= UART_RTSENABLED;
- #endif
- #ifdef UART0_DTR_BIT
- if (bit_is_set(UART0_DTR_PORT, UART0_DTR_BIT))
- *status |= UART_DTRDISABLED;
- else
- *status |= UART_DTRENABLED;
- #endif
- us = inb(USR);
- }
- if (us & FE)
- *status |= UART_FRAMINGERROR;
- if (us & DOR)
- *status |= UART_OVERRUNERROR;
- if (dcb->dcb_tx_idx == dcb->dcb_wr_idx)
- *status |= UART_TXBUFFEREMPTY;
- if (dcb->dcb_rd_idx == dcb->dcb_rx_idx)
- *status |= UART_RXBUFFEREMPTY;
- return 0;
- }
- /*
- * \param dev Indicates the UART device.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int AhdlcAvrSetStatus(NUTDEVICE * dev, uint32_t status)
- {
- #ifdef __AVR_ENHANCED__
- if (dev->dev_base) {
- #ifdef UART1_RTS_BIT
- if (status & UART_RTSDISABLED)
- sbi(UART1_RTS_PORT, UART1_RTS_BIT);
- else if (status & UART_RTSENABLED)
- cbi(UART1_RTS_PORT, UART1_RTS_BIT);
- #endif
- #ifdef UART1_DTR_BIT
- if (status & UART_DTRDISABLED)
- sbi(UART1_DTR_PORT, UART1_DTR_BIT);
- else if (status & UART_DTRENABLED)
- cbi(UART1_DTR_PORT, UART1_DTR_BIT);
- #endif
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_RTS_BIT
- if (status & UART_RTSDISABLED)
- sbi(UART0_RTS_PORT, UART0_RTS_BIT);
- else if (status & UART_RTSENABLED)
- cbi(UART0_RTS_PORT, UART0_RTS_BIT);
- #endif
- #ifdef UART0_DTR_BIT
- if (status & UART_DTRDISABLED)
- sbi(UART0_DTR_PORT, UART0_DTR_BIT);
- else if (status & UART_DTRENABLED)
- cbi(UART0_DTR_PORT, UART0_DTR_BIT);
- #endif
- }
- return 0;
- }
- /*
- * Carefully enable UART functions.
- */
- static void AhdlcAvrEnable(uint16_t base)
- {
- NutEnterCritical();
- #ifdef __AVR_ENHANCED__
- if (base) {
- #ifdef UART1_CTS_BIT
- sbi(EIMSK, UART1_CTS_BIT);
- #endif
- outb(UCSR1B, BV(RXCIE) | BV(RXEN) | BV(TXEN));
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_CTS_BIT
- sbi(EIMSK, UART0_CTS_BIT);
- #endif
- outb(UCR, BV(RXCIE) | BV(RXEN) | BV(TXEN));
- }
- NutExitCritical();
- }
- /*
- * Carefully disable UART functions.
- */
- static void AhdlcAvrDisable(uint16_t base)
- {
- /*
- * Disable UART interrupts.
- */
- NutEnterCritical();
- #ifdef __AVR_ENHANCED__
- if (base) {
- #ifdef UART1_CTS_BIT
- cbi(EIMSK, UART1_CTS_BIT);
- #endif
- outb(UCSR1B, inb(UCSR1B) & ~(BV(RXCIE) | BV(UDRIE)));
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_CTS_BIT
- cbi(EIMSK, UART0_CTS_BIT);
- #endif
- outb(UCR, inb(UCR) & ~(BV(RXCIE) | BV(UDRIE)));
- }
- NutExitCritical();
- /*
- * Allow incoming or outgoing character to finish.
- */
- NutDelay(10);
- /*
- * Now disable UART functions.
- */
- #ifdef __AVR_ENHANCED__
- if (base)
- outb(UCSR1B, inb(UCSR1B) & ~(BV(RXEN) | BV(TXEN)));
- else
- #endif /* __AVR_ENHANCED__ */
- outb(UCR, inb(UCR) & ~(BV(RXEN) | BV(TXEN)));
- }
- /*!
- * \brief Perform on-chip UART control functions.
- *
- * \param dev Identifies the device that receives the device-control
- * function.
- * \param req Requested control function. May be set to one of the
- * following constants:
- * - UART_SETSPEED, conf points to an uint32_t value containing the baudrate.
- * - UART_GETSPEED, conf points to an uint32_t value receiving the current baudrate.
- * - UART_SETDATABITS, conf points to an uint32_t value containing the number of data bits, 5, 6, 7 or 8.
- * - UART_GETDATABITS, conf points to an uint32_t value receiving the number of data bits, 5, 6, 7 or 8.
- * - UART_SETPARITY, conf points to an uint32_t value containing the parity, 0 (no), 1 (odd) or 2 (even).
- * - UART_GETPARITY, conf points to an uint32_t value receiving the parity, 0 (no), 1 (odd) or 2 (even).
- * - UART_SETSTOPBITS, conf points to an uint32_t value containing the number of stop bits 1 or 2.
- * - UART_GETSTOPBITS, conf points to an uint32_t value receiving the number of stop bits 1 or 2.
- * - UART_SETSTATUS, conf points to an uint32_t value containing the changes for the control lines.
- * - UART_GETSTATUS, conf points to an uint32_t value receiving the state of the control lines and the device.
- * - UART_SETREADTIMEOUT, conf points to an uint32_t value containing the read timeout.
- * - UART_GETREADTIMEOUT, conf points to an uint32_t value receiving the read timeout.
- * - UART_SETWRITETIMEOUT, conf points to an uint32_t value containing the write timeout.
- * - UART_GETWRITETIMEOUT, conf points to an uint32_t value receiving the write timeout.
- * - UART_SETLOCALECHO, conf points to an uint32_t value containing 0 (off) or 1 (on).
- * - UART_GETLOCALECHO, conf points to an uint32_t value receiving 0 (off) or 1 (on).
- * - UART_SETFLOWCONTROL, conf points to an uint32_t value containing combined UART_FCTL_ values.
- * - UART_GETFLOWCONTROL, conf points to an uint32_t value containing receiving UART_FCTL_ values.
- * - UART_SETCOOKEDMODE, conf points to an uint32_t value containing 0 (off) or 1 (on).
- * - UART_GETCOOKEDMODE, conf points to an uint32_t value receiving 0 (off) or 1 (on).
- * - UART_SETRAWMODE, conf points to an uint32_t value containing 0 (off) or 1 (on).
- * - UART_GETRAWMODE, conf points to an uint32_t value receiving 0 (off) or 1 (on).
- * - HDLC_SETIFNET, conf points to a pointer containing the address of the network device's NUTDEVICE structure.
- * - HDLC_GETIFNET, conf points to a pointer receiving the address of the network device's NUTDEVICE structure.
- * - HDLC_SETTXACCM, conf points to an uint32_t value containing the ACC Map in host endian.
- * - HDLC_GETTXACCM, conf points to an uint32_t value receiving the ACC Map in host endian.
- *
- * \param conf Points to a buffer that contains any data required for
- * the given control function or receives data from that
- * function.
- * \return 0 on success, -1 otherwise.
- *
- * \warning Timeout values are given in milliseconds and are limited to
- * the granularity of the system timer.
- *
- * \note For ATmega103, only 8 data bits, 1 stop bit and no parity are allowed.
- *
- */
- int AhdlcAvrIOCtl(NUTDEVICE * dev, int req, void *conf)
- {
- int rc = 0;
- AHDLCDCB *dcb;
- void **ppv = (void **) conf;
- uint32_t *lvp = (uint32_t *) conf;
- uint8_t bv = 0;
- uint16_t sv = 0;
- uint8_t devnum;
- #if !defined(MCU_AT90USB1287)
- if (dev == 0)
- dev = &devUart0;
- #else
- if (dev == 0)
- return -1;
- #endif
- devnum = dev->dev_base;
- dcb = dev->dev_dcb;
- switch (req) {
- case UART_SETSPEED:
- AhdlcAvrDisable(devnum);
- sv = (uint16_t) ((((2UL * NutGetCpuClock()) / (*lvp * 16UL)) + 1UL) / 2UL) - 1;
- #ifdef __AVR_ENHANCED__
- if (devnum) {
- outb(UBRR1L, (uint8_t) sv);
- outb(UBRR1H, (uint8_t) (sv >> 8));
- #if !defined(MCU_AT90USB1287)
- } else {
- outb(UBRR0L, (uint8_t) sv);
- outb(UBRR0H, (uint8_t) (sv >> 8));
- #endif
- }
- #else
- outb(UBRR, (uint8_t) sv);
- #endif
- AhdlcAvrEnable(devnum);
- break;
- case UART_GETSPEED:
- #ifdef __AVR_ENHANCED__
- if (devnum)
- sv = (uint16_t) inb(UBRR1H) << 8 | inb(UBRR1L);
- #if !defined(MCU_AT90USB1287)
- else
- sv = (uint16_t) inb(UBRR0H) << 8 | inb(UBRR0L);
- #endif
- #else
- sv = inb(UBRR);
- #endif
- *lvp = NutGetCpuClock() / (16UL * (uint32_t) (sv + 1));
- break;
- case UART_SETDATABITS:
- AhdlcAvrDisable(devnum);
- bv = (uint8_t)(*lvp);
- #ifdef __AVR_ENHANCED__
- if (bv >= 5 && bv <= 8) {
- bv = (bv - 5) << 1;
- if (devnum) {
- outb(UCSR1C, (inb(UCSR1C) & 0xF9) | bv);
- outb(UCSR1B, inb(UCSR1B) & 0xFB);
- #if !defined(MCU_AT90USB1287)
- } else {
- outb(UCSR0C, (inb(UCSR0C) & 0xF9) | bv);
- outb(UCSR0B, inb(UCSR0B) & 0xFB);
- #endif
- }
- } else
- rc = -1;
- #else
- if (bv != 8)
- rc = -1;
- #endif
- AhdlcAvrEnable(devnum);
- break;
- case UART_GETDATABITS:
- #ifdef __AVR_ENHANCED__
- if (devnum)
- *lvp = ((inb(UCSR1C) & 0x06) >> 1) + 5;
- #if !defined(MCU_AT90USB1287)
- else
- *lvp = ((inb(UCSR0C) & 0x06) >> 1) + 5;
- #endif
- #else
- *lvp = 8;
- #endif
- break;
- case UART_SETPARITY:
- AhdlcAvrDisable(devnum);
- bv = (uint8_t)(*lvp);
- #ifdef __AVR_ENHANCED__
- if (bv <= 2) {
- if (bv == 1)
- bv = 3;
- bv <<= 4;
- if (devnum)
- outb(UCSR1C, (inb(UCSR1C) & 0xCF) | bv);
- #if !defined(MCU_AT90USB1287)
- else
- outb(UCSR0C, (inb(UCSR0C) & 0xCF) | bv);
- #endif
- } else
- rc = -1;
- #endif
- if (bv)
- rc = -1;
- AhdlcAvrEnable(devnum);
- break;
- case UART_GETPARITY:
- #ifdef __AVR_ENHANCED__
- if (devnum)
- bv = (inb(UCSR1C) & 0x30) >> 4;
- #if !defined(MCU_AT90USB1287)
- else
- bv = (inb(UCSR0C) & 0x30) >> 4;
- #endif
- if (bv == 3)
- bv = 1;
- #else
- bv = 0;
- #endif
- *lvp = bv;
- break;
- case UART_SETSTOPBITS:
- AhdlcAvrDisable(devnum);
- bv = (uint8_t)(*lvp);
- #ifdef __AVR_ENHANCED__
- if (bv == 1 || bv == 2) {
- bv = (bv - 1) << 3;
- if (devnum)
- outb(UCSR1C, (inb(UCSR1C) & 0xF7) | bv);
- #if !defined(MCU_AT90USB1287)
- else
- outb(UCSR0C, (inb(UCSR0C) & 0xF7) | bv);
- #endif
- } else
- rc = -1;
- #else
- if (bv != 1)
- rc = -1;
- #endif
- AhdlcAvrEnable(devnum);
- break;
- case UART_GETSTOPBITS:
- #ifdef __AVR_ENHANCED__
- if (devnum)
- *lvp = ((inb(UCSR1C) & 0x08) >> 3) + 1;
- #if !defined(MCU_AT90USB1287)
- else
- *lvp = ((inb(UCSR0C) & 0x08) >> 3) + 1;
- #endif
- #else
- *lvp = 1;
- #endif
- break;
- case UART_GETSTATUS:
- AhdlcAvrGetStatus(dev, lvp);
- break;
- case UART_SETSTATUS:
- AhdlcAvrSetStatus(dev, *lvp);
- break;
- case UART_SETREADTIMEOUT:
- dcb->dcb_rtimeout = *lvp;
- break;
- case UART_GETREADTIMEOUT:
- *lvp = dcb->dcb_rtimeout;
- break;
- case UART_SETWRITETIMEOUT:
- dcb->dcb_wtimeout = *lvp;
- break;
- case UART_GETWRITETIMEOUT:
- *lvp = dcb->dcb_wtimeout;
- break;
- case UART_SETLOCALECHO:
- bv = (uint8_t)(*lvp);
- if (bv)
- dcb->dcb_modeflags |= UART_MF_LOCALECHO;
- else
- dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
- break;
- case UART_GETLOCALECHO:
- if (dcb->dcb_modeflags & UART_MF_LOCALECHO)
- *lvp = 1;
- else
- *lvp = 0;
- break;
- case UART_SETFLOWCONTROL:
- bv = (uint8_t)(*lvp);
- if (bv)
- dcb->dcb_modeflags |= UART_MF_LOCALECHO;
- else
- dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
- break;
- case UART_GETFLOWCONTROL:
- break;
- case UART_SETRAWMODE:
- bv = (uint8_t)(*lvp);
- if (bv)
- dcb->dcb_modeflags |= UART_MF_RAWMODE;
- else
- dcb->dcb_modeflags &= ~UART_MF_RAWMODE;
- break;
- case UART_GETRAWMODE:
- if (dcb->dcb_modeflags & UART_MF_RAWMODE)
- *lvp = 1;
- else
- *lvp = 0;
- break;
- case HDLC_SETIFNET:
- if (ppv && (*ppv != 0)) {
- dev->dev_icb = *ppv;
- dev->dev_type = IFTYP_NET;
- dcb->dcb_rx_mru = dcb->dcb_tx_mru = ((IFNET *)(((NUTDEVICE *)ppv)->dev_icb))->if_mtu;
- NutEventPost(&dcb->dcb_mf_evt);
- } else {
- dev->dev_type = IFTYP_CHAR;
- if (dev->dev_icb != 0)
- {
- dev->dev_icb = 0;
- /*
- * Signal AHDLC Thread, so it can change it's state instantly
- */
- NutEventPost(&dcb->dcb_rx_rdy);
- }
- }
- break;
- case HDLC_GETIFNET:
- *ppv = dev->dev_icb;
- break;
- /* AVR host endian is little endian, and the ACCM should have been switched
- * to host endian when the value was read in. */
- case HDLC_SETTXACCM:
- dcb->dcb_tx_accm = (*lvp);
- break;
- case HDLC_GETTXACCM:
- (*lvp) = dcb->dcb_tx_accm;
- break;
- default:
- rc = -1;
- break;
- }
- return rc;
- }
- /*!
- * \brief Initialize asynchronous HDLC device.
- *
- * This function will be called during device registration. It
- * initializes the hardware, registers all required interrupt
- * handlers and initializes all internal data structures used by
- * this driver.
- *
- * \param dev Identifies the device to initialize.
- *
- * \return 0 on success, -1 otherwise.
- */
- int AhdlcAvrInit(NUTDEVICE * dev)
- {
- int rc = 0;
- AHDLCDCB *dcb;
- uint32_t baudrate = 9600;
- /* Disable UART. */
- AhdlcAvrDisable(dev->dev_base);
- /* Initialize driver control block. */
- dcb = dev->dev_dcb;
- memset(dcb, 0, sizeof(AHDLCDCB));
- dcb->dcb_base = dev->dev_base;
- dcb->dcb_rx_buf = NutHeapAlloc(256);
- dcb->dcb_tx_buf = NutHeapAlloc(256);
- dcb->dcb_rx_mru = dcb->dcb_tx_mru = ((IFNET *)dev->dev_icb)->if_mtu;
- dcb->dcb_tx_accm = 0xFFFFFFFF;
- /*
- * Initialize UART handshake hardware and register interrupt handlers.
- */
- if (dev->dev_base) {
- #ifdef __AVR_ENHANCED__
- #ifdef UART1_CTS_BIT
- sbi(UART1_CTS_PORT, UART1_CTS_BIT);
- cbi(UART1_CTS_DDR, UART1_CTS_BIT);
- /* Falling edge will generate interrupts. */
- #if UART1_CTS_BIT == 4
- sbi(EICR, 1);
- #elif UART1_CTS_BIT == 5
- sbi(EICR, 3);
- #elif UART1_CTS_BIT == 6
- sbi(EICR, 5);
- #elif UART1_CTS_BIT == 7
- sbi(EICR, 7);
- #endif
- #endif
- #ifdef UART1_RTS_BIT
- sbi(UART1_RTS_PORT, UART1_RTS_BIT);
- sbi(UART1_RTS_DDR, UART1_RTS_BIT);
- #endif
- #ifdef UART1_DTR_BIT
- sbi(UART1_DTR_PORT, UART1_DTR_BIT);
- sbi(UART1_DTR_DDR, UART1_DTR_BIT);
- #endif
- if (NutRegisterIrqHandler(&sig_UART1_RECV, Rx1Complete, dcb))
- rc = -1;
- else if (NutRegisterIrqHandler(&sig_UART1_DATA, Tx1Complete, dcb))
- #ifdef UART1_CTS_BIT
- rc = -1;
- else if (NutRegisterIrqHandler(&UART1_CTS_SIGNAL, Cts1Interrupt, dev))
- #endif
- #endif /* __AVR_ENHANCED__ */
- rc = -1;
- } else {
- #if defined(MCU_AT90USB1287)
- rc = -1;
- #else
- #ifdef UART0_CTS_BIT
- sbi(UART0_CTS_PORT, UART0_CTS_BIT);
- cbi(UART0_CTS_DDR, UART0_CTS_BIT);
- #if UART0_CTS_BIT == 4
- sbi(EICR, 1);
- #elif UART0_CTS_BIT == 5
- sbi(EICR, 3);
- #elif UART0_CTS_BIT == 6
- sbi(EICR, 5);
- #elif UART0_CTS_BIT == 7
- sbi(EICR, 7);
- #endif
- #endif
- #ifdef UART0_RTS_BIT
- sbi(UART0_RTS_PORT, UART0_RTS_BIT);
- sbi(UART0_RTS_DDR, UART0_RTS_BIT);
- #endif
- #ifdef UART0_DTR_BIT
- sbi(UART0_DTR_PORT, UART0_DTR_BIT);
- sbi(UART0_DTR_DDR, UART0_DTR_BIT);
- #endif
- if (NutRegisterIrqHandler(&sig_UART0_RECV, Rx0Complete, dcb))
- rc = -1;
- else if (NutRegisterIrqHandler(&sig_UART0_DATA, Tx0Complete, dcb))
- rc = -1;
- #ifdef UART0_CTS_BIT
- else if (NutRegisterIrqHandler(&UART0_CTS_SIGNAL, Cts0Interrupt, dev))
- rc = -1;
- #endif
- #endif
- }
- /*
- * If we have been successful so far, start the HDLC receiver thread,
- * set the initial baudrate and enable the UART.
- */
- if (rc == 0 && NutThreadCreate("ahdlcrx", AhdlcRx, dev,
- (NUT_THREAD_AHDLCRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) {
- AhdlcAvrIOCtl(dev, UART_SETSPEED, &baudrate);
- return 0;
- }
- /* We failed, clean up. */
- if (dcb->dcb_rx_buf)
- NutHeapFree((void *) dcb->dcb_rx_buf);
- if (dcb->dcb_tx_buf)
- NutHeapFree((void *) dcb->dcb_tx_buf);
- return -1;
- }
- /*!
- * \brief Read from the asynchronous HDLC device.
- *
- * This function is called by the low level input routines of the
- * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_read
- * entry.
- *
- * The function may block the calling thread until at least one
- * character has been received or a timeout occurs.
- *
- * It is recommended to set a proper read timeout with software handshake.
- * In this case a timeout may occur, if the communication peer lost our
- * last XON character. The application may then use ioctl() to disable the
- * receiver and do the read again. This will send out another XON.
- *
- * \param fp Pointer to a \ref _NUTFILE structure, obtained by a
- * previous call to AhdlcOpen().
- * \param buffer Pointer to the buffer that receives the data. If zero,
- * then all characters in the input buffer will be
- * removed.
- * \param size Maximum number of bytes to read.
- *
- * \return The number of bytes read, which may be less than the number
- * of bytes specified. A return value of -1 indicates an error,
- * while zero is returned in case of a timeout.
- */
- int AhdlcAvrRead(NUTFILE * fp, void *buffer, int size)
- {
- int rc = 0;
- AHDLCDCB *dcb = fp->nf_dev->dev_dcb;
- uint8_t *cp = buffer;
- /*
- * Get characters from receive buffer.
- */
- if (buffer) {
- while (rc < size) {
- if (dcb->dcb_rd_idx != dcb->dcb_rx_idx) {
- *cp++ = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
- rc++;
- } else if (rc || NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout))
- break;
- }
- }
- /*
- * Call without data buffer discards receive buffer.
- */
- else
- dcb->dcb_rd_idx = dcb->dcb_rx_idx;
- return rc;
- }
- /*!
- * \brief Write to the asynchronous HDLC device.
- *
- * \param dev Pointer to a previously registered NUTDEVICE structure.
- * \param buffer Pointer the data to write.
- * \param len Number of data bytes to write.
- * \param pflg If this flag is set, then the buffer is located in program
- * space.
- *
- * \return The number of bytes written. In case of a write timeout, this
- * may be less than the specified length.
- */
- int AhdlcAvrPut(NUTDEVICE * dev, const void *buffer, int len, int pflg)
- {
- int rc = 0;
- AHDLCDCB *dcb = dev->dev_dcb;
- const uint8_t *cp = buffer;
- /*
- * Put characters in transmit buffer.
- */
- if (buffer) {
- while (rc < len) {
- if (SendRawByte(dcb, pflg ? PRG_RDB(cp) : *cp, 0))
- break;
- cp++;
- rc++;
- }
- }
- /*
- * Call without data pointer starts transmission.
- */
- else {
- /*
- * TODO: Check handshake.
- */
- #ifdef __AVR_ENHANCED__
- if (dev->dev_base)
- sbi(UCSR1B, UDRIE);
- else
- #endif
- sbi(UCR, UDRIE);
- }
- return rc;
- }
- /*!
- * \brief Write to the asynchronous HDLC device.
- *
- * This function is called by the low level output routines of the
- * \ref xrCrtLowio "C runtime library", using the
- * \ref _NUTDEVICE::dev_write entry.
- *
- * The function may block the calling thread.
- *
- * \param fp Pointer to a _NUTFILE structure, obtained by a previous
- * call to AhldcOpen().
- * \param buffer Pointer to the data to be written. If zero, then the
- * output buffer will be flushed.
- * \param len Number of bytes to write.
- *
- * \return The number of bytes written, which may be less than the number
- * of bytes specified if a timeout occured. A return value of -1
- * indicates an error.
- */
- int AhdlcAvrWrite(NUTFILE * fp, const void *buffer, int len)
- {
- return AhdlcAvrPut(fp->nf_dev, buffer, len, 0);
- }
- /*!
- * \brief Write to the asynchronous HDLC device.
- *
- * Similar to AhdlcWrite() except that the data is located in program
- * memory.
- *
- * This function is called by the low level output routines of the
- * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_write_P
- * entry.
- *
- * The function may block the calling thread.
- *
- * \param fp Pointer to a NUTFILE structure, obtained by a previous
- * call to AhdlcOpen().
- * \param buffer Pointer to the data in program space to be written.
- * \param len Number of bytes to write.
- *
- * \return The number of bytes written, which may be less than the number
- * of bytes specified if a timeout occured. A return value of -1
- * indicates an error.
- */
- int AhdlcAvrWrite_P(NUTFILE * fp, PGM_P buffer, int len)
- {
- return AhdlcAvrPut(fp->nf_dev, (const char *) buffer, len, 1);
- }
- /*!
- * \brief Open the asynchronous HDLC device.
- *
- * This function is called by the low level open routine of the C runtime
- * library, using the _NUTDEVICE::dev_open entry.
- *
- * \param dev Pointer to the NUTDEVICE structure.
- * \param name Ignored, should point to an empty string.
- * \param mode Operation mode. Any of the following values may be or-ed:
- * - \ref _O_BINARY
- * - \ref _O_RDONLY
- * - \ref _O_WRONLY
- * \param acc Ignored, should be zero.
- *
- * \return Pointer to a NUTFILE structure if successful or NUTFILE_EOF otherwise.
- */
- NUTFILE *AhdlcAvrOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
- {
- NUTFILE *fp;
- if ((fp = NutHeapAlloc(sizeof(NUTFILE))) == 0)
- return NUTFILE_EOF;
- fp->nf_dev = dev;
- fp->nf_fcb = NULL;
- /* Enable handshake outputs. */
- #ifdef __AVR_ENHANCED__
- if (dev->dev_base) {
- #ifdef UART1_RTS_BIT
- cbi(UART1_RTS_PORT, UART1_RTS_BIT);
- #endif
- #ifdef UART1_DTR_BIT
- cbi(UART1_DTR_PORT, UART1_DTR_BIT);
- #endif
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_RTS_BIT
- cbi(UART0_RTS_PORT, UART0_RTS_BIT);
- #endif
- #ifdef UART0_DTR_BIT
- cbi(UART0_DTR_PORT, UART0_DTR_BIT);
- #endif
- }
- return fp;
- }
- /*!
- * \brief Close the asynchronous HDLC device.
- *
- * This function is called by the low level close routine of the C runtime
- * library, using the _NUTDEVICE::dev_close entry.
- *
- * \param fp Pointer to a _NUTFILE structure, obtained by a previous call
- * to UsartOpen().
- *
- * \return 0 on success or -1 otherwise.
- *
- * \todo We may support shared open and use dev_irq as an open counter.
- */
- int AhdlcAvrClose(NUTFILE * fp)
- {
- if (fp && fp != NUTFILE_EOF) {
- /* Disable handshake outputs. */
- #ifdef __AVR_ENHANCED__
- if (fp->nf_dev->dev_base) {
- #ifdef UART1_RTS_BIT
- sbi(UART1_RTS_PORT, UART1_RTS_BIT);
- #endif
- #ifdef UART1_DTR_BIT
- sbi(UART1_DTR_PORT, UART1_DTR_BIT);
- #endif
- } else
- #endif /* __AVR_ENHANCED__ */
- {
- #ifdef UART0_RTS_BIT
- sbi(UART0_RTS_PORT, UART0_RTS_BIT);
- #endif
- #ifdef UART0_DTR_BIT
- sbi(UART0_DTR_PORT, UART0_DTR_BIT);
- #endif
- }
- NutHeapFree(fp);
- return 0;
- }
- return -1;
- }
- /*@}*/
|