| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020 |
- //*****************************************************************************
- //
- // usbdcdc.c - USB CDC ACM (serial) device class driver.
- //
- // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
- // Software License Agreement
- //
- // Texas Instruments (TI) is supplying this software for use solely and
- // exclusively on TI's microcontroller products. The software is owned by
- // TI and/or its suppliers, and is protected under applicable copyright
- // laws. You may not combine this software with "viral" open-source
- // software in order to form a larger program.
- //
- // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
- // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
- // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
- // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
- // DAMAGES, FOR ANY REASON WHATSOEVER.
- //
- // This is part of AM1808 StarterWare USB Library and reused from revision 6288
- // of the Stellaris USB Library.
- //
- //*****************************************************************************
- #include "hw_usb.h"
- #include "hw_types.h"
- #include "debug.h"
- #include "interrupt.h"
- #include "usb.h"
- #include "usblib.h"
- #include "usbdevice.h"
- #include "usbcdc.h"
- #include "usbdcdc.h"
- #include "usbdcomp.h"
- #include "usblibpriv.h"
- //*****************************************************************************
- //
- //! \addtogroup cdc_device_class_api
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // Some assumptions and deviations from the CDC specification
- // ----------------------------------------------------------
- //
- // 1. Although the CDC specification indicates that the following requests
- // should be supported by ACM CDC devices, these don't seem relevant to a
- // virtual COM port implementation and are never seen when connecting to a
- // Windows host and running either Hyperterminal or TeraTerm. As a result,
- // this implementation does not support them and stalls endpoint 0 if they are
- // received.
- // - SEND_ENCAPSULATED_COMMAND
- // - GET_ENCAPSULATED_RESPONSE
- // - SET_COMM_FEATURE
- // - GET_COMM_FEATURE
- // - CLEAR_COMM_FEATURE
- //
- // 2. The CDC specification is very clear on the fact that an ACM device
- // should offer two interfaces - a control interface offering an interrupt IN
- // endpoint and a data interface offering bulk IN and OUT endpoints. Using
- // this descriptor configuration, however, Windows insists on enumerating the
- // device as two separate entities resulting in two virtual COM ports or one
- // COM port and an Unknown Device (depending upon INF contents) appearing
- // in Device Manager. This implementation, derived by experimentation and
- // examination of other virtual COM and CDC solutions, uses only a single
- // interface combining all three endpoints. This appears to satisfy
- // Windows2000, XP and Vista and operates as intended using the Hyperterminal
- // and TeraTerm terminal emulators. Your mileage may vary with other
- // (untested) operating systems!
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // The subset of endpoint status flags that we consider to be reception
- // errors. These are passed to the client via USB_EVENT_ERROR if seen.
- //
- //*****************************************************************************
- #define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
- USBERR_DEV_RX_OVERRUN | \
- USBERR_DEV_RX_FIFO_FULL)
- //*****************************************************************************
- //
- // Size of the buffer to hold request-specific data read from the host. This
- // must be sized to accommodate the largest request structure that we intend
- // processing.
- //
- //*****************************************************************************
- #define MAX_REQUEST_DATA_SIZE sizeof(tLineCoding)
- //*****************************************************************************
- //This macro is used to diable the bit band operartion. Need to undefine this macro to use the
- // bit band operation.
- //***************************************************************************
- #define DISABLE_BIT_BAND
- //*****************************************************************************
- //
- // Flags that may appear in usDeferredOpFlags to indicate some operation that
- // has been requested but could not be processed at the time it was received.
- //
- //*****************************************************************************
- #define CDC_DO_SERIAL_STATE_CHANGE 0
- #define CDC_DO_SEND_BREAK 1
- #define CDC_DO_CLEAR_BREAK 2
- #define CDC_DO_LINE_CODING_CHANGE 3
- #define CDC_DO_LINE_STATE_CHANGE 4
- #define CDC_DO_PACKET_RX 5
- //*****************************************************************************
- //
- // The subset of deferred operations which result in the receive channel
- // being blocked.
- //
- //*****************************************************************************
- #define RX_BLOCK_OPS ((1 << CDC_DO_SEND_BREAK) | \
- (1 << CDC_DO_LINE_CODING_CHANGE) | \
- (1 << CDC_DO_LINE_STATE_CHANGE))
- //*****************************************************************************
- //
- // Macros to convert between USB controller base address and an index. These
- // are currently trivial but are included to allow for the possibility of
- // supporting more than one controller in the future.
- //
- //*****************************************************************************
- #if (USB_NUM_INSTANCE == 2)
- #define USB_BASE_TO_INDEX(BaseAddr, index) do{ \
- if(USB0_BASE==BaseAddr) \
- index = 0; \
- else if(USB1_BASE==BaseAddr) \
- index = 1; \
- else \
- index = -1; \
- }while(0)
- #define USB_INDEX_TO_BASE(Index, BaseAddr) ( \
- if(0==Index) \
- BaseAddr = USB0_BASE; \
- else if(1==Index) \
- BaseAddr = USB1_BASE; \
- else \
- BaseAddr = -1; \
- )
- #else
- #define USB_BASE_TO_INDEX(BaseAddr, index) do{ \
- if(USB0_BASE==BaseAddr) \
- index = 0; \
- else \
- index = -1; \
- }while(0)
- #define USB_INDEX_TO_BASE(Index, BaseAddr) ( \
- if(0==Index) \
- BaseAddr = USB0_BASE; \
- else \
- BaseAddr = -1; \
- )
- #endif
- //*****************************************************************************
- //
- // Endpoints to use for each of the required endpoints in the driver.
- //
- //*****************************************************************************
- #define CONTROL_ENDPOINT USB_EP_1
- #define DATA_IN_ENDPOINT USB_EP_2
- #define DATA_OUT_ENDPOINT USB_EP_1
- //*****************************************************************************
- //
- // The following are the USB interface numbers for the CDC serial device.
- //
- //*****************************************************************************
- #define SERIAL_INTERFACE_CONTROL 0
- #define SERIAL_INTERFACE_DATA 1
- //*****************************************************************************
- //
- // Maximum packet size for the bulk endpoints used for serial data
- // transmission and reception and the associated FIFO sizes to set aside
- // for each endpoint.
- //
- //*****************************************************************************
- #define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
- #define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
- #define CTL_IN_EP_FIFO_SIZE USB_FIFO_SZ_16
- #define DATA_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
- #define DATA_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
- #define CTL_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(CTL_IN_EP_FIFO_SIZE)
- //*****************************************************************************
- //
- // The collection of serial state flags indicating character errors.
- //
- //*****************************************************************************
- #define USB_CDC_SERIAL_ERRORS (USB_CDC_SERIAL_STATE_OVERRUN | \
- USB_CDC_SERIAL_STATE_PARITY | \
- USB_CDC_SERIAL_STATE_FRAMING)
- //*****************************************************************************
- //
- // USB instance Object
- //
- //*****************************************************************************
- extern tUSBInstanceObject g_USBInstance[];
- //*****************************************************************************
- //
- // Device Descriptor. This is stored in RAM to allow several fields to be
- // changed at runtime based on the client's requirements.
- //
- //*****************************************************************************
- unsigned char g_pCDCSerDeviceDescriptor[] =
- {
- 18, // Size of this structure.
- USB_DTYPE_DEVICE, // Type of this structure.
- USBShort(0x200), // USB version 1.1 (if we say 2.0, hosts assume
- // high-speed - see USB 2.0 spec 9.2.6.6)
- USB_CLASS_CDC, // USB Device Class (spec 5.1.1)
- 0, // USB Device Sub-class (spec 5.1.1)
- USB_CDC_PROTOCOL_NONE, // USB Device protocol (spec 5.1.1)
- 64, // Maximum packet size for default pipe.
- USBShort(0), // Vendor ID (filled in during USBDCDCInit).
- USBShort(0), // Product ID (filled in during USBDCDCInit).
- USBShort(0x100), // Device Version BCD.
- 1, // Manufacturer string identifier.
- 2, // Product string identifier.
- 3, // Product serial number.
- 1 // Number of configurations.
- };
- //*****************************************************************************
- //
- // CDC Serial configuration descriptor.
- //
- // It is vital that the configuration descriptor bConfigurationValue field
- // (byte 6) is 1 for the first configuration and increments by 1 for each
- // additional configuration defined here. This relationship is assumed in the
- // device stack for simplicity even though the USB 2.0 specification imposes
- // no such restriction on the bConfigurationValue values.
- //
- // Note that this structure is deliberately located in RAM since we need to
- // be able to patch some values in it based on client requirements.
- //
- //*****************************************************************************
- unsigned char g_pCDCSerDescriptor[] =
- {
- //
- // Configuration descriptor header.
- //
- 9, // Size of the configuration descriptor.
- USB_DTYPE_CONFIGURATION, // Type of this descriptor.
- USBShort(9), // The total size of this full structure, this
- // will be patched so it is just set to the
- // size of this structure.
- 2, // The number of interfaces in this
- // configuration.
- 1, // The unique value for this configuration.
- 5, // The string identifier that describes this
- // configuration.
- USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
- 250, // The maximum power in 2mA increments.
- };
- const tConfigSection g_sCDCSerConfigSection =
- {
- sizeof(g_pCDCSerDescriptor),
- g_pCDCSerDescriptor
- };
- //*****************************************************************************
- //
- // This is the Interface Association Descriptor for the serial device used in
- // composite devices.
- //
- //*****************************************************************************
- unsigned char g_pIADSerDescriptor[] =
- {
- 8, // Size of the interface descriptor.
- USB_DTYPE_INTERFACE_ASC, // Interface Association Type.
- 0x0, // Default starting interface is 0.
- 0x2, // Number of interfaces in this association.
- USB_CLASS_CDC, // The device class for this association.
- USB_CDC_SUBCLASS_ABSTRACT_MODEL, // The device subclass for this
- // association.
- USB_CDC_PROTOCOL_V25TER, // The protocol for this association.
- 0 // The string index for this association.
- };
- const tConfigSection g_sIADSerConfigSection =
- {
- sizeof(g_pIADSerDescriptor),
- g_pIADSerDescriptor
- };
- //*****************************************************************************
- //
- // This is the control interface for the serial device.
- //
- //*****************************************************************************
- const unsigned char g_pCDCSerCommInterface[] =
- {
- //
- // Communication Class Interface Descriptor.
- //
- 9, // Size of the interface descriptor.
- USB_DTYPE_INTERFACE, // Type of this descriptor.
- SERIAL_INTERFACE_CONTROL, // The index for this interface.
- 0, // The alternate setting for this interface.
- 1, // The number of endpoints used by this
- // interface.
- USB_CLASS_CDC, // The interface class constant defined by
- // USB-IF (spec 5.1.3).
- USB_CDC_SUBCLASS_ABSTRACT_MODEL, // The interface sub-class constant
- // defined by USB-IF (spec 5.1.3).
- USB_CDC_PROTOCOL_V25TER, // The interface protocol for the sub-class
- // specified above.
- 4, // The string index for this interface.
- //
- // Communication Class Interface Functional Descriptor - Header
- //
- 5, // Size of the functional descriptor.
- USB_CDC_CS_INTERFACE, // CDC interface descriptor
- USB_CDC_FD_SUBTYPE_HEADER, // Header functional descriptor
- USBShort(0x110), // Complies with CDC version 1.1
- //
- // Communication Class Interface Functional Descriptor - ACM
- //
- 4, // Size of the functional descriptor.
- USB_CDC_CS_INTERFACE, // CDC interface descriptor
- USB_CDC_FD_SUBTYPE_ABSTRACT_CTL_MGMT,
- USB_CDC_ACM_SUPPORTS_LINE_PARAMS | USB_CDC_ACM_SUPPORTS_SEND_BREAK,
- //
- // Communication Class Interface Functional Descriptor - Unions
- //
- 5, // Size of the functional descriptor.
- USB_CDC_CS_INTERFACE, // CDC interface descriptor
- USB_CDC_FD_SUBTYPE_UNION,
- SERIAL_INTERFACE_CONTROL,
- SERIAL_INTERFACE_DATA, // Data interface number
- //
- // Communication Class Interface Functional Descriptor - Call Management
- //
- 5, // Size of the functional descriptor.
- USB_CDC_CS_INTERFACE, // CDC interface descriptor
- USB_CDC_FD_SUBTYPE_CALL_MGMT,
- USB_CDC_CALL_MGMT_HANDLED,
- SERIAL_INTERFACE_DATA, // Data interface number
- //
- // Endpoint Descriptor (interrupt, IN)
- //
- 7, // The size of the endpoint descriptor.
- USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
- USB_EP_DESC_IN | USB_EP_TO_INDEX(CONTROL_ENDPOINT),
- USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
- USBShort(CTL_IN_EP_MAX_SIZE), // The maximum packet size.
- 10 // The polling interval for this endpoint.
- };
- const tConfigSection g_sCDCSerCommInterfaceSection =
- {
- sizeof(g_pCDCSerCommInterface),
- g_pCDCSerCommInterface
- };
- //*****************************************************************************
- //
- // This is the Data interface for the serial device.
- //
- //*****************************************************************************
- const unsigned char g_pCDCSerDataInterface[] =
- {
- //
- // Communication Class Data Interface Descriptor.
- //
- 9, // Size of the interface descriptor.
- USB_DTYPE_INTERFACE, // Type of this descriptor.
- SERIAL_INTERFACE_DATA, // The index for this interface.
- 0, // The alternate setting for this interface.
- 2, // The number of endpoints used by this
- // interface.
- USB_CLASS_CDC_DATA, // The interface class constant defined by
- // USB-IF (spec 5.1.3).
- 0, // The interface sub-class constant
- // defined by USB-IF (spec 5.1.3).
- USB_CDC_PROTOCOL_NONE, // The interface protocol for the sub-class
- // specified above.
- 0, // The string index for this interface.
- //
- // Endpoint Descriptor
- //
- 7, // The size of the endpoint descriptor.
- USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
- USB_EP_DESC_IN | USB_EP_TO_INDEX(DATA_IN_ENDPOINT),
- USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
- USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
- 0, // The polling interval for this endpoint.
- //
- // Endpoint Descriptor
- //
- 7, // The size of the endpoint descriptor.
- USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
- USB_EP_DESC_OUT | USB_EP_TO_INDEX(DATA_OUT_ENDPOINT),
- USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
- USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
- 0, // The polling interval for this endpoint.
- };
- const tConfigSection g_sCDCSerDataInterfaceSection =
- {
- sizeof(g_pCDCSerDataInterface),
- g_pCDCSerDataInterface
- };
- //*****************************************************************************
- //
- // This array lists all the sections that must be concatenated to make a
- // single, complete CDC ACM configuration descriptor.
- //
- //*****************************************************************************
- const tConfigSection *g_psCDCSerSections[] =
- {
- &g_sCDCSerConfigSection,
- &g_sCDCSerCommInterfaceSection,
- &g_sCDCSerDataInterfaceSection,
- };
- #define NUM_CDCSER_SECTIONS (sizeof(g_psCDCSerSections) / \
- sizeof(tConfigSection *))
- //*****************************************************************************
- //
- // The header for the single configuration. This is the root of the data
- // structure that defines all the bits and pieces that are pulled together to
- // generate the configuration descriptor.
- //
- //*****************************************************************************
- const tConfigHeader g_sCDCSerConfigHeader =
- {
- NUM_CDCSER_SECTIONS,
- g_psCDCSerSections
- };
- //*****************************************************************************
- //
- // This array lists all the sections that must be concatenated to make a
- // single, complete CDC ACM configuration descriptor used in composite devices.
- // The only addition is the g_sIADSerConfigSection.
- //
- //*****************************************************************************
- const tConfigSection *g_psCDCCompSerSections[] =
- {
- &g_sCDCSerConfigSection,
- &g_sIADSerConfigSection,
- &g_sCDCSerCommInterfaceSection,
- &g_sCDCSerDataInterfaceSection,
- };
- #define NUM_COMP_CDCSER_SECTIONS (sizeof(g_psCDCCompSerSections) / \
- sizeof(tConfigSection *))
- //*****************************************************************************
- //
- // The header for the composite configuration. This is the root of the data
- // structure that defines all the bits and pieces that are pulled together to
- // generate the configuration descriptor.
- //
- //*****************************************************************************
- const tConfigHeader g_sCDCCompSerConfigHeader =
- {
- NUM_COMP_CDCSER_SECTIONS,
- g_psCDCCompSerSections
- };
- //*****************************************************************************
- //
- // Configuration Descriptor for the CDC serial class device.
- //
- //*****************************************************************************
- const tConfigHeader * const g_pCDCSerConfigDescriptors[] =
- {
- &g_sCDCSerConfigHeader
- };
- //*****************************************************************************
- //
- // Configuration Descriptor for the CDC serial class device used in a composite
- // device.
- //
- //*****************************************************************************
- const tConfigHeader * const g_pCDCCompSerConfigDescriptors[] =
- {
- &g_sCDCCompSerConfigHeader
- };
- //*****************************************************************************
- //
- // Forward references for device handler callbacks
- //
- //*****************************************************************************
- static void HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex);
- static void HandleConfigChange(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex);
- static void HandleEP0Data(void *pvInstance, unsigned int ulDataSize,
- unsigned int ulIndex);
- static void HandleDisconnect(void *pvInstance);
- static void HandleEndpoints(void *pvInstance, unsigned int ulStatus,
- unsigned int ulIndex);
- static void HandleSuspend(void *pvInstance);
- static void HandleResume(void *pvInstance);
- static void HandleDevice(void *pvInstance, unsigned int ulRequest,
- void *pvRequestData);
- //*****************************************************************************
- //
- // The device information structure for the USB serial device.
- //
- //*****************************************************************************
- tDeviceInfo g_sCDCSerDeviceInfo =
- {
- //
- // Device event handler callbacks.
- //
- {
- //
- // GetDescriptor
- //
- 0,
- //
- // RequestHandler
- //
- HandleRequests,
- //
- // InterfaceChange
- //
- 0,
- //
- // ConfigChange
- //
- HandleConfigChange,
- //
- // DataReceived
- //
- HandleEP0Data,
- //
- // DataSentCallback
- //
- 0,
- //
- // ResetHandler
- //
- 0,
- //
- // SuspendHandler
- //
- HandleSuspend,
- //
- // ResumeHandler
- //
- HandleResume,
- //
- // DisconnectHandler
- //
- HandleDisconnect,
- //
- // EndpointHandler
- //
- HandleEndpoints,
- //
- // Device handler.
- //
- HandleDevice
- },
- //
- // The common device descriptor.
- //
- g_pCDCSerDeviceDescriptor,
- //
- // Default to no interrupt endpoint.
- //
- g_pCDCCompSerConfigDescriptors,
- //
- // String descriptors will be passed in.
- //
- 0,
- 0,
- //
- // Use the default USB FIFO configuration.
- //
- &g_sUSBDefaultFIFOConfig,
- //
- // Zero out the instance pointer by default.
- //
- 0
- };
- //*****************************************************************************
- //
- // Set or clear deferred operation flags in an "atomic" manner.
- //
- // \param pusDeferredOp points to the flags variable which is to be modified.
- // \param usBit indicates which bit number is to be set or cleared.
- // \param bSet indicates the state that the flag must be set to. If \b true,
- // the flag is set, if \b false, the flag is cleared.
- //
- // This function safely sets or clears a bit in a flag variable. The operation
- // makes use of bitbanding to ensure that the operation is atomic (no read-
- // modify-write is required).
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- SetDeferredOpFlag(volatile unsigned short *pusDeferredOp,
- unsigned short usBit, tBoolean bSet)
- {
- #ifdef DISABLE_BIT_BAND
- if(bSet)
- {
- HWREG(pusDeferredOp) |= (1<<usBit);
- }
- else
- {
- HWREG(pusDeferredOp) &= ~(1<<usBit);
- }
- #else
- //
- // Set the flag bit to 1 or 0 using a bitband access.
- //
- HWREGBITH(pusDeferredOp, usBit) = bSet ? 1 : 0;
- #endif
- }
- //*****************************************************************************
- //
- // Determines whether or not a client has consumed all received data previously
- // passed to it.
- //
- //! \param psDevice is the pointer to the device instance structure as returned
- //! by USBDCDCInit().
- //
- // This function is called to determine whether or not a device has consumed
- // all data previously passed to it via its receive callback.
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- static tBoolean
- DeviceConsumedAllData(const tUSBDCDCDevice *psDevice)
- {
- unsigned int ulRemaining;
- //
- // Send the device an event requesting that it tell us how many bytes
- // of data it still has to process.
- //
- ulRemaining = psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_DATA_REMAINING, 0, (void *)0);
- //
- // If any data remains to be processed, return false, else return true.
- //
- return (ulRemaining ? false : true);
- }
- //*****************************************************************************
- //
- // Notifies the client that it should set or clear a break condition.
- //
- // \param psDevice is the pointer to the device instance structure as returned
- // by USBDCDCInit().
- // \param bSend is \b true if a break condition is to be set or \b false if
- // it is to be cleared.
- //
- // This function is called to instruct the client to start or stop sending a
- // break condition on its serial transmit line.
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- static void
- SendBreak(const tUSBDCDCDevice *psDevice, tBoolean bSend)
- {
- tCDCSerInstance *psInst;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Set the break state flags as necessary. If we are turning the break on,
- // set the flag to tell ourselves that we need to notify the client when
- // it is time to turn it off again.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_SEND_BREAK, false);
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_CLEAR_BREAK, bSend);
- //
- // Tell the client to start or stop sending the break.
- //
- psDevice->pfnControlCallback(psDevice->pvControlCBData,
- (bSend ? USBD_CDC_EVENT_SEND_BREAK :
- USBD_CDC_EVENT_CLEAR_BREAK), 0,
- (void *)0);
- }
- //*****************************************************************************
- //
- // Notifies the client of a host request to set the serial communication
- // parameters.
- //
- // \param psDevice is the device instance whose communication parameters are to
- // be set.
- //
- // This function is called to notify the client when the host requests a change
- // in the serial communication parameters (baud rate, parity, number of bits
- // per character and number of stop bits) to use.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- SendLineCodingChange(const tUSBDCDCDevice *psDevice)
- {
- tCDCSerInstance *psInst;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Clear the flag we use to tell ourselves that the line coding change has
- // yet to be notified to the client.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_LINE_CODING_CHANGE,
- false);
- //
- // Tell the client to update their serial line coding parameters.
- //
- psDevice->pfnControlCallback(psDevice->pvControlCBData,
- USBD_CDC_EVENT_SET_LINE_CODING, 0,
- &(psInst->sLineCoding));
- }
- //*****************************************************************************
- //
- // Notifies the client of a host request to set the RTS and DTR handshake line
- // states.
- //
- // \param psDevice is the device instance whose break condition is to be set or
- // cleared.
- //
- // This function is called to notify the client when the host requests a change
- // in the state of one or other of the RTS and DTR handshake lines.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- SendLineStateChange(const tUSBDCDCDevice *psDevice)
- {
- tCDCSerInstance *psInst;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Clear the flag we use to tell ourselves that the line coding change has
- // yet to be notified to the client.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_LINE_STATE_CHANGE,
- false);
- //
- // Tell the client to update their serial line coding parameters.
- //
- psDevice->pfnControlCallback(psDevice->pvControlCBData,
- USBD_CDC_EVENT_SET_CONTROL_LINE_STATE,
- psInst->usControlLineState,
- (void *)0);
- }
- //*****************************************************************************
- //
- // Notifies the client of a break request if no data remains to be processed.
- //
- // \param psDevice is the device instance that is to be commanded to send a
- // break condition.
- //
- // This function is called when the host requests that the device set a break
- // condition on the serial transmit line. If no data received from the host
- // remains to be processed, the break request is passed to the control
- // callback. If data is outstanding, the call is ignored (with the operation
- // being retried on the next timer tick).
- //
- // \return Returns \b true if the break notification was sent, \b false
- // otherwise.
- //
- //*****************************************************************************
- static tBoolean
- CheckAndSendBreak(const tUSBDCDCDevice *psDevice, unsigned short usDuration)
- {
- tBoolean bCanSend;
- //
- // Has the client consumed all data received from the host yet?
- //
- bCanSend = DeviceConsumedAllData(psDevice);
- //
- // Can we send the break request?
- //
- if(bCanSend)
- {
- //
- // Pass the break request on to the client since no data remains to be
- // consumed.
- //
- SendBreak(psDevice, (usDuration ? true : false));
- }
- //
- // Tell the caller whether or not we sent the notification.
- //
- return (bCanSend);
- }
- //*****************************************************************************
- //
- // Notifies the client of a request to change the serial line parameters if no
- // data remains to be processed.
- //
- // \param psDevice is the device instance whose line coding parameters are to
- // be changed.
- //
- // This function is called when the host requests that the device change the
- // serial line coding parameters. If no data received from the host remains
- // to be processed, the request is passed to the control callback. If data is
- // outstanding, the call is ignored (with the operation being retried on the
- // next timer tick).
- //
- // \return Returns \b true if the notification was sent, \b false otherwise.
- //
- //*****************************************************************************
- static tBoolean
- CheckAndSendLineCodingChange(const tUSBDCDCDevice *psDevice)
- {
- tBoolean bCanSend;
- //
- // Has the client consumed all data received from the host yet?
- //
- bCanSend = DeviceConsumedAllData(psDevice);
- //
- // Can we send the break request?
- //
- if(bCanSend)
- {
- //
- // Pass the request on to the client since no data remains to be
- // consumed.
- //
- SendLineCodingChange(psDevice);
- }
- //
- // Tell the caller whether or not we sent the notification.
- //
- return (bCanSend);
- }
- //*****************************************************************************
- //
- // Notifies the client of a request to change the handshake line states if no
- // data remains to be processed.
- //
- // \param psDevice is the device instance whose handshake line states are to
- // be changed.
- //
- // This function is called when the host requests that the device change the
- // state of one or other of the RTS or DTR handshake lines. If no data
- // received from the host remains to be processed, the request is passed to
- // the control callback. If data is outstanding, the call is ignored (with
- // the operation being retried on the next timer tick).
- //
- // \return Returns \b true if the notification was sent, \b false otherwise.
- //
- //*****************************************************************************
- static tBoolean
- CheckAndSendLineStateChange(const tUSBDCDCDevice *psDevice)
- {
- tBoolean bCanSend;
- //
- // Has the client consumed all data received from the host yet?
- //
- bCanSend = DeviceConsumedAllData(psDevice);
- //
- // Can we send the break request?
- //
- if(bCanSend)
- {
- //
- // Pass the request on to the client since no data remains to be
- // consumed.
- //
- SendLineStateChange(psDevice);
- }
- //
- // Tell the caller whether or not we sent the notification.
- //
- return (bCanSend);
- }
- //*****************************************************************************
- //
- // Notifies the client of a change in the serial line state.
- //
- // \param psInst is the instance whose serial state is to be reported.
- //
- // This function is called to send the current serial state information to
- // the host via the the interrupt IN endpoint. This notification informs the
- // host of problems or conditions such as parity errors, breaks received,
- // framing errors, etc.
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- static tBoolean
- SendSerialState(const tUSBDCDCDevice *psDevice)
- {
- tUSBRequest sRequest;
- unsigned short usSerialState;
- tCDCSerInstance *psInst;
- int iRetcode;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Remember that we are in the middle of sending a notification.
- //
- psInst->eCDCInterruptState = CDC_STATE_WAIT_DATA;
- //
- // Clear the flag we use to indicate that a send is required.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
- false);
- //
- // Take a snapshot of the serial state.
- //
- usSerialState = psInst->usSerialState;
- //
- // Build the request we will use to send the notification.
- //
- sRequest.bmRequestType = (USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
- USB_RTYPE_INTERFACE);
- sRequest.bRequest = USB_CDC_NOTIFY_SERIAL_STATE;
- sRequest.wValue = 0;
- sRequest.wIndex = 0;
- sRequest.wLength = USB_CDC_NOTIFY_SERIAL_STATE_SIZE;
- //
- // Write the request structure to the USB FIFO.
- //
- iRetcode = USBEndpointDataPut(psInst->ulUSBBase, psInst->ucControlEndpoint,
- (unsigned char *)&sRequest,
- sizeof(tUSBRequest));
- iRetcode = USBEndpointDataPut(psInst->ulUSBBase, psInst->ucControlEndpoint,
- (unsigned char *)&usSerialState,
- USB_CDC_NOTIFY_SERIAL_STATE_SIZE);
- //
- // Did we correctly write the data to the endpoint FIFO?
- //
- if(iRetcode != -1)
- {
- //
- // We put the data into the FIFO so now schedule it to be
- // sent.
- //
- iRetcode = USBEndpointDataSend(psInst->ulUSBBase,
- psInst->ucControlEndpoint,
- USB_TRANS_IN);
- }
- //
- // If an error occurred, mark the endpoint as idle (to prevent possible
- // lockup) and return an error.
- //
- if(iRetcode == -1)
- {
- psInst->eCDCInterruptState = CDC_STATE_IDLE;
- return (false);
- }
- else
- {
- //
- // Everything went fine. Clear the error bits that we just notified
- // and return true.
- //
- psInst->usSerialState &= ~(usSerialState & USB_CDC_SERIAL_ERRORS);
- return (true);
- }
- }
- //*****************************************************************************
- //
- // Receives notifications related to data received from the host.
- //
- // \param psDevice is the device instance whose endpoint is to be processed.
- // \param ulStatus is the USB interrupt status that caused this function to
- // be called.
- //
- // This function is called from HandleEndpoints for all interrupts signaling
- // the arrival of data on the bulk OUT endpoint (in other words, whenever the
- // host has sent us a packet of data). We inform the client that a packet
- // is available and, on return, check to see if the packet has been read. If
- // not, we schedule another notification to the client for a later time.
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- tBoolean
- ProcessDataFromHost(const tUSBDCDCDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tCDCSerInstance *psInst;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucBulkOUTEndpoint,
- ulEPStatus);
- //
- // Has a packet been received?
- //
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // Set the flag we use to indicate that a packet read is pending. This
- // will be cleared if the packet is read. If the client doesn't read
- // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
- // the event will be notified later during tick processing.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_PACKET_RX, true);
- //
- // Is the receive channel currently blocked?
- //
- if(!psInst->bControlBlocked && !psInst->bRxBlocked)
- {
- //
- // How big is the packet we've just been sent?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- //
- // The receive channel is not blocked so let the caller know
- // that a packet is waiting. The parameters are set to indicate
- // that the packet has not been read from the hardware FIFO yet.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_RX_AVAILABLE, ulSize,
- (void *)0);
- }
-
- }
- else
- {
- //
- // No packet was received. Some error must have been reported. Check
- // and pass this on to the client if necessary.
- //
- if(ulEPStatus & USB_RX_ERROR_FLAGS)
- {
- //
- // This is an error we report to the client so...
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_ERROR,
- (ulEPStatus & USB_RX_ERROR_FLAGS),
- (void *)0);
- }
- return (false);
- }
- return (true);
- }
- //*****************************************************************************
- //
- // Receives notifications related to interrupt messages sent to the host.
- //
- // \param psDevice is the device instance whose endpoint is to be processed.
- // \param ulStatus is the USB interrupt status that caused this function to
- // be called.
- //
- // This function is called from HandleEndpoints for all interrupts originating
- // from the interrupt IN endpoint (in other words, whenever a notification has
- // been transmitted to the USB host).
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- tBoolean
- ProcessNotificationToHost(const tUSBDCDCDevice *psDevice,
- unsigned int ulStatus)
- {
- unsigned int ulEPStatus;
- tCDCSerInstance *psInst;
- tBoolean bRetcode;
- //
- // Assume all will go well until we have reason to believe otherwise.
- //
- bRetcode = true;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase,
- psInst->ucControlEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase,
- psInst->ucControlEndpoint, ulEPStatus);
- //
- // Did the state change while we were waiting for the previous notification
- // to complete?
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_SERIAL_STATE_CHANGE))
- {
- //
- // The state changed while we were waiting so we need to schedule
- // another notification immediately.
- //
- bRetcode = SendSerialState(psDevice);
- }
- else
- {
- //
- // Our last notification completed and we didn't have any new
- // notifications to make so the interrupt channel is now idle again.
- //
- psInst->eCDCInterruptState = CDC_STATE_IDLE;
- }
- //
- // Tell the caller how things went.
- //
- return (bRetcode);
- }
- //*****************************************************************************
- //
- // Receives notifications related to data sent to the host.
- //
- // \param psDevice is the device instance whose endpoint is to be processed.
- // \param ulStatus is the USB interrupt status that caused this function to
- // be called.
- //
- // This function is called from HandleEndpoints for all interrupts originating
- // from the bulk IN endpoint (in other words, whenever data has been
- // transmitted to the USB host). We examine the cause of the interrupt and,
- // if due to completion of a transmission, notify the client.
- //
- // \return Returns \b true on success or \b false on failure.
- //
- //*****************************************************************************
- tBoolean
- ProcessDataToHost(const tUSBDCDCDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- tCDCSerInstance *psInst;
- unsigned int ulEPStatus, ulSize;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase,
- psInst->ucBulkINEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase,
- psInst->ucBulkINEndpoint, ulEPStatus);
- //
- // Our last transmission completed. Clear our state back to idle and
- // see if we need to send any more data.
- //
- psInst->eCDCTxState = CDC_STATE_IDLE;
- //
- // Notify the client that the last transmission completed.
- //
- ulSize = (unsigned int)psInst->usLastTxSize;
- psInst->usLastTxSize = 0;
- psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
- ulSize, (void *)0);
- return (true);
- }
- //*****************************************************************************
- //
- // Called by the USB stack for any activity involving one of our endpoints
- // other than EP0. This function is a fan out that merely directs the call to
- // the correct handler depending upon the endpoint and transaction direction
- // signaled in ulStatus.
- //
- //*****************************************************************************
- static void
- HandleEndpoints(void *pvInstance, unsigned int ulStatus, unsigned int ulIndex)
- {
- const tUSBDCDCDevice *psDeviceInst;
- tCDCSerInstance *psInst;
- ASSERT(pvInstance != 0);
- //
- // Determine if the serial device is in single or composite mode because
- // the meaning of ulIndex is different in both cases.
- //
- psDeviceInst = pvInstance;
- psInst = psDeviceInst->psPrivateCDCSerData;
- //
- // Handler for the interrupt IN notification endpoint.
- //
- if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucControlEndpoint)))
- {
- //
- // We have sent an interrupt notification to the host.
- //
- ProcessNotificationToHost(psDeviceInst, ulStatus);
- }
- //
- // Handler for the bulk OUT data endpoint.
- //
- if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucBulkOUTEndpoint)))
- {
- //
- // Data is being sent to us from the host.
- //
- ProcessDataFromHost(psDeviceInst, ulStatus, ulIndex);
- }
- //
- // Handler for the bulk IN data endpoint.
- //
- if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucBulkINEndpoint)))
- {
- ProcessDataToHost(psDeviceInst, ulStatus, ulIndex);
- }
- }
- //*****************************************************************************
- //
- // Called by the USB stack whenever a configuration change occurs.
- //
- //*****************************************************************************
- static void
- HandleConfigChange(void *pvInstance, unsigned int ulInfo, unsigned int ulIndex)
- {
- tCDCSerInstance *psInst;
- const tUSBDCDCDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create a device instance pointer.
- //
- psDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Set all our endpoints to idle state.
- //
- psInst->eCDCInterruptState = CDC_STATE_IDLE;
- psInst->eCDCRequestState = CDC_STATE_IDLE;
- psInst->eCDCRxState = CDC_STATE_IDLE;
- psInst->eCDCTxState = CDC_STATE_IDLE;
- //
- // If we are not currently connected so let the client know we are open
- // for business.
- //
- if(!psInst->bConnected)
- {
- //
- // Pass the connected event to the client.
- //
- psDevice->pfnControlCallback(psDevice->pvControlCBData,
- USB_EVENT_CONNECTED, 0, (void *)0);
- }
- //
- // Remember that we are connected.
- //
- psInst->bConnected = true;
- }
- //*****************************************************************************
- //
- // USB data received callback.
- //
- // This function is called by the USB stack whenever any data requested from
- // EP0 is received.
- //
- //*****************************************************************************
- static void
- HandleEP0Data(void *pvInstance, unsigned int ulDataSize, unsigned int ulIndex)
- {
- const tUSBDCDCDevice *psDevice;
- tCDCSerInstance *psInst;
- tBoolean bRetcode;
- ASSERT(pvInstance != 0);
- //
- // Create a device instance pointer.
- //
- psDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // If we were not passed any data, just return.
- //
- if(ulDataSize == 0)
- {
- return;
- }
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Make sure we are actually expecting something.
- //
- if(psInst->eCDCRequestState != CDC_STATE_WAIT_DATA)
- {
- return;
- }
- //
- // Process the data received. This will be a request-specific data
- // block associated with the last request received.
- //
- switch (psInst->ucPendingRequest)
- {
- //
- // We just got the line coding structure. Make sure the client has
- // read all outstanding data then pass it back to initiate a change
- // in the line state.
- //
- case USB_CDC_SET_LINE_CODING:
- {
- if(ulDataSize != sizeof(tLineCoding))
- {
- USBDCDStallEP0(ulIndex);
- }
- else
- {
- //
- // Set the flag telling us that we need to send a line coding
- // notification to the client.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- CDC_DO_LINE_CODING_CHANGE, true);
- //
- // See if we can send the notification immediately.
- //
- bRetcode = CheckAndSendLineCodingChange(psDevice);
- //
- // If we couldn't send the line coding change request to the
- // client, block reception of more data from the host until
- // previous data is processed and we send the change request.
- //
- if(!bRetcode)
- {
- psInst->bRxBlocked = true;
- }
- }
- break;
- }
- //
- // Oops - we seem to be waiting on a request which has not yet been
- // coded here. Flag the error and stall EP0 anyway (even though
- // this would indicate a coding error).
- //
- default:
- {
- USBDCDStallEP0(ulIndex);ASSERT(ulIndex);
- break;
- }
- }
- //
- // All is well. Set the state back to IDLE.
- //
- psInst->eCDCRequestState = CDC_STATE_IDLE;
- }
- //*****************************************************************************
- //
- // Device instance specific handler.
- //
- //*****************************************************************************
- static void
- HandleDevice(void *pvInstance, unsigned int ulRequest, void *pvRequestData)
- {
- tCDCSerInstance *psInst;
- unsigned char *pucData;
- //
- // Create the serial instance data.
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Create the char array used by the events supported by the USB CDC
- // serial class.
- //
- pucData = (unsigned char *)pvRequestData;
- switch(ulRequest)
- {
- //
- // This was an interface change event.
- //
- case USB_EVENT_COMP_IFACE_CHANGE:
- {
- //
- // Save the change to the appropriate interface number.
- //
- if(pucData[0] == SERIAL_INTERFACE_CONTROL)
- {
- psInst->ucInterfaceControl = pucData[1];
- }
- else if(pucData[0] == SERIAL_INTERFACE_DATA)
- {
- psInst->ucInterfaceData = pucData[1];
- }
- break;
- }
- //
- // This was an endpoint change event.
- //
- case USB_EVENT_COMP_EP_CHANGE:
- {
- //
- // Determine if this is an IN or OUT endpoint that has changed.
- //
- if(pucData[0] & USB_EP_DESC_IN)
- {
- //
- // Determine which IN endpoint to modify.
- //
- if((pucData[0] & 0x7f) == USB_EP_TO_INDEX(CONTROL_ENDPOINT))
- {
- psInst->ucControlEndpoint =
- INDEX_TO_USB_EP((pucData[1] & 0x7f));
- }
- else
- {
- psInst->ucBulkINEndpoint =
- INDEX_TO_USB_EP((pucData[1] & 0x7f));
- }
- }
- else
- {
- //
- // Extract the new endpoint number.
- //
- psInst->ucBulkOUTEndpoint =
- INDEX_TO_USB_EP(pucData[1] & 0x7f);
- }
- break;
- }
- //
- // Handle class specific reconfiguring of the configuration descriptor
- // once the composite class has built the full descriptor.
- //
- case USB_EVENT_COMP_CONFIG:
- {
- //
- // This sets the bFirstInterface of the Interface Association
- // descriptor to the first interface which is the control
- // interface used by this instance.
- //
- pucData[2] = psInst->ucInterfaceControl;
- //
- // This sets the bMasterInterface of the Union descriptor to the
- // Control interface and the bSlaveInterface of the Union
- // Descriptor to the Data interface used by this instance.
- //
- pucData[29] = psInst->ucInterfaceControl;
- pucData[30] = psInst->ucInterfaceData;
- //
- // This sets the bDataInterface of the Union descriptor to the
- // Data interface used by this instance.
- pucData[35] = psInst->ucInterfaceData;
- break;
- }
- default:
- {
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // USB non-standard request callback.
- //
- // This function is called by the USB stack whenever any non-standard request
- // is made to the device. The handler should process any requests that it
- // supports or stall EP0 in any unsupported cases.
- //
- //*****************************************************************************
- static void
- HandleRequests(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex)
- {
- const tUSBDCDCDevice *psDevice;
- tCDCSerInstance *psInst;
- tLineCoding sLineCoding;
- tBoolean bRetcode;
-
- ASSERT(pvInstance != 0);
- //
- // Create a device instance pointer.
- //
- psDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Only handle requests meant for this interface.
- //
- if(pUSBRequest->wIndex != psInst->ucInterfaceControl)
- {
- return;
- }
- //
- // Handle each of the requests that we expect from the host.
- //
- switch(pUSBRequest->bRequest)
- {
- case USB_CDC_SEND_ENCAPSULATED_COMMAND:
- {
- //
- // This implementation makes use of no communication protocol so
- // this request is meaningless. We stall endpoint 0 if we receive
- // it.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- case USB_CDC_GET_ENCAPSULATED_RESPONSE:
- {
- //
- // This implementation makes use of no communication protocol so
- // this request is meaningless. We stall endpoint 0 if we receive
- // it.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- case USB_CDC_SET_COMM_FEATURE:
- {
- //
- // This request is apparently required by an ACM device but does
- // not appear relevant to a virtual COM port and is never used by
- // Windows (or, at least, is not seen when using Hyperterminal or
- // TeraTerm via a Windows virtual COM port). We stall endpoint 0
- // to indicate that we do not support the request.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- case USB_CDC_GET_COMM_FEATURE:
- {
- //
- // This request is apparently required by an ACM device but does
- // not appear relevant to a virtual COM port and is never used by
- // Windows (or, at least, is not seen when using Hyperterminal or
- // TeraTerm via a Windows virtual COM port). We stall endpoint 0
- // to indicate that we do not support the request.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- case USB_CDC_CLEAR_COMM_FEATURE:
- {
- //
- // This request is apparently required by an ACM device but does
- // not appear relevant to a virtual COM port and is never used by
- // Windows (or, at least, is not seen when using Hyperterminal or
- // TeraTerm via a Windows virtual COM port). We stall endpoint 0
- // to indicate that we do not support the request.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- //
- // Set the serial communication parameters.
- //
- case USB_CDC_SET_LINE_CODING:
- {
- //
- // Remember the request we are processing.
- //
- psInst->ucPendingRequest = USB_CDC_SET_LINE_CODING;
- //
- // Set the state to indicate we are waiting for data.
- //
- psInst->eCDCRequestState = CDC_STATE_WAIT_DATA;
- //
- // Now read the payload of the request. We handle the actual
- // operation in the data callback once this data is received.
- //
- USBDCDRequestDataEP0(0, (unsigned char *)&psInst->sLineCoding,
- sizeof(tLineCoding));
- //
- // ACK what we have already received. We must do this after
- // requesting the data or we get into a race condition where the
- // data may return before we have set the stack state appropriately
- // to receive it.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, false);
- break;
- }
- //
- // Return the serial communication parameters.
- //
- case USB_CDC_GET_LINE_CODING:
- {
- //
- // ACK what we have already received
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, false);
- //
- // Ask the client for the current line coding.
- //
- psDevice->pfnControlCallback(psDevice->pvControlCBData,
- USBD_CDC_EVENT_GET_LINE_CODING, 0,
- &sLineCoding);
- //
- // Send the line coding information back to the host.
- //
- USBDCDSendDataEP0(0, (unsigned char *)&sLineCoding,
- sizeof(tLineCoding));
- break;
- }
- case USB_CDC_SET_CONTROL_LINE_STATE:
- {
- //
- // ACK what we have already received
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, false);
- //
- // Set the handshake lines as required.
- //
- psInst->usControlLineState = pUSBRequest->wValue;
- //
- // Remember that we are due to notify the client of a line
- // state change.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- CDC_DO_LINE_STATE_CHANGE, true);
- //
- // See if we can notify now.
- //
- bRetcode = CheckAndSendLineStateChange(psDevice);
- //
- // If we couldn't send the line state change request to the
- // client, block reception of more data from the host until
- // previous data is processed and we send the change request.
- //
- if(!bRetcode)
- {
- psInst->bRxBlocked = true;
- }
- break;
- }
- case USB_CDC_SEND_BREAK:
- {
- //
- // ACK what we have already received
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, false);
- //
- // Keep a copy of the requested break duration.
- //
- psInst->usBreakDuration = pUSBRequest->wValue;
- //
- // Remember that we need to send a break request.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- CDC_DO_SEND_BREAK, true);
- //
- // Send the break request if all outstanding receive data has been
- // processed.
- //
- bRetcode = CheckAndSendBreak(psDevice, pUSBRequest->wValue);
- //
- // If we couldn't send the line coding change request to the
- // client, block reception of more data from the host until
- // previous data is processed and we send the change request.
- //
- if(!bRetcode)
- {
- psInst->bRxBlocked = true;
- }
- break;
- }
- //
- // These are valid CDC requests but not ones that an ACM device should
- // receive.
- //
- case USB_CDC_SET_AUX_LINE_STATE:
- case USB_CDC_SET_HOOK_STATE:
- case USB_CDC_PULSE_SETUP:
- case USB_CDC_SEND_PULSE:
- case USB_CDC_SET_PULSE_TIME:
- case USB_CDC_RING_AUX_JACK:
- case USB_CDC_SET_RINGER_PARMS:
- case USB_CDC_GET_RINGER_PARMS:
- case USB_CDC_SET_OPERATION_PARMS:
- case USB_CDC_GET_OPERATION_PARMS:
- case USB_CDC_SET_LINE_PARMS:
- case USB_CDC_GET_LINE_PARMS:
- case USB_CDC_DIAL_DIGITS:
- case USB_CDC_SET_UNIT_PARAMETER:
- case USB_CDC_GET_UNIT_PARAMETER:
- case USB_CDC_CLEAR_UNIT_PARAMETER:
- case USB_CDC_GET_PROFILE:
- case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
- case USB_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
- case USB_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
- case USB_CDC_SET_ETHERNET_PACKET_FILTER:
- case USB_CDC_GET_ETHERNET_STATISTIC:
- case USB_CDC_SET_ATM_DATA_FORMAT:
- case USB_CDC_GET_ATM_DEVICE_STATISTICS:
- case USB_CDC_SET_ATM_DEFAULT_VC:
- case USB_CDC_GET_ATM_VC_STATISTICS:
- {
- USBDCDStallEP0(ulIndex);
- break;
- }
- default:
- {
- //
- // This request is not part of the CDC specification.
- //
- USBDCDStallEP0(ulIndex);
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device is
- // disconnected from the host.
- //
- //*****************************************************************************
- static void
- HandleDisconnect(void *pvInstance)
- {
- const tUSBDCDCDevice *psCDCDevice;
- tCDCSerInstance *psInst;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psCDCDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psCDCDevice->psPrivateCDCSerData;
- //
- // If we are not currently connected and we have a control callback,
- // let the client know we are open for business.
- //
- if(psInst->bConnected)
- {
- //
- // Pass the disconnected event to the client.
- //
- psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
- USB_EVENT_DISCONNECTED, 0, (void *)0);
- }
- //
- // Remember that we are no longer connected.
- //
- psInst->bConnected = false;
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the bus is put into
- // suspend state.
- //
- //*****************************************************************************
- static void
- HandleSuspend(void *pvInstance)
- {
- const tUSBDCDCDevice *psCDCDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psCDCDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // Pass the event on to the client.
- //
- psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
- USB_EVENT_SUSPEND, 0, (void *)0);
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the bus is taken
- // out of suspend state.
- //
- //*****************************************************************************
- static void
- HandleResume(void *pvInstance)
- {
- tUSBDCDCDevice *psCDCDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psCDCDevice = (tUSBDCDCDevice *)pvInstance;
- //
- // Pass the event on to the client.
- //
- psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
- USB_EVENT_RESUME, 0, (void *)0);
- }
- //*****************************************************************************
- //
- // This function is called periodically and provides us with a time reference
- // and method of implementing delayed or time-dependent operations.
- //
- // \param ulIndex is the index of the USB controller for which this tick
- // is being generated.
- // \param ulTimemS is the elapsed time in milliseconds since the last call
- // to this function.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- CDCTickHandler(void *pvInstance, unsigned int ulTimemS, unsigned int ulIndex)
- {
- tBoolean bCanSend;
- const tUSBDCDCDevice *psDevice;
- tCDCSerInstance *psInst;
- unsigned int ulSize;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDCDCDevice *)pvInstance;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateCDCSerData;
- //
- // Is there any outstanding operation that we should try to perform?
- //
- if(psInst->usDeferredOpFlags)
- {
- //
- // Yes - we have at least one deferred operation pending. First check
- // to see if it is time to turn off a break condition.
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_CLEAR_BREAK))
- {
- //
- // Will our break timer expire this time?
- //
- if(psInst->usBreakDuration <= ulTimemS)
- {
- //
- // Yes - turn off the break condition.
- //
- SendBreak(psDevice, false);
- }
- else
- {
- //
- // We have not timed out yet. Decrement the break timer.
- //
- psInst->usBreakDuration -= (unsigned short)ulTimemS;
- }
- }
- // Now check to see if the client has any data remaining to be
- // processed. This information is needed by the remaining deferred
- // operations which are waiting for the receive pipe to be emptied
- // before they can be carried out.
- //
- bCanSend = DeviceConsumedAllData(psDevice);
- //
- // Has all outstanding data been consumed?
- //
- if(bCanSend)
- {
- //
- // Yes - go ahead and notify the client of the various things
- // it has been asked to do while we waited for data to be
- // consumed.
- //
- //
- // Do we need to start sending a break condition?
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_SEND_BREAK))
- {
- SendBreak(psDevice, true);
- }
- //
- // Do we need to set the RTS/DTR states?
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_LINE_STATE_CHANGE))
- {
- SendLineStateChange(psDevice);
- }
- //
- // Do we need to change the line coding parameters?
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_LINE_CODING_CHANGE))
- {
- SendLineCodingChange(psDevice);
- }
- //
- // NOTE: We do not need to handle CDC_DO_SERIAL_STATE_CHANGE here
- // since this is handled in the transmission complete notification
- // for the control IN endpoint (ProcessNotificationToHost()).
- //
- //
- // If all the deferred operations which caused the receive channel
- // to be blocked are now handled, we can unblock receive and handle
- // any packet that is currently waiting to be received.
- //
- if(!(psInst->usDeferredOpFlags & RX_BLOCK_OPS))
- {
- //
- // We can remove the receive block.
- //
- psInst->bRxBlocked = false;
- }
- }
- //
- // Is the receive channel unblocked?
- //
- if(!psInst->bRxBlocked)
- {
- //
- // Do we have a deferred receive waiting
- //
- if(psInst->usDeferredOpFlags & (1 << CDC_DO_PACKET_RX))
- {
- //
- // Yes - how big is the waiting packet?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- // Tell the client that there is a packet waiting for it.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_RX_AVAILABLE, ulSize,
- (void *)0);
- }
- }
- }
- return;
- }
- //*****************************************************************************
- //
- //! Initializes CDC device operation when used with a composite device.
- //!
- //! \param ulIndex is the index of the USB controller in use.
- //! \param psCDCDevice points to a structure containing parameters customizing
- //! the operation of the CDC device.
- //!
- //! An application wishing to make use of a composite
- //! USB CDC communication channel needs to call this function.
- //! This function is used for initializing an instance related information of the
- //! CDC device.
- //!
- //! \return Returns NULL on failure or the psCDCDevice pointer on success.
- //
- //*****************************************************************************
- void *
- USBDCDCCompositeInit(unsigned int ulIndex, const tUSBDCDCDevice *psCDCDevice)
- {
- tCDCSerInstance *psInst;
- tDeviceDescriptor *psDevDesc;
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psCDCDevice);
- ASSERT(psCDCDevice->psPrivateCDCSerData);
- ASSERT(psCDCDevice->pfnControlCallback);
- ASSERT(psCDCDevice->pfnRxCallback);
- ASSERT(psCDCDevice->pfnTxCallback);
- if(ulIndex == 0)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB0_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_0_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB0;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USBPHYCTRL;
- }
- #if (USB_NUM_INSTANCE == 2)
- else if(ulIndex == 1)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB1_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_1_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB1;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USB1PHYCTRL;
- }
- #endif
- //
- // Create an instance pointer to the private data area.
- //
- psInst = psCDCDevice->psPrivateCDCSerData;
- //
- // Set the default endpoint and interface assignments.
- //
- psInst->ucBulkINEndpoint = DATA_IN_ENDPOINT;
- psInst->ucBulkOUTEndpoint = DATA_OUT_ENDPOINT;
- psInst->ucInterfaceControl = SERIAL_INTERFACE_CONTROL;
- psInst->ucInterfaceData = SERIAL_INTERFACE_DATA;
- //
- // By default do not use the interrupt control endpoint. The single
- // instance CDC serial device will turn this on in USBDCDCInit();
- //
- psInst->ucControlEndpoint = CONTROL_ENDPOINT;
- //
- // Initialize the workspace in the passed instance structure.
- //
- psInst->psConfDescriptor = (tConfigDescriptor *)g_pCDCSerDescriptor;
- psInst->psDevInfo = &g_sCDCSerDeviceInfo;
- psInst->ulUSBBase = g_USBInstance[ulIndex].uiBaseAddr;
- psInst->eCDCRxState = CDC_STATE_UNCONFIGURED;
- psInst->eCDCTxState = CDC_STATE_UNCONFIGURED;
- psInst->eCDCInterruptState = CDC_STATE_UNCONFIGURED;
- psInst->eCDCRequestState = CDC_STATE_UNCONFIGURED;
- psInst->ucPendingRequest = 0;
- psInst->usBreakDuration = 0;
- psInst->usSerialState = 0;
- psInst->usDeferredOpFlags = 0;
- psInst->usControlLineState = 0;
- psInst->bRxBlocked = false;
- psInst->bControlBlocked = false;
- psInst->bConnected = false;
- //
- // Fix up the device descriptor with the client-supplied values.
- //
- psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
- psDevDesc->idVendor = psCDCDevice->usVID;
- psDevDesc->idProduct = psCDCDevice->usPID;
- //
- // Fix up the configuration descriptor with client-supplied values.
- //
- psInst->psConfDescriptor->bmAttributes = psCDCDevice->ucPwrAttributes;
- psInst->psConfDescriptor->bMaxPower =
- (unsigned char)(psCDCDevice->usMaxPowermA / 2);
- //
- // Plug in the client's string stable to the device information
- // structure.
- //
- psInst->psDevInfo->ppStringDescriptors = psCDCDevice->ppStringDescriptors;
- psInst->psDevInfo->ulNumStringDescriptors
- = psCDCDevice->ulNumStringDescriptors;
- //
- // Register our tick handler (this must be done after USBDCDInit).
- //
- InternalUSBRegisterTickHandler(USB_TICK_HANDLER_DEVICE,
- CDCTickHandler,
- (void *)psCDCDevice);
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return((void *)psCDCDevice);
- }
- //*****************************************************************************
- //
- //! Initializes CDC device operation for a given USB controller.
- //!
- //! \param ulIndex is the index of the USB controller which is to be
- //! initialized for CDC device operation.
- //! \param psCDCDevice points to a structure containing parameters customizing
- //! the operation of the CDC device.
- //!
- //! An application wishing to make use of a USB CDC communication channel and
- //! appear as a virtual serial port on the host system must call this function
- //! to initialize the USB controller and attach the device to the USB bus.
- //! This function performs all required USB initialization.
- //!
- //! The value returned by this function is the \e psCDCDevice pointer passed
- //! to it if successful. This pointer must be passed to all later calls to the
- //! CDC class driver to identify the device instance.
- //!
- //! The USB CDC device class driver offers packet-based transmit and receive
- //! operation. If the application would rather use block based communication
- //! with transmit and receive buffers, USB buffers on the transmit and receive
- //! channels may be used to offer this functionality.
- //!
- //! Transmit Operation:
- //!
- //! Calls to USBDCDCPacketWrite() must send no more than 64 bytes of data at a
- //! time and may only be made when no other transmission is currently
- //! outstanding.
- //!
- //! Once a packet of data has been acknowledged by the USB host, a
- //! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to
- //! inform it that another packet may be transmitted.
- //!
- //! Receive Operation:
- //!
- //! An incoming USB data packet will result in a call to the application
- //! callback with event \b USB_EVENT_RX_AVAILABLE. The application must then
- //! call USBDCDCPacketRead(), passing a buffer capable of holding the received
- //! packet to retrieve the data and acknowledge reception to the USB host. The
- //! size of the received packet may be queried by calling
- //! USBDCDCRxPacketAvailable().
- //!
- //! \note The application must not make any calls to the low level USB Device
- //! API if interacting with USB via the CDC device class API. Doing so
- //! will cause unpredictable (though almost certainly unpleasant) behavior.
- //!
- //! \return Returns NULL on failure or the psCDCDevice pointer on success.
- //
- //*****************************************************************************
- void *
- USBDCDCInit(unsigned int ulIndex, const tUSBDCDCDevice *psCDCDevice)
- {
- void *pvRet;
- tCDCSerInstance *psInst;
- //
- // Initialize the internal state for this class.
- //
- pvRet = USBDCDCCompositeInit(ulIndex, psCDCDevice);
- if(pvRet)
- {
- //
- // Create an instance pointer to the private data area.
- //
- psInst = psCDCDevice->psPrivateCDCSerData;
- //
- // Set the instance data for this device so that USBDCDInit() call can
- // have the instance data.
- //
- psInst->psDevInfo->pvInstance = (void *)psCDCDevice;
- //
- // Enable the default interrupt control endpoint if this class is not
- // being used in a composite device.
- //
- psInst->ucControlEndpoint = CONTROL_ENDPOINT;
- //
- // Use the configuration descriptor with the interrupt control endpoint.
- //
- psInst->psDevInfo->ppConfigDescriptors = g_pCDCSerConfigDescriptors;
- //
- // All is well so now pass the descriptors to the lower layer and put
- // the CDC device on the bus.
- //
- USBDCDInit(ulIndex, psInst->psDevInfo);
-
-
- }
- return(pvRet);
- }
- //*****************************************************************************
- //
- //! Shuts down the CDC device instance.
- //!
- //! \param pvInstance is the pointer to the device instance structure as returned
- //! by USBDCDCInit().
- //!
- //! This function terminates CDC operation for the instance supplied and
- //! removes the device from the USB bus. This function should not be called
- //! if the CDC device is part of a composite device and instead the
- //! USBDCompositeTerm() function should be called for the full composite
- //! device.
- //!
- //! Following this call, the \e pvInstance instance should not me used in any
- //! other calls.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDCDCTerm(void *pvInstance)
- {
- tCDCSerInstance *psInst;
- int index;
- ASSERT(pvInstance);
- //
- // Get a pointer to our instance data.
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Terminate the requested instance.
- //
- USB_BASE_TO_INDEX(psInst->ulUSBBase, index);
- USBDCDTerm(index);
- psInst->ulUSBBase = 0;
- psInst->psDevInfo = (tDeviceInfo *)0;
- psInst->psConfDescriptor = (tConfigDescriptor *)0;
- return;
- }
- //*****************************************************************************
- //
- //! Sets the client-specific pointer for the control callback.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param pvCBData is the pointer that client wishes to be provided on each
- //! event sent to the control channel callback function.
- //!
- //! The client uses this function to change the callback pointer passed in
- //! the first parameter on all callbacks to the \e pfnControlCallback function
- //! passed on USBDCDCInit().
- //!
- //! If a client wants to make runtime changes in the callback pointer, it must
- //! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
- //! RAM. If this structure is in flash, callback pointer changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback pointer that was being used for
- //! this instance's control callback.
- //
- //*****************************************************************************
- void *
- USBDCDCSetControlCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback pointer for the control channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvControlCBData;
- ((tUSBDCDCDevice *)pvInstance)->pvControlCBData = pvCBData;
- //
- // Return the previous callback data value.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Sets the client-specific data parameter for the receive channel callback.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param pvCBData is the pointer that client wishes to be provided on each
- //! event sent to the receive channel callback function.
- //!
- //! The client uses this function to change the callback pointer passed in
- //! the first parameter on all callbacks to the \e pfnRxCallback function
- //! passed on USBDCDCInit().
- //!
- //! If a client wants to make runtime changes in the callback pointer, it must
- //! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
- //! RAM. If this structure is in flash, callback data changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback pointer that was being used for
- //! this instance's receive callback.
- //
- //*****************************************************************************
- void *
- USBDCDCSetRxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback data for the receive channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvRxCBData;
- ((tUSBDCDCDevice *)pvInstance)->pvRxCBData = pvCBData;
- //
- // Return the previous callback pointer.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Sets the client-specific data parameter for the transmit callback.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param pvCBData is the pointer that client wishes to be provided on each
- //! event sent to the transmit channel callback function.
- //!
- //! The client uses this function to change the callback pointer passed in
- //! the first parameter on all callbacks to the \e pfnTxCallback function
- //! passed on USBDCDCInit().
- //!
- //! If a client wants to make runtime changes in the callback pointer, it must
- //! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
- //! RAM. If this structure is in flash, callback data changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback pointer that was being used for
- //! this instance's transmit callback.
- //
- //*****************************************************************************
- void *
- USBDCDCSetTxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback data for the transmit channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDCDCDevice *)pvInstance)->pvTxCBData;
- ((tUSBDCDCDevice *)pvInstance)->pvTxCBData = pvCBData;
- //
- // Return the previous callback pointer.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Transmits a packet of data to the USB host via the CDC data interface.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param pcData points to the first byte of data which is to be transmitted.
- //! \param ulLength is the number of bytes of data to transmit.
- //! \param bLast indicates whether more data is to be written before a packet
- //! should be scheduled for transmission. If \b true, the client will make
- //! a further call to this function. If \b false, no further call will be
- //! made and the driver should schedule transmission of a short packet.
- //!
- //! This function schedules the supplied data for transmission to the USB
- //! host in a single USB packet. If no transmission is currently ongoing
- //! the data is immediately copied to the relevant USB endpoint FIFO. If the
- //! \e bLast parameter is \b true, the newly written packet is then scheduled
- //! for transmission. Whenever a USB packet is acknowledged by the host, a
- //! USB_EVENT_TX_COMPLETE event will be sent to the application transmit
- //! callback indicating that more data can now be transmitted.
- //!
- //! The maximum value for ulLength is 64 bytes (the maximum USB packet size
- //! for the bulk endpoints in use by CDC). Attempts to send more data than
- //! this will result in a return code of 0 indicating that the data cannot be
- //! sent.
- //!
- //! \return Returns the number of bytes actually sent. At this level, this
- //! will either be the number of bytes passed (if less than or equal to the
- //! maximum packet size for the USB endpoint in use and no outstanding
- //! transmission ongoing) or 0 to indicate a failure.
- //
- //*****************************************************************************
- unsigned int
- USBDCDCPacketWrite(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- tCDCSerInstance *psInst;
- int iRetcode;
-
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Can we send the data provided?
- //
- if((ulLength > DATA_IN_EP_MAX_SIZE) ||
- (psInst->eCDCTxState != CDC_STATE_IDLE))
- {
- //
- // Either the packet was too big or we are in the middle of sending
- // another packet. Return 0 to indicate that we can't send this data.
- //
- return (0);
- }
- //
- // Copy the data into the USB endpoint FIFO.
- //
- iRetcode = USBEndpointDataPut(psInst->ulUSBBase,
- psInst->ucBulkINEndpoint, pcData,
- ulLength);
- //
- // Did we copy the data successfully?
- //
- if(iRetcode != -1)
- {
- //
- // Remember how many bytes we sent.
- //
- psInst->usLastTxSize += (unsigned short)ulLength;
- //
- // If this is the last call for this packet, schedule transmission.
- //
- if(bLast)
- {
- //
- // Send the packet to the host if we have received all the data we
- // can expect for this packet.
- //
- psInst->eCDCTxState = CDC_STATE_WAIT_DATA;
- iRetcode = USBEndpointDataSend(psInst->ulUSBBase,
- psInst->ucBulkINEndpoint,
- USB_TRANS_IN);
- }
- }
- //
- // Did an error occur while trying to send the data?
- //
- if(iRetcode != -1)
- {
- //
- // No - tell the caller we sent all the bytes provided.
- //
- return (ulLength);
- }
- else
- {
- //
- // Yes - tell the caller we couldn't send the data.
- //
- return (0);
- }
- }
- //*****************************************************************************
- //
- //! Reads a packet of data received from the USB host via the CDC data
- //! interface.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param pcData points to a buffer into which the received data will be
- //! written.
- //! \param ulLength is the size of the buffer pointed to by pcData.
- //! \param bLast indicates whether the client will make a further call to
- //! read additional data from the packet.
- //!
- //! This function reads up to ulLength bytes of data received from the USB
- //! host into the supplied application buffer.
- //!
- //! \note The \e bLast parameter is ignored in this implementation since the
- //! end of a packet can be determined without relying upon the client to
- //! provide this information.
- //!
- //! \return Returns the number of bytes of data read.
- //
- //*****************************************************************************
- unsigned int
- USBDCDCPacketRead(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- unsigned int ulEPStatus, ulPkt;
- unsigned int ulCount;
- tCDCSerInstance *psInst;
- int iRetcode;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // If receive is currently blocked or the buffer we were passed is
- // (potentially) too small, set the flag telling us that we have a
- // packet waiting but return 0.
- //
- if(psInst->bRxBlocked || psInst->bControlBlocked)
- {
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- CDC_DO_PACKET_RX, true);
- return (0);
- }
- else
- {
- //
- // It is OK to receive the new packet. How many bytes are
- // available for us to receive?
- //
- ulPkt = USBEndpointDataAvail(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- //
- // Get as much data as we can.
- //
- ulCount = ulLength;
- iRetcode = USBEndpointDataGet(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint,
- pcData, &ulCount);
- //
- // Did we read the last of the packet data?
- //
- if(ulCount == ulPkt)
- {
- //
- // Clear the endpoint status so that we know no packet is
- // waiting.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint,
- ulEPStatus);
- //
- // Acknowledge the data, thus freeing the host to send the
- // next packet.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint,
- true);
- //
- // Clear the flag we set to indicate that a packet read is
- // pending.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- CDC_DO_PACKET_RX, false);
- }
- //
- // If all went well, tell the caller how many bytes they got.
- //
- if(iRetcode != -1)
- {
- return (ulCount);
- }
- }
- }
- //
- // No packet was available or an error occurred while reading so tell
- // the caller no bytes were returned.
- //
- return (0);
- }
- //*****************************************************************************
- //
- //! Returns the number of free bytes in the transmit buffer.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //!
- //! This function returns the maximum number of bytes that can be passed on a
- //! call to USBDCDCPacketWrite and accepted for transmission. The value
- //! returned will be the maximum USB packet size (64) if no transmission is
- //! currently outstanding or 0 if a transmission is in progress.
- //!
- //! \return Returns the number of bytes available in the transmit buffer.
- //
- //*****************************************************************************
- unsigned int
- USBDCDCTxPacketAvailable(void *pvInstance)
- {
- tCDCSerInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer.
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Do we have a packet transmission currently ongoing?
- //
- if(psInst->eCDCTxState != CDC_STATE_IDLE)
- {
- //
- // We are not ready to receive a new packet so return 0.
- //
- return (0);
- }
- else
- {
- //
- // We can receive a packet so return the max packet size for the
- // relevant endpoint.
- //
- return (DATA_IN_EP_MAX_SIZE);
- }
- }
- //*****************************************************************************
- //
- //! Determines whether a packet is available and, if so, the size of the
- //! buffer required to read it.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //!
- //! This function may be used to determine if a received packet remains to be
- //! read and allows the application to determine the buffer size needed to
- //! read the data.
- //!
- //! \return Returns 0 if no received packet remains unprocessed or the
- //! size of the packet if a packet is waiting to be read.
- //
- //*****************************************************************************
- unsigned int
- USBDCDCRxPacketAvailable(void *pvInstance)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tCDCSerInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // If receive is currently blocked, return 0.
- //
- if(psInst->bRxBlocked || psInst->bControlBlocked)
- {
- return (0);
- }
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // Yes - a packet is waiting. How big is it?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase,
- psInst->ucBulkOUTEndpoint);
- return (ulSize);
- }
- else
- {
- //
- // There is no packet waiting to be received.
- //
- return (0);
- }
- }
- //*****************************************************************************
- //
- //! Informs the CDC module of changes in the serial control line states or
- //! receive error conditions.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDCDCInit().
- //! \param usState indicates the states of the various control lines and
- //! any receive errors detected. Bit definitions are as for the USB CDC
- //! SerialState asynchronous notification and are defined in header file
- //! usbcdc.h.
- //!
- //! The application should call this function whenever the state of any of
- //! the incoming RS232 handshake signals changes or in response to a receive
- //! error or break condition. The usState parameter is the ORed combination
- //! of the following flags with each flag indicating the presence of that
- //! condition.
- //!
- //! - USB_CDC_SERIAL_STATE_OVERRUN
- //! - USB_CDC_SERIAL_STATE_PARITY
- //! - USB_CDC_SERIAL_STATE_FRAMING
- //! - USB_CDC_SERIAL_STATE_RING_SIGNAL
- //! - USB_CDC_SERIAL_STATE_BREAK
- //! - USB_CDC_SERIAL_STATE_TXCARRIER
- //! - USB_CDC_SERIAL_STATE_RXCARRIER
- //!
- //! This function should be called only when the state of any flag changes.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDCDCSerialStateChange(void *pvInstance, unsigned short usState)
- {
- tCDCSerInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDCDCDevice *)pvInstance)->psPrivateCDCSerData;
- //
- // Add the newly reported state bits to the current collection. We do this
- // in case two state changes occur back-to-back before the first has been
- // notified. There are two distinct types of signals that we report here
- // and we deal with them differently:
- //
- // 1. Errors (overrun, parity, framing error) are ORed together so that
- // any reported error is sent on the next notification.
- // 2. Signal line states (RI, break, TX carrier, RX carrier) always
- // report the last state notified to us. The implementation here will
- // send an interrupt showing the last state but, if two state changes
- // occur very quickly, the host may receive a notification containing
- // the same state that was last reported (in other words, a short pulse
- // will be lost). It would be possible to reduce the likelihood of
- // this happening by building a queue of state changes and sending
- // these in order but you are left with exactly the same problem if the
- // queue fills up. For now, therefore, we run the risk of missing very
- // short pulses on the "steady-state" signal lines.
- //
- psInst->usSerialState |= (usState & USB_CDC_SERIAL_ERRORS);
- psInst->usSerialState &= ~USB_CDC_SERIAL_ERRORS;
- psInst->usSerialState |= (usState & ~USB_CDC_SERIAL_ERRORS);
- //
- // Set the flag indicating that a serial state change is to be sent.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
- true);
- //
- // Can we send the state change immediately?
- //
- if(psInst->eCDCInterruptState == CDC_STATE_IDLE)
- {
- //
- // The interrupt channel is free so send the notification immediately.
- // If we can't do this, the tick timer will catch this next time
- // round.
- //
- psInst->eCDCInterruptState = CDC_STATE_WAIT_DATA;
- SendSerialState(pvInstance);
- }
- return;
- }
- //*****************************************************************************
- //
- //! Reports the device power status (bus- or self-powered) to the USB library.
- //!
- //! \param pvInstance is the pointer to the CDC device instance structure.
- //! \param ucPower indicates the current power status, either \b
- //! USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
- //!
- //! Applications which support switching between bus- or self-powered
- //! operation should call this function whenever the power source changes
- //! to indicate the current power status to the USB library. This information
- //! is required by the USB library to allow correct responses to be provided
- //! when the host requests status from the device.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDCDCPowerStatusSet(void *pvInstance, unsigned char ucPower)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- USBDCDPowerStatusSet(0, ucPower);
- }
- //*****************************************************************************
- //
- //! Requests a remote wakeup to resume communication when in suspended state.
- //!
- //! \param pvInstance is the pointer to the CDC device instance structure.
- //!
- //! When the bus is suspended, an application which supports remote wakeup
- //! (advertised to the host via the config descriptor) may call this function
- //! to initiate remote wakeup signaling to the host. If the remote wakeup
- //! feature has not been disabled by the host, this will cause the bus to
- //! resume operation within 20mS. If the host has disabled remote wakeup,
- //! \b false will be returned to indicate that the wakeup request was not
- //! successful.
- //!
- //! \return Returns \b true if the remote wakeup is not disabled and the
- //! signaling was started or \b false if remote wakeup is disabled or if
- //! signaling is currently ongoing following a previous call to this function.
- //
- //*****************************************************************************
- tBoolean
- USBDCDCRemoteWakeupRequest(void *pvInstance)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- return(USBDCDRemoteWakeupRequest(0));
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|