| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665 |
- //*****************************************************************************
- //
- // usbdhid.c - USB HID 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 "usb.h"
- #include "interrupt.h"
- #include "usblib.h"
- #include "usbhid.h"
- #include "usbdevice.h"
- #include "usbdhid.h"
- #include "usblibpriv.h"
- //*****************************************************************************
- //
- //! \addtogroup hid_device_class_api
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //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
- //*****************************************************************************
- //
- // 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)
- //*****************************************************************************
- //
- // Marker used to indicate that a given HID descriptor cannot be found in the
- // client-supplied list.
- //
- //*****************************************************************************
- #define HID_NOT_FOUND 0xFFFFFFFF
- //*****************************************************************************
- //
- // 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.
- // Each deferred operation is defined as the bit number that should be set in
- // tHIDInstance->usDeferredOpFlags to indicate that the operation is pending.
- //
- //*****************************************************************************
- #define HID_DO_PACKET_RX 5
- #define HID_DO_SEND_IDLE_REPORT 6
- //*****************************************************************************
- //
- // 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 INT_IN_ENDPOINT USB_EP_3
- #define INT_OUT_ENDPOINT USB_EP_3
- //*****************************************************************************
- //
- // Maximum packet size for the interrupt endpoints used for report transmission
- // and reception and the associated FIFO sizes to set aside for each endpoint.
- //
- //*****************************************************************************
- #define INT_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
- #define INT_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
- #define INT_IN_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(INT_IN_EP_FIFO_SIZE)
- #define INT_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(INT_IN_EP_FIFO_SIZE)
- //*****************************************************************************
- //
- // 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_pHIDDeviceDescriptor[] =
- {
- 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_DEVICE, // USB Device Class
- 0, // USB Device Sub-class
- USB_HID_PROTOCOL_NONE, // USB Device protocol
- 64, // Maximum packet size for default pipe.
- USBShort(0), // Vendor ID (VID).
- USBShort(0), // Product ID (PID).
- USBShort(0x100), // Device Version BCD.
- 1, // Manufacturer string identifier.
- 2, // Product string identifier.
- 3, // Product serial number.
- 1 // Number of configurations.
- };
- //*****************************************************************************
- //
- // HID device 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_pHIDDescriptor[] =
- {
- //
- // Configuration descriptor header.
- //
- 9, // Size of the configuration descriptor.
- USB_DTYPE_CONFIGURATION, // Type of this descriptor.
- USBShort(34), // The total size of this full structure.
- 1, // 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.
- };
- //*****************************************************************************
- //
- // The remainder of the configuration descriptor is stored in flash since we
- // don't need to modify anything in it at runtime.
- //
- //*****************************************************************************
- unsigned char g_pHIDInterface[] =
- {
- //
- // HID Device Class Interface Descriptor.
- //
- 9, // Size of the interface descriptor.
- USB_DTYPE_INTERFACE, // Type of this descriptor.
- 0, // The index for this interface.
- 0, // The alternate setting for this interface.
- 2, // The number of endpoints used by this
- // interface.
- USB_CLASS_HID, // The interface class
- 0, // The interface sub-class.
- 0, // The interface protocol for the sub-class
- // specified above.
- 4, // The string index for this interface.
- };
- const unsigned char g_pHIDInEndpoint[] =
- {
- //
- // Interrupt IN 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(INT_IN_ENDPOINT),
- USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
- USBShort(INT_IN_EP_MAX_SIZE), // The maximum packet size.
- 16, // The polling interval for this endpoint.
- };
- const unsigned char g_pHIDOutEndpoint[] =
- {
- //
- // Interrupt OUT 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(INT_OUT_ENDPOINT),
- USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
- USBShort(INT_OUT_EP_MAX_SIZE), // The maximum packet size.
- 16, // The polling interval for this endpoint.
- };
- //*****************************************************************************
- //
- // The HID configuration descriptor is defined as four or five sections
- // depending upon the client's configuration choice. These sections are:
- //
- // 1. The 9 byte configuration descriptor (RAM).
- // 2. The interface descriptor (RAM).
- // 3. The HID report and physical descriptors (provided by the client)
- // (FLASH).
- // 4. The mandatory interrupt IN endpoint descriptor (FLASH).
- // 5. The optional interrupt OUT endpoint descriptor (FLASH).
- //
- //*****************************************************************************
- const tConfigSection g_sHIDConfigSection =
- {
- sizeof(g_pHIDDescriptor),
- g_pHIDDescriptor
- };
- const tConfigSection g_sHIDInterfaceSection =
- {
- sizeof(g_pHIDInterface),
- g_pHIDInterface
- };
- const tConfigSection g_sHIDInEndpointSection =
- {
- sizeof(g_pHIDInEndpoint),
- g_pHIDInEndpoint
- };
- const tConfigSection g_sHIDOutEndpointSection =
- {
- sizeof(g_pHIDOutEndpoint),
- g_pHIDOutEndpoint
- };
- //*****************************************************************************
- //
- // Place holder for the user's HID descriptor block.
- //
- //*****************************************************************************
- tConfigSection g_sHIDDescriptorSection =
- {
- 0, (void *)0
- };
- //*****************************************************************************
- //
- // This array lists all the sections that must be concatenated to make a
- // single, complete HID configuration descriptor.
- //
- //*****************************************************************************
- const tConfigSection *g_psHIDSections[] =
- {
- &g_sHIDConfigSection,
- &g_sHIDInterfaceSection,
- &g_sHIDDescriptorSection,
- &g_sHIDInEndpointSection,
- &g_sHIDOutEndpointSection
- };
- #define NUM_HID_SECTIONS (sizeof(g_psHIDSections) / \
- sizeof(tConfigSection *))
- //*****************************************************************************
- //
- // The header for the single configuration we support. This is the root of
- // the data structure that defines all the bits and pieces that are pulled
- // together to generate the configuration descriptor. Note that this must be
- // in RAM since we need to include or exclude the final section based on
- // client supplied initialization parameters.
- //
- //*****************************************************************************
- tConfigHeader g_sHIDConfigHeader =
- {
- NUM_HID_SECTIONS,
- g_psHIDSections
- };
- //*****************************************************************************
- //
- // Configuration Descriptor.
- //
- //*****************************************************************************
- const tConfigHeader * const g_pHIDConfigDescriptors[] =
- {
- &g_sHIDConfigHeader
- };
- //*****************************************************************************
- //
- // Forward references for device handler callbacks
- //
- //*****************************************************************************
- static void HandleGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex);
- static void HandleRequest(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex);
- static void HandleConfigChange(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex);
- static void HandleEP0DataReceived(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex);
- static void HandleEP0DataSent(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex);
- static void HandleReset(void *pvInstance);
- static void HandleSuspend(void *pvInstance);
- static void HandleResume(void *pvInstance);
- static void HandleDisconnect(void *pvInstance);
- static void HandleEndpoints(void *pvInstance, unsigned int ulStatus,
- unsigned int ulIndex);
- static void HandleDevice(void *pvInstance, unsigned int ulRequest,
- void *pvRequestData);
- //*****************************************************************************
- //
- // The device information structure for the USB HID devices.
- //
- //*****************************************************************************
- tDeviceInfo g_sHIDDeviceInfo =
- {
- //
- // Device event handler callbacks.
- //
- {
- HandleGetDescriptor, // GetDescriptor
- HandleRequest, // RequestHandler
- 0, // InterfaceChange
- HandleConfigChange, // ConfigChange
- HandleEP0DataReceived, // DataReceived
- HandleEP0DataSent, // DataSentCallback
- HandleReset, // ResetHandler
- HandleSuspend, // SuspendHandler
- HandleResume, // ResumeHandler
- HandleDisconnect, // DisconnectHandler
- HandleEndpoints, // EndpointHandler
- HandleDevice // Device handler.
- },
- g_pHIDDeviceDescriptor,
- g_pHIDConfigDescriptors,
- 0, // Will be completed during USBDHIDInit().
- 0, // Will be completed during USBDHIDInit().
- &g_sUSBDefaultFIFOConfig
- };
- //*****************************************************************************
- //
- // 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
- }
- //*****************************************************************************
- //
- // This function is called to clear the counter used to keep track of the time
- // elapsed since a given report was last sent.
- //
- // \param psDevice points to the HID device structure whose report timer is to
- // be cleared.
- // \param ucReportID is the first byte of the report to be sent. If this
- // device offers more than one input report, this value is used to find the
- // relevant report timer structure in the psDevice structure.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- ClearReportTimer(const tUSBDHIDDevice *psDevice, unsigned char ucReportID)
- {
- unsigned int ulLoop;
- if(psDevice->ucNumInputReports > 1)
- {
- //
- // We have more than 1 input report so the report must begin with a
- // byte containing the report ID. Scan the table we were provided
- // when the device was initialized to find the entry for this report.
- //
- for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
- {
- if(psDevice->psReportIdle[ulLoop].ucReportID == ucReportID)
- {
- break;
- }
- }
- }
- else
- {
- ulLoop = 0;
- }
- //
- // If we drop out of the loop with an index less than ucNumInputReports,
- // we found the relevant report so clear its timer.
- //
- if(ulLoop < psDevice->ucNumInputReports)
- {
- psDevice->psReportIdle[ulLoop].ulTimeSinceReportmS = 0;
- }
- }
- //*****************************************************************************
- //
- // This function is called to clear the idle period timers for each input
- // report supported by the device.
- //
- // \param psDevice points to the HID device structure whose timers are to be
- // cleared.
- // \param ulTimemS is the elapsed time in milliseconds since the last call
- // to this function.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- ClearIdleTimers(const tUSBDHIDDevice *psDevice)
- {
- unsigned int ulLoop;
- //
- // Clear the "time till next report" counters for each input report.
- //
- for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
- {
- psDevice->psReportIdle[ulLoop].usTimeTillNextmS =
- psDevice->psReportIdle[ulLoop].ucDuration4mS * 4;
- }
- }
- //*****************************************************************************
- //
- // This function is called periodically to allow us to process the report idle
- // timers.
- //
- // \param psDevice points to the HID device structure whose timers are to be
- // updated.
- // \param ulElapsedmS indicates the number of milliseconds that have elapsed
- // since the last call to this function.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- ProcessIdleTimers(const tUSBDHIDDevice *psDevice, unsigned int ulElapsedmS)
- {
- unsigned int ulLoop;
- unsigned int ulSizeReport;
- void *pvReport;
- tHIDInstance *psInst;
- tBoolean bDeferred;
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDHIDDevice *)psDevice)->psPrivateHIDData;
- //
- // We have not had to defer any report transmissions yet.
- //
- bDeferred = false;
- //
- // Look at each of the input report idle timers in turn.
- //
- for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
- {
- //
- // Update the time since the last report was sent.
- //
- psDevice->psReportIdle[ulLoop].ulTimeSinceReportmS += ulElapsedmS;
- //
- // Is this timer running?
- //
- if(psDevice->psReportIdle[ulLoop].ucDuration4mS)
- {
- //
- // Yes - is it about to expire?
- //
- if(psDevice->psReportIdle[ulLoop].usTimeTillNextmS <= ulElapsedmS)
- {
- //
- // The timer is about to expire. Can we send a report right
- // now?
- //
- if((psInst->eHIDTxState == HID_STATE_IDLE) &&
- (psInst->bSendInProgress == false))
- {
- //
- // We can send a report so send a message to the
- // application to retrieve its latest report for
- // transmission to the host.
- //
- ulSizeReport = psDevice->pfnRxCallback(
- psDevice->pvRxCBData,
- USBD_HID_EVENT_IDLE_TIMEOUT,
- psDevice->psReportIdle[ulLoop].ucReportID,
- &pvReport);
- //
- // Schedule the report for transmission.
- //
- USBDHIDReportWrite((void *)psDevice, pvReport,
- ulSizeReport, true);
- //
- // Reload the timer for the next period.
- //
- psDevice->psReportIdle[ulLoop].usTimeTillNextmS =
- psDevice->psReportIdle[ulLoop].ucDuration4mS * 4;
- }
- else
- {
- //
- // We can't send the report straight away so flag it for
- // transmission as soon as the previous transmission ends.
- //
- psDevice->psReportIdle[ulLoop].usTimeTillNextmS = 0;
- bDeferred = true;
- }
- }
- else
- {
- //
- // The timer is not about to expire. Update the time till the
- // next report transmission.
- //
- psDevice->psReportIdle[ulLoop].usTimeTillNextmS -= ulElapsedmS;
- }
- }
- }
- //
- // If we had to defer transmission of any report, remember this so that we
- // will process it as soon as possible.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- HID_DO_SEND_IDLE_REPORT, bDeferred);
- }
- static void
- SetIdleTimeout(const tUSBDHIDDevice *psDevice, unsigned char ucReportID,
- unsigned char ucTimeout4mS)
- {
- unsigned int ulLoop;
- tBoolean bReportNeeded;
- tHIDReportIdle *psIdle;
- //
- // Remember that we have not found any report that needs to be sent
- // immediately.
- //
- bReportNeeded = false;
- //
- // Search through all the input reports looking for ones that fit the
- // requirements.
- //
- for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
- {
- psIdle = &psDevice->psReportIdle[ulLoop];
- //
- // If the report ID passed matches the report ID in the idle timer
- // control structure or we were passed a report ID of zero, which
- // indicates that all timers are to be set...
- //
- if(!ucReportID || (ucReportID == psIdle->ucReportID))
- {
- //
- // Save the new duration for the idle timer.
- //
- psIdle->ucDuration4mS = ucTimeout4mS;
- //
- // Are we enabling the idle timer? If so, fix up the time until it
- // needs to fire.
- //
- if(ucTimeout4mS)
- {
- //
- // Determine what the timeout is for this report given the time
- // since the last report of this type was sent.
- //
- if(psIdle->ulTimeSinceReportmS >=
- ((unsigned int)ucTimeout4mS * 4))
- {
- psIdle->usTimeTillNextmS = 0;
- bReportNeeded = true;
- }
- else
- {
- psIdle->usTimeTillNextmS =
- (((unsigned short)ucTimeout4mS * 4) -
- psIdle->ulTimeSinceReportmS);
- }
- }
- }
- }
- //
- // If we get to here and bReportNeeded is true, this means we need to
- // send back at least one of the input reports as soon as possible. Try
- // to do this immediately.
- //
- if(bReportNeeded)
- {
- ProcessIdleTimers(psDevice, 0);
- }
- }
- //*****************************************************************************
- //
- // Find the idle timeout for a given HID input report.
- //
- // \param psDevice points to the HID device whose report idle timeout is to be
- // found.
- // \param ucReportID identifies the report whose timeout is requested. If 0,
- // the timeout for the first report is returns, regardless of its ID (or
- // whether it has one).
- //
- // This function returns the current idle timeout for a given HID input report.
- // The value returned is expressed in terms of 4mS intervals. Convert to
- // milliseconds by multiplying by 4. If the return value is 0, this indicates
- // that an infinite timeout is currently set and the device will not send the
- // report unless a state change occurs.
- //
- // \return Returns the current idle timeout for the given report.
- //
- //*****************************************************************************
- static unsigned int
- GetIdleTimeout(const tUSBDHIDDevice *psDevice, unsigned char ucReportID)
- {
- unsigned int ulLoop;
- tHIDReportIdle *psIdle;
- //
- // Search through all the input reports looking for ones that fit the
- // requirements.
- //
- for(ulLoop = 0; ulLoop < psDevice->ucNumInputReports; ulLoop++)
- {
- psIdle = &psDevice->psReportIdle[ulLoop];
- //
- // If the report ID passed matches the report ID in the idle timer
- // control structure or we were passed a report ID of zero, which
- // indicates that all timers are to be set...
- //
- if(!ucReportID || (ucReportID == psIdle->ucReportID))
- {
- //
- // We found a report matching the required ID or we were not passed
- // an ID and we are looking at the first report information.
- //
- return((unsigned int)psIdle->ucDuration4mS);
- }
- }
- //
- // If we drop out, the report couldn't be found so we need to indicate
- // an error.
- //
- return(HID_NOT_FOUND);
- }
- //*****************************************************************************
- //
- // Find the n-th HID class descriptor of a given type in the client-provided
- // descriptor table.
- //
- // \param psDevice points to the HID device which is to be searched for the
- // required class descriptor.
- // \param ucType is the type of class descriptor being requested. This will
- // be either USB_HID_DTYPE_REPORT or USB_HID_DTYPE_PHYSICAL.
- // \param ulIndex is the zero-based index of the descriptor that is being
- // requested.
- //
- // This function parses the supplied HID descriptor to find the index into the
- // sClassDescriptor array that corresponds to the requested descriptor. If
- // a descriptor with the requested index does not exist, HID_NOT_FOUND will be
- // returned unless the request is for a physical descriptor and at least one
- // such descriptor exists. In this case, the index returned will be for the
- // last physical descriptor (as required by the HID spec 7.1.1).
- //
- // \return Returns the index of the descriptor within the sClassDescriptor
- // of the tHIDDevice structure if found or HID_NOT_FOUND otherwise.
- //
- //*****************************************************************************
- static unsigned int
- FindHIDDescriptor(const tUSBDHIDDevice *psDevice, unsigned char ucType,
- unsigned int ulIndex, unsigned int *pulLen)
- {
- tBoolean bFoundType;
- unsigned int ulLoop;
- unsigned int ulCount;
- unsigned int ulLastFound;
- const tHIDClassDescriptorInfo *psDesc;
- //
- // Remember that we have not found any descriptor with a matching type yet.
- //
- bFoundType = false;
- ulCount = 0;
- ulLastFound = 0;
- //
- // Walk through all the class descriptors looking for the one which
- // matches the requested index and type.
- //
- for(ulLoop = 0; ulLoop < psDevice->psHIDDescriptor->bNumDescriptors;
- ulLoop++)
- {
- psDesc = &(psDevice->psHIDDescriptor->sClassDescriptor[ulLoop]);
- if(psDesc->bDescriptorType == ucType)
- {
- //
- // We found a descriptor of the correct type. Is this the
- // correct index?
- //
- bFoundType = true;
- //
- // Is this the descriptor we are looking for?
- //
- if(ulCount == ulIndex)
- {
- //
- // Yes - we found it so return the index and size to the
- // caller.
- //
- *pulLen = (unsigned int)psDesc->wDescriptorLength;
- return(ulLoop);
- }
- else
- {
- //
- // Update our count and keep looking. Remember where we were
- // when we found this descriptor in case we need to return the
- // last physical descriptor.
- //
- ulCount++;
- ulLastFound = ulLoop;
- }
- }
- }
- //
- // If we drop out, we didn't find the requested descriptor. Now handle
- // the special case of a physical descriptor - if we found any physical
- // descriptors, return the last one.
- //
- if((ucType == USB_HID_DTYPE_PHYSICAL) && bFoundType)
- {
- //
- // Get the length of the last descriptor we found.
- //
- psDesc = &(psDevice->psHIDDescriptor->sClassDescriptor[ulLastFound]);
- *pulLen = (unsigned int)psDesc->wDescriptorLength;
- //
- // Return the index to the caller.
- //
- return(ulLastFound);
- }
- else
- {
- //
- // We couldn't find the descriptor so return an appropriate error.
- //
- return(HID_NOT_FOUND);
- }
- }
- //*****************************************************************************
- //
- // Schedule transmission of the next packet forming part of an input report.
- //
- // \param psInst points to the device instance whose input report is to be
- // sent.
- //
- // This function is called to transmit the next packet of an input report
- // passed to the driver via a call to USBDHIDReportWrite. If any data remains
- // to be sent, a USB packet is written to the FIFO and scheduled for
- // transmission to the host. The function ensures that reports are sent as
- // a sequence of full packets followed by either a single short packet or a
- // packet with no data to indicate the end of the transaction.
- //
- //*****************************************************************************
- static int
- ScheduleReportTransmission(tHIDInstance *psInst)
- {
- unsigned int ulNumBytes;
- unsigned char *pucData;
- int iRetcode;
- //
- // Set the number of bytes to send this iteration.
- //
- ulNumBytes = (unsigned int)(psInst->usInReportSize -
- psInst->usInReportIndex);
- //
- // Limit individual transfers to the maximum packet size for the endpoint.
- //
- if(ulNumBytes > INT_IN_EP_MAX_SIZE)
- {
- ulNumBytes = INT_IN_EP_MAX_SIZE;
- }
- //
- // Where are we sending this data from?
- //
- pucData = psInst->pucInReportData + psInst->usInReportIndex;
- //
- // Put the data in the correct FIFO.
- //
- iRetcode = USBEndpointDataPut(psInst->ulUSBBase, psInst->ucINEndpoint,
- pucData, ulNumBytes);
- if(iRetcode != -1)
- {
- //
- // Update the count and index ready for the next time round.
- //
- psInst->usInReportIndex += ulNumBytes;
- //
- // Send out the current data.
- //
- iRetcode = USBEndpointDataSend(psInst->ulUSBBase, psInst->ucINEndpoint,
- USB_TRANS_IN);
- }
- //
- // Tell the caller how we got on.
- //
- return(iRetcode);
- }
- //*****************************************************************************
- //
- // 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 interrupt 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.
- //
- //*****************************************************************************
- static tBoolean
- ProcessDataFromHost(const tUSBDHIDDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tHIDInstance *psInst;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint, 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 signaled later during tick processing.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, HID_DO_PACKET_RX, true);
- //
- // How big is the packet we've just been sent?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase,
- psInst->ucOUTEndpoint);
- //
- // 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 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 interrupt 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.
- //
- //*****************************************************************************
- static tBoolean
- ProcessDataToHost(const tUSBDHIDDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- unsigned int ulEPStatus;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucINEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucINEndpoint,
- ulEPStatus);
- //
- // Our last packet was transmitted successfully. Is there any more data to
- // send or have we finished sending the whole report? We know we finished
- // if the usInReportIndex has reached the usInReportSize value.
- //
- if(psInst->usInReportSize == psInst->usInReportIndex)
- {
- //
- // We finished sending the last report so are idle once again.
- //
- psInst->eHIDTxState = HID_STATE_IDLE;
- //
- // Notify the client that the report transmission completed.
- //
- psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
- psInst->usInReportSize, (void *)0);
- //
- // Do we have any reports to send as a result of idle timer timeouts?
- //
- if(psInst->usDeferredOpFlags & (1 << HID_DO_SEND_IDLE_REPORT))
- {
- //
- // Yes - send reports for any timers that expired recently.
- //
- ProcessIdleTimers(psDevice, 0);
- }
- }
- else
- {
- //
- // There must be more data or a zero length packet waiting to be sent
- // so go ahead and do this.
- //
- ScheduleReportTransmission(psInst);
- }
- 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 tUSBDHIDDevice *psHIDInst;
- tHIDInstance *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.
- //
- psHIDInst = (const tUSBDHIDDevice *)pvInstance;
- psInst = psHIDInst->psPrivateHIDData;
- //
- // Handler for the interrupt OUT data endpoint.
- //
- if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint)))
- {
- //
- // Data is being sent to us from the host.
- //
- ProcessDataFromHost(pvInstance, ulStatus, ulIndex);
- }
- //
- // Handler for the interrupt IN data endpoint.
- //
- if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint)))
- {
- ProcessDataToHost(pvInstance, ulStatus, ulIndex);
- }
- }
- //*****************************************************************************
- //
- // Called by the USB stack whenever a configuration change occurs.
- //
- //*****************************************************************************
- static void
- HandleConfigChange(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // Set all our endpoints to idle state.
- //
- psInst->eHIDRxState = HID_STATE_IDLE;
- psInst->eHIDTxState = HID_STATE_IDLE;
- //
- // If we are not currently connected let the client know we are open for
- // business.
- //
- if(!psInst->bConnected)
- {
- //
- // Pass the connected event to the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_CONNECTED, 0,
- (void *)0);
- }
- //
- // Clear the idle timers for each input report.
- //
- ClearIdleTimers(psDevice);
- //
- // Remember that we are connected.
- //
- psInst->bConnected = true;
- }
- //*****************************************************************************
- //
- // Device instance specific handler.
- //
- //*****************************************************************************
- static void
- HandleDevice(void *pvInstance, unsigned int ulRequest, void *pvRequestData)
- {
- tHIDInstance *psInst;
- unsigned char *pucData;
- //
- // Create the serial instance data.
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // 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:
- {
- psInst->ucInterface = 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)
- {
- psInst->ucINEndpoint =
- INDEX_TO_USB_EP((pucData[1] & 0x7f));
- }
- else
- {
- //
- // Extract the new endpoint number.
- //
- psInst->ucOUTEndpoint =
- INDEX_TO_USB_EP(pucData[1] & 0x7f);
- }
- break;
- }
- default:
- {
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device is
- // disconnected from the host.
- //
- //*****************************************************************************
- static void
- HandleDisconnect(void *pvInstance)
- {
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDHIDDevice *)pvInstance;
- //
- // If we are not currently connected so let the client know we are open
- // for business.
- //
- if(psDevice->psPrivateHIDData->bConnected)
- {
- //
- // Pass the disconnected event to the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_DISCONNECTED,
- 0, (void *)0);
- }
- //
- // Remember that we are no longer connected.
- //
- psDevice->psPrivateHIDData->bConnected = false;
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever a request for a
- // non-standard descriptor is received.
- //
- // \param pvInstance is the instance data for this request.
- // \param pUSBRequest points to the request received.
- //
- // This call parses the provided request structure and determines which
- // descriptor is being requested. Assuming the descriptor can be found, it is
- // scheduled for transmission via endpoint zero. If the descriptor cannot be
- // found, the endpoint is stalled to indicate an error to the host.
- //
- //*****************************************************************************
- static void
- HandleGetDescriptor(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex)
- {
- unsigned int ulSize;
- unsigned int ulDesc;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Which device are we dealing with?
- //
- psDevice = pvInstance;
- //
- // Which type of class descriptor are we being asked for?
- //
- switch(pUSBRequest->wValue >> 8)
- {
- //
- // This is a request for a HID report or physical descriptor.
- //
- case USB_HID_DTYPE_REPORT:
- case USB_HID_DTYPE_PHYSICAL:
- {
- //
- // Find the index to the descriptor that is being queried.
- //
- ulSize = 0;
- ulDesc = FindHIDDescriptor(psDevice, pUSBRequest->wValue >> 8,
- pUSBRequest->wValue & 0xFF,
- &ulSize);
- //
- // Did we find the descriptor?
- //
- if(ulDesc == HID_NOT_FOUND)
- {
- //
- // No - stall the endpoint and return.
- //
- USBDCDStallEP0(ulIndex);
- return;
- }
- //
- // If there is more data to send than the host requested then just
- // send the requested amount of data.
- //
- if(ulSize > pUSBRequest->wLength)
- {
- ulSize = pUSBRequest->wLength;
- }
- //
- // Send the data via endpoint 0.
- //
- USBDCDSendDataEP0(0,
- (unsigned char *)psDevice->ppClassDescriptors[ulDesc], ulSize);
- break;
- }
- //
- // This is a request for the HID descriptor (as found in the
- // configuration descriptor following the relevant interface).
- //
- case USB_HID_DTYPE_HID:
- {
- //
- // How big is the HID descriptor?
- //
- ulSize = (unsigned int)psDevice->psHIDDescriptor->bLength;
- //
- // If there is more data to send than the host requested then just
- // send the requested amount of data.
- //
- if(ulSize > pUSBRequest->wLength)
- {
- ulSize = pUSBRequest->wLength;
- }
- //
- // Send the data via endpoint 0.
- //
- USBDCDSendDataEP0(0, (unsigned char *)psDevice->psHIDDescriptor,
- ulSize);
- break;
- }
- //
- // This was an unknown request so stall.
- //
- default:
- {
- USBDCDStallEP0(ulIndex);
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever a non-standard
- // request is received.
- //
- // \param pvInstance is the instance data for this HID device.
- // \param pUSBRequest points to the request received.
- //
- // This call parses the provided request structure. Assuming the request is
- // understood, it is handled and any required response generated. If the
- // request cannot be handled by this device class, endpoint zero is stalled to
- // indicate an error to the host.
- //
- //*****************************************************************************
- static void
- HandleRequest(void *pvInstance, tUSBRequest *pUSBRequest,
- unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- unsigned char ucProtocol;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Which device are we dealing with?
- //
- psDevice = pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // Make sure the request was for this interface.
- //
- if(pUSBRequest->wIndex != psInst->ucInterface)
- {
- return;
- }
- //
- // Determine the type of request.
- //
- switch(pUSBRequest->bRequest)
- {
- //
- // A Set Report request is received from the host when it sends an
- // Output report via endpoint 0.
- //
- case USBREQ_SET_REPORT:
- {
- //
- // Ask the application for a buffer large enough to hold the
- // report we are to be sent.
- //
- psInst->usOutReportSize = pUSBRequest->wLength;
- psInst->pucOutReportData =
- (unsigned char *)psDevice->pfnRxCallback(
- psDevice->pvRxCBData,
- USBD_HID_EVENT_GET_REPORT_BUFFER,
- pUSBRequest->wValue,
- (void *)(unsigned int)(pUSBRequest->wLength));
- //
- // Did the client provide us a buffer?
- //
- if(!psInst->pucOutReportData)
- {
- //
- // The application couldn't provide us a buffer so stall the
- // request.
- //
- USBDCDStallEP0(ulIndex);
- }
- else
- {
- //
- // The client provided us a buffer to read the report into
- // so request the data from the host.
- //
- //
- // Set the state to indicate we are waiting for data.
- //
- psInst->eHIDRxState = HID_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, psInst->pucOutReportData,
- (unsigned int)pUSBRequest->wLength);
- //
- // Need to ACK the data on end point 0 in this case. Do this
- // after requesting the data to prevent race conditions that
- // occur if you acknowledge before setting up to receive the
- // request data.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- }
- break;
- }
- //
- // A Get Report request is used by the host to poll a device for its
- // current state.
- //
- case USBREQ_GET_REPORT:
- {
- unsigned int ulSize;
- unsigned char *pucReport;
- //
- // Get the latest report from the application.
- //
- ulSize = psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USBD_HID_EVENT_GET_REPORT,
- pUSBRequest->wValue, &pucReport);
- //
- // Need to ACK the data on end point 0 in this case.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- //
- // ..then send back the requested report.
- //
- psInst->bGetRequestPending = true;
- USBDCDSendDataEP0(0, pucReport, ulSize);
- break;
- }
- //
- // A set IDLE request has been made. This indicates to us how often a
- // given report should be sent back to the host in the absence of any
- // change in state of the device.
- //
- case USBREQ_SET_IDLE:
- {
- //
- // Set the idle timeout for the requested report(s).
- //
- SetIdleTimeout(psDevice, pUSBRequest->wValue & 0xFF,
- (pUSBRequest->wValue >> 8) & 0xFF);
- //
- // Need to ACK the data on end point 0 in this case.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- break;
- }
- //
- // A get IDLE request has been made. This request queries the current
- // idle timeout for a given report.
- //
- case USBREQ_GET_IDLE:
- {
- unsigned int ulTimeout;
- //
- // Determine the timeout for the requested report.
- //
- ulTimeout = GetIdleTimeout(psDevice, pUSBRequest->wValue);
- if(ulTimeout != HID_NOT_FOUND)
- {
- //
- // Need to ACK the data on end point 0 in this case.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- //
- // Send our response to the host.
- //
- USBDCDSendDataEP0(0, (unsigned char *)&ulTimeout, 1);
- }
- else
- {
- //
- // The report ID was not found so stall the endpoint.
- //
- USBDCDStallEP0(ulIndex);
- }
- break;
- }
- //
- // Set either boot or report protocol for reports sent from the device.
- // This is only supported by devices in the boot subclass.
- //
- case USBREQ_SET_PROTOCOL:
- {
- if(psDevice->ucSubclass == USB_HID_SCLASS_BOOT)
- {
- //
- // We need to ACK the data on end point 0 in this case.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- //
- // We are a boot subclass device so pass this on to the
- // application.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USBD_HID_EVENT_SET_PROTOCOL,
- pUSBRequest->wValue,
- (void *)0);
- }
- else
- {
- //
- // This is not a boot subclass device so stall the endpoint to
- // show that we don't support this request.
- //
- USBDCDStallEP0(ulIndex);
- }
- break;
- }
- //
- // Inform the host of the protocol, boot or report, that is currently
- // in use. This is only supported by devices in the boot subclass.
- //
- case USBREQ_GET_PROTOCOL:
- {
- if(psDevice->ucSubclass == USB_HID_SCLASS_BOOT)
- {
- //
- // We need to ACK the data on end point 0 in this case.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
- //
- // We are a boot subclass device so pass this on to the
- // application callback to get the answer.
- //
- ucProtocol = (unsigned char)psDevice->pfnRxCallback(
- psDevice->pvRxCBData, USBD_HID_EVENT_GET_PROTOCOL, 0,
- (void *)0);
- //
- // Send our response to the host.
- //
- USBDCDSendDataEP0(0, (unsigned char *)&ucProtocol, 1);
- }
- else
- {
- //
- // This is not a boot subclass device so stall the endpoint to
- // show that we don't support this request.
- //
- USBDCDStallEP0(ulIndex);
- }
- break;
- }
- //
- // This request was not recognized so stall.
- //
- default:
- {
- USBDCDStallEP0(ulIndex);
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the data requested
- // on endpoint zero is received.
- //
- //*****************************************************************************
- static void
- HandleEP0DataReceived(void *pvInstance, unsigned int ulDataSize,
- unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Which device are we dealing with?
- //
- psDevice = pvInstance;
- //
- // If we were not passed any data, just return.
- //
- if(ulDataSize == 0)
- {
- return;
- }
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // Make sure we are actually expecting something.
- //
- if(psInst->eHIDRxState != HID_STATE_WAIT_DATA)
- {
- return;
- }
- //
- // Change the endpoint state back to idle now that we have been passed
- // the data we were waiting for.
- //
- psInst->eHIDRxState = HID_STATE_IDLE;
- //
- // The only things we ever request via endpoint zero are reports sent to
- // us via a Set_Report request. Pass the newly received report on to
- // the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData, USBD_HID_EVENT_SET_REPORT,
- psInst->usOutReportSize,
- psInst->pucOutReportData);
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the data sent on
- // endpoint zero is received and acknowledged by the host.
- //
- //*****************************************************************************
- static void
- HandleEP0DataSent(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Which device are we dealing with?
- //
- psDevice = pvInstance;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // If we just sent a report in response to a Get_Report request, send an
- // event to the application telling it that the transmission completed.
- //
- if(psInst->bGetRequestPending)
- {
- //
- // Clear the flag now that we are sending the application callback.
- //
- psInst->bGetRequestPending = false;
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USBD_HID_EVENT_REPORT_SENT, 0, (void *)0);
- }
- return;
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device is
- // reset. If we are currently connected, send a disconnect event at this
- // point.
- //
- //*****************************************************************************
- static void
- HandleReset(void *pvInstance)
- {
- ASSERT(pvInstance != 0);
- //
- // Merely call the disconnect handler. This causes a disconnect message to
- // be sent to the client if we think we are currently connected.
- //
- HandleDisconnect(pvInstance);
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the bus is put into
- // suspend state.
- //
- //*****************************************************************************
- static void
- HandleSuspend(void *pvInstance)
- {
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDHIDDevice *)pvInstance;
- //
- // Pass the event on to the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData, 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)
- {
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDHIDDevice *)pvInstance;
- //
- // Pass the event on to the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- 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 pvInstance is the instance data for this request.
- // \param ulTimemS is the elapsed time in milliseconds since the last call
- // to this function.
- //
- // \return None.
- //
- //*****************************************************************************
- static void
- HIDTickHandler(void *pvInstance, unsigned int ulTimemS, unsigned int ulIndex)
- {
- tHIDInstance *psInst;
- unsigned int ulSize;
- const tUSBDHIDDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psDevice = (const tUSBDHIDDevice *)pvInstance;
- //
- // Get our instance data pointer.
- //
- psInst = psDevice->psPrivateHIDData;
- //
- // If we are connected, process our idle timers.
- //
- if(psInst->bConnected)
- {
- ProcessIdleTimers(psDevice, ulTimemS);
- }
- //
- // Do we have a deferred receive waiting
- //
- if(psInst->usDeferredOpFlags & (1 << HID_DO_PACKET_RX))
- {
- //
- // Yes - how big is the waiting packet?
- //
- ulSize = USBEndpointDataAvail(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint);
- //
- // Tell the client that there is a packet waiting for it.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_RX_AVAILABLE, ulSize, (void *)0);
- }
- return;
- }
- //*****************************************************************************
- //
- //! Initializes HID device operation for a given USB controller.
- //!
- //! \param ulIndex is the index of the USB controller which is to be
- //! initialized for HID device operation.
- //! \param psDevice points to a structure containing parameters customizing
- //! the operation of the HID device.
- //!
- //! An application wishing to offer a USB HID interface to a 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.
- //!
- //! On successful completion, this function will return the \e psDevice pointer
- //! passed to it. This must be passed on all future calls from the application
- //! to the HID device class driver.
- //!
- //! The USB HID device class API offers the application a report-based transmit
- //! interface for Input reports. Output reports may be received via the
- //! control endpoint or via a dedicated Interrupt OUT endpoint. If using the
- //! dedicated endpoint, report data is delivered to the application packet-by-
- //! packet. If the application uses reports longer than 64 bytes and would
- //! rather receive full reports, it may use a USB buffer above the receive
- //! channel to allow full reports to be read.
- //!
- //! Transmit Operation:
- //!
- //! Calls to USBDHIDReportWrite() pass complete reports to the driver for
- //! transmission. These will be transmitted to the host using as many USB
- //! packets as are necessary to complete the transmission.
- //!
- //! Once a full Input report has been acknowledged by the USB host, a
- //! USB_EVENT_TX_COMPLETE event is sent to the application transmit callback to
- //! inform it that another report may be transmitted.
- //!
- //! Receive Operation (when using a dedicated interrupt OUT endpoint):
- //!
- //! An incoming USB data packet will result in a call to the application
- //! callback with event USB_EVENT_RX_AVAILABLE. The application must then
- //! call USBDHIDPacketRead(), passing a buffer capable of holding the received
- //! packet. The size of the packet may be determined by calling function
- //! USBDHIDRxPacketAvailable() prior to reading the packet.
- //!
- //! Receive Operation (when not using a dedicated OUT endpoint):
- //!
- //! If no dedicated OUT endpoint is used, Output and Feature reports are sent
- //! from the host using the control endpoint, endpoint zero. When such a
- //! report is received, USBD_HID_EVENT_GET_REPORT_BUFFER is sent to the
- //! application which must respond with a buffer large enough to hold the
- //! report. The device class driver will then copy the received report into
- //! the supplied buffer before sending USBD_HID_EVENT_SET_REPORT to indicate
- //! that the report is now available.
- //!
- //! \note The application must not make any calls to the low level USB device
- //! interface if interacting with USB via the USB HID device class API. Doing
- //! so will cause unpredictable (though almost certainly unpleasant) behavior.
- //!
- //! \return Returns NULL on failure or the \e psDevice pointer on success.
- //
- //*****************************************************************************
- void *
- USBDHIDInit(unsigned int ulIndex, const tUSBDHIDDevice *psDevice)
- {
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- ASSERT(psDevice->ppStringDescriptors);
- ASSERT(psDevice->psPrivateHIDData);
- ASSERT(psDevice->pfnRxCallback);
- ASSERT(psDevice->pfnTxCallback);
- ASSERT(psDevice->ppClassDescriptors);
- ASSERT(psDevice->psHIDDescriptor);
- ASSERT((psDevice->ucNumInputReports == 0) || psDevice->psReportIdle);
- USBDHIDCompositeInit(ulIndex, psDevice);
- //
- // All is well so now pass the descriptors to the lower layer and put
- // the HID device on the bus.
- //
- USBDCDInit(ulIndex, psDevice->psPrivateHIDData->psDevInfo);
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return((void *)psDevice);
- }
- //*****************************************************************************
- //
- //! Initializes HID device operation for a given USB controller.
- //!
- //! This function is used for initializing an instance related information of the
- //! HID device.
- //!
- //! \param ulIndex is the index of the USB controller which is to be
- //! initialized for HID device operation.
- //! \param psDevice points to a structure containing parameters customizing
- //! the operation of the HID device.
- //!
- //! \return Returns NULL on failure or the \e psDevice pointer on success.
- //
- //*****************************************************************************
- void *
- USBDHIDCompositeInit(unsigned int ulIndex, const tUSBDHIDDevice *psDevice)
- {
- tHIDInstance *psInst;
- tDeviceDescriptor *psDevDesc;
- tInterfaceDescriptor *psDevIf;
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- ASSERT(psDevice->ppStringDescriptors);
- ASSERT(psDevice->psPrivateHIDData);
- ASSERT(psDevice->pfnRxCallback);
- ASSERT(psDevice->pfnTxCallback);
- ASSERT(psDevice->ppClassDescriptors);
- ASSERT(psDevice->psHIDDescriptor);
- ASSERT((psDevice->ucNumInputReports == 0) || psDevice->psReportIdle);
- 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
- //
- // Initialize the workspace in the passed instance structure.
- //
- psInst = psDevice->psPrivateHIDData;
- psInst->psConfDescriptor = (tConfigDescriptor *)g_pHIDDescriptor;
- psInst->psDevInfo = &g_sHIDDeviceInfo;
- psInst->ulUSBBase = g_USBInstance[ulIndex].uiBaseAddr;
- psInst->eHIDRxState = HID_STATE_UNCONFIGURED;
- psInst->eHIDTxState = HID_STATE_UNCONFIGURED;
- psInst->usDeferredOpFlags = 0;
- psInst->bConnected = false;
- psInst->bGetRequestPending = false;
- psInst->bSendInProgress = false;
- psInst->usInReportIndex = 0;
- psInst->usInReportSize = 0;
- psInst->pucInReportData = (unsigned char *)0;
- psInst->usOutReportSize = 0;
- psInst->pucOutReportData = (unsigned char *)0;
- //
- // Set the default endpoint and interface assignments.
- //
- psInst->ucINEndpoint = INT_IN_ENDPOINT;
- psInst->ucOUTEndpoint = INT_OUT_ENDPOINT;
- psInst->ucInterface = 0;
- //
- // Fix up the device descriptor with the client-supplied values.
- //
- psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
- psDevDesc->idVendor = psDevice->usVID;
- psDevDesc->idProduct = psDevice->usPID;
- //
- // Fix up the configuration descriptor with client-supplied values.
- //
- psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
- psInst->psConfDescriptor->bMaxPower =
- (unsigned char)(psDevice->usMaxPowermA / 2);
- //
- // Slot the client's HID descriptor into our standard configuration
- // descriptor.
- //
- g_sHIDDescriptorSection.ucSize = psDevice->psHIDDescriptor->bLength;
- g_sHIDDescriptorSection.pucData =
- (unsigned char *)psDevice->psHIDDescriptor;
- //
- // Fix up the interface and endpoint descriptors depending upon client
- // choices.
- //
- psDevIf = (tInterfaceDescriptor *)g_pHIDInterface;
- psDevIf->bNumEndpoints = psDevice->bUseOutEndpoint ? 2 : 1;
- psDevIf->bInterfaceSubClass = psDevice->ucSubclass;
- psDevIf->bInterfaceProtocol = psDevice->ucProtocol;
- //
- // If necessary, remove the interrupt OUT endpoint from the configuration
- // descriptor.
- //
- if(psDevice->bUseOutEndpoint == false)
- {
- g_sHIDConfigHeader.ucNumSections = (NUM_HID_SECTIONS - 1);
- }
- else
- {
- g_sHIDConfigHeader.ucNumSections = NUM_HID_SECTIONS;
- }
- //
- // Plug in the client's string table to the device information
- // structure.
- //
- psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
- psInst->psDevInfo->ulNumStringDescriptors
- = psDevice->ulNumStringDescriptors;
- psInst->psDevInfo->pvInstance = (void *)psDevice;
- //
- // Initialize the input report idle timers if any input reports exist.
- //
- ClearIdleTimers(psDevice);
- //
- // Register our tick handler (this must be done after USBDCDInit).
- //
- InternalUSBRegisterTickHandler(USB_TICK_HANDLER_DEVICE,
- HIDTickHandler,
- (void *)psDevice);
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return((void *)psDevice);
- }
- //*****************************************************************************
- //
- //! Shuts down the HID device.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDHIDInit().
- //!
- //! This function terminates HID operation for the instance supplied and
- //! removes the device from the USB bus. This function should not be called
- //! if the HID 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
- USBDHIDTerm(void *pvInstance)
- {
- tHIDInstance *psInst;
- int index;
- ASSERT(pvInstance);
- //
- // Get a pointer to our instance data.
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // Terminate the requested instance.
- //
- USB_BASE_TO_INDEX(psInst->ulUSBBase, index);
- USBDCDTerm(index);
- psInst->ulUSBBase = 0;
- psInst->psDevInfo = (tDeviceInfo *)0;
- psInst->psConfDescriptor = (tConfigDescriptor *)0;
- }
- //*****************************************************************************
- //
- //! Sets the client-specific pointer parameter for the receive channel
- //! callback.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDHIDInit().
- //! \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 USBDHIDInit().
- //!
- //! If a client wants to make runtime changes in the callback pointer, it must
- //! ensure that the pvInstance structure passed to USBDHIDInit() 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 *
- USBDHIDSetRxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback data for the receive channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDHIDDevice *)pvInstance)->pvRxCBData;
- ((tUSBDHIDDevice *)pvInstance)->pvRxCBData = pvCBData;
- //
- // Return the previous callback data value.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Sets the client-specific data pointer for the transmit callback.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDHIDInit().
- //! \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 data pointer passed in
- //! the first parameter on all callbacks to the \e pfnTxCallback function
- //! passed on USBDHIDInit().
- //!
- //! If a client wants to make runtime changes in the callback data, it must
- //! ensure that the pvInstance structure passed to USBDHIDInit() resides in
- //! RAM. If this structure is in flash, callback data changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback data pointer that was being used for
- //! this instance's transmit callback.
- //
- //*****************************************************************************
- void *
- USBDHIDSetTxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback data for the transmit channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDHIDDevice *)pvInstance)->pvTxCBData;
- ((tUSBDHIDDevice *)pvInstance)->pvTxCBData = pvCBData;
- //
- // Return the previous callback data value.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Transmits a HID device report to the USB host via the HID interrupt IN
- //! endpoint.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDHIDInit().
- //! \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 is ignored in this implementation. This parameter is required
- //! to ensure compatibility with other device class drivers and USB buffers.
- //!
- //! This function schedules the supplied data for transmission to the USB
- //! host in a single USB transaction using as many packets as it takes to send
- //! all the data in the report. If no transmission is currently ongoing,
- //! the first packet of data is immediately copied to the relevant USB endpoint
- //! FIFO for transmission. Whenever all the report data has been acknowledged
- //! by the host, a \b USB_EVENT_TX_COMPLETE event will be sent to the
- //! application transmit callback indicating that another report can now be
- //! transmitted.
- //!
- //! The caller must ensure that the data pointed to by pucData remains
- //! accessible and unaltered until the \b USB_EVENT_TX_COMPLETE is received.
- //!
- //! \return Returns the number of bytes actually scheduled for transmission.
- //! At this level, this will either be the number of bytes passed or 0 to
- //! indicate a failure.
- //
- //*****************************************************************************
- unsigned int
- USBDHIDReportWrite(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- tHIDInstance *psInst;
- int iRetcode;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // Set a flag indicating that we are currently in the process of sending
- // a packet.
- //
- psInst->bSendInProgress = true;
- //
- // Can we send the data provided?
- //
- if(psInst->eHIDTxState != HID_STATE_IDLE)
- {
- //
- // We are in the middle of sending another report. Return 0 to
- // indicate that we can't send this report until the previous one
- // finishes.
- //
- psInst->bSendInProgress = false;
- return (0);
- }
- //
- // Clear the elapsed time since this report was last sent.
- //
- if(ulLength)
- {
- ClearReportTimer(pvInstance, *pcData);
- }
- //
- // Keep track of the whereabouts of the report so that we can send it in
- // multiple packets if necessary.
- //
- psInst->pucInReportData = pcData;
- psInst->usInReportIndex = 0;
- psInst->usInReportSize = ulLength;
- //
- // Schedule transmission of the first packet of the report.
- //
- psInst->eHIDTxState = HID_STATE_WAIT_DATA;
- iRetcode = ScheduleReportTransmission(psInst);
- //
- // Clear the flag we use to indicate that we are in the midst of sending
- // a packet.
- //
- psInst->bSendInProgress = false;
- //
- // 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 interrupt OUT
- //! endpoint (if in use).
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDHIDInit().
- //! \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. If the driver detects that the
- //! entire packet has been read, it is acknowledged to the host.
- //!
- //! 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
- USBDHIDPacketRead(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- unsigned int ulEPStatus, ulPkt;
- unsigned int ulCount;
- tHIDInstance *psInst;
- int iRetcode;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // How many bytes are available for us to receive?
- //
- ulPkt = USBEndpointDataAvail(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- //
- // Get as much data as we can.
- //
- ulCount = ulLength;
- iRetcode = USBEndpointDataGet(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- 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->ucOUTEndpoint,
- ulEPStatus);
- //
- // Acknowledge the data, thus freeing the host to send the
- // next packet.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- true);
- //
- // Clear the flag we set to indicate that a packet read is
- // pending.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags,
- HID_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 USBDHIDInit().
- //!
- //! This function indicates to the caller whether or not it is safe to send a
- //! new report using a call to USBDHIDReportWrite(). 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. Since the function
- //! USBDHIDReportWrite() can accept full reports longer than a single USB
- //! packet, the caller should be aware that the returned value from this
- //! class driver, unlike others, does not indicate the maximum size of report
- //! that can be written but is merely an indication that another report can be
- //! written.
- //!
- //! \return Returns 0 if an outgoing report is still being transmitted or 64
- //! if no transmission is currently in progress.
- //
- //*****************************************************************************
- unsigned int
- USBDHIDTxPacketAvailable(void *pvInstance)
- {
- tHIDInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer.
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // Do we have a packet transmission currently ongoing?
- //
- if(psInst->eHIDTxState != HID_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 (INT_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 USBDHIDInit().
- //!
- //! 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
- USBDHIDRxPacketAvailable(void *pvInstance)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tHIDInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDHIDDevice *)pvInstance)->psPrivateHIDData;
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // Yes - a packet is waiting. How big is it?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- return (ulSize);
- }
- else
- {
- //
- // There is no packet waiting to be received.
- //
- return (0);
- }
- }
- //*****************************************************************************
- //
- //! Reports the device power status (bus- or self-powered) to the USB library.
- //!
- //! \param pvInstance is the pointer to the HID 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
- USBDHIDPowerStatusSet(void *pvInstance, unsigned char ucPower)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- USBDCDPowerStatusSet(0, ucPower);
- }
- //*****************************************************************************
- //
- //! Requests a remote wake up to resume communication when in suspended state.
- //!
- //! \param pvInstance is the pointer to the HID device instance structure.
- //!
- //! When the bus is suspended, an application which supports remote wake up
- //! (advertised to the host via the configuration descriptor) may call this
- //! function to initiate remote wake up signaling to the host. If the remote
- //! wake up feature has not been disabled by the host, this will cause the bus
- //! to resume operation within 20mS. If the host has disabled remote wake up,
- //! \b false will be returned to indicate that the wake up request was not
- //! successful.
- //!
- //! \return Returns \b true if the remote wake up is not disabled and the
- //! signaling was started or \b false if remote wake up is disabled or if
- //! signaling is currently ongoing following a previous call to this function.
- //
- //*****************************************************************************
- tBoolean
- USBDHIDRemoteWakeupRequest(void *pvInstance)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- return(USBDCDRemoteWakeupRequest(0));
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|