1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823 |
- /*++
- Copyright (c) 2013 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- usbcore.c
- Abstract:
- This module implements the USB core library.
- Author:
- Evan Green 15-Jan-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/fw/acpitabs.h>
- #include "usbcore.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the initial allocation size for a configuration descriptor.
- //
- #define USB_INITIAL_CONFIGURATION_LENGTH 0xFF
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- UsbpCancelTransfer (
- PUSB_TRANSFER_PRIVATE Transfer
- );
- VOID
- UsbpDestroyTransfer (
- PUSB_TRANSFER Transfer
- );
- KSTATUS
- UsbpGetConfiguration (
- PUSB_DEVICE Device,
- UCHAR ConfigurationNumber,
- BOOL NumberIsIndex,
- PUSB_CONFIGURATION *Configuration
- );
- KSTATUS
- UsbpSubmitTransfer (
- PUSB_TRANSFER Transfer,
- ULONG PrivateFlags,
- BOOL PolledMode
- );
- KSTATUS
- UsbpCreateEndpointsForInterface (
- PUSB_DEVICE Device,
- PUSB_INTERFACE Interface
- );
- PUSB_ENDPOINT
- UsbpGetDeviceEndpoint (
- PUSB_DEVICE Device,
- UCHAR EndpointNumber
- );
- VOID
- UsbpCompletedTransferWorker (
- PVOID Parameter
- );
- RUNLEVEL
- UsbpAcquireCompletedTransfersLock (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue
- );
- VOID
- UsbpReleaseCompletedTransfersLock (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue,
- RUNLEVEL OldRunLevel
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER UsbCoreDriver;
- //
- // Store a pointer to the USB core work queue.
- //
- PWORK_QUEUE UsbCoreWorkQueue = NULL;
- //
- // Store a pointer to the special USB paging transfer completion queue.
- //
- PUSB_TRANSFER_COMPLETION_QUEUE UsbCorePagingCompletionQueue = NULL;
- //
- // Store a list of all active host controllers and a lock that protects this
- // list.
- //
- LIST_ENTRY UsbHostControllerList;
- PQUEUED_LOCK UsbHostControllerListLock = NULL;
- //
- // Store a list of all active USB devices in the system.
- //
- LIST_ENTRY UsbDeviceList;
- PQUEUED_LOCK UsbDeviceListLock = NULL;
- //
- // Store a bitfield of enabled USB debug flags. See USB_DEBUG_* definitions.
- //
- ULONG UsbDebugFlags = 0x0;
- //
- // Set this to enable debugging only a single device address. If this is zero,
- // it's enabled on all addresses.
- //
- UCHAR UsbDebugDeviceAddress = 0x0;
- //
- // Store a pointer to the USB debugger handoff data.
- //
- PDEBUG_HANDOFF_DATA UsbDebugHandoffData = NULL;
- //
- // Define transfer direction and endpoint type strings.
- //
- PSTR UsbTransferDirectionStrings[UsbTransferDirectionCount] = {
- "INVALID",
- "from",
- "to",
- "from/to"
- };
- PSTR UsbTransferTypeStrings[UsbTransferTypeCount] = {
- "INVALID",
- "control",
- "interrupt",
- "bulk",
- "isochronous",
- };
- PSTR UsbErrorStrings[UsbErrorCount] = {
- "No error",
- "Not started",
- "Cancelled",
- "Allocated incorrectly",
- "Double submitted",
- "Incorrectly filled out",
- "Failed to submit",
- "Stalled",
- "Data buffer",
- "Babble",
- "Nak",
- "CrcOrTimeout",
- "Bitstuff",
- "Missed microframe",
- "Misaligned buffer",
- "Device not connected",
- "Short packet",
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- __USED
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine implements the initial entry point of the USB core library,
- called when the library is first loaded.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- Status code.
- --*/
- {
- ULONG PathIndex;
- KSTATUS Status;
- Status = STATUS_INSUFFICIENT_RESOURCES;
- UsbCoreDriver = Driver;
- //
- // Initialize USB structures.
- //
- INITIALIZE_LIST_HEAD(&UsbHostControllerList);
- INITIALIZE_LIST_HEAD(&UsbDeviceList);
- ASSERT((UsbHostControllerListLock == NULL) &&
- (UsbDeviceListLock == NULL) &&
- (UsbCorePagingCompletionQueue == NULL) &&
- (UsbCoreWorkQueue == NULL));
- UsbHostControllerListLock = KeCreateQueuedLock();
- if (UsbHostControllerListLock == NULL) {
- goto DriverEntryEnd;
- }
- UsbDeviceListLock = KeCreateQueuedLock();
- if (UsbDeviceListLock == NULL) {
- goto DriverEntryEnd;
- }
- UsbCoreWorkQueue = KeCreateWorkQueue(WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL,
- "UsbCoreWorker");
- if (UsbCoreWorkQueue== NULL) {
- goto DriverEntryEnd;
- }
- Status = KdGetDeviceInformation(&UsbDebugHandoffData);
- if ((!KSUCCESS(Status)) || (UsbDebugHandoffData == NULL) ||
- (UsbDebugHandoffData->PortType != DEBUG_PORT_TYPE_USB)) {
- UsbDebugHandoffData = NULL;
- }
- if ((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) {
- RtlDebugPrint("USB: Debug handoff data: 0x%x\n", UsbDebugHandoffData);
- if (UsbDebugHandoffData != NULL) {
- RtlDebugPrint("USB: Debug device %04X:%04X is at path ",
- UsbDebugHandoffData->U.Usb.VendorId,
- UsbDebugHandoffData->U.Usb.ProductId);
- for (PathIndex = 0;
- PathIndex < UsbDebugHandoffData->U.Usb.DevicePathSize;
- PathIndex += 1) {
- if (PathIndex != 0) {
- RtlDebugPrint(", ");
- }
- RtlDebugPrint(
- "%d",
- UsbDebugHandoffData->U.Usb.DevicePath[PathIndex]);
- }
- RtlDebugPrint("\n");
- }
- }
- Status = STATUS_SUCCESS;
- DriverEntryEnd:
- return Status;
- }
- USB_API
- HANDLE
- UsbDeviceOpen (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine attempts to open a USB device for I/O.
- Arguments:
- Device - Supplies a pointer to the device to open.
- Return Value:
- Returns a handle to the device upon success.
- INVALID_HANDLE if the device could not be opened.
- --*/
- {
- if (Device->Connected != FALSE) {
- UsbpDeviceAddReference(Device);
- return (HANDLE)Device;
- }
- return INVALID_HANDLE;
- }
- USB_API
- VOID
- UsbDeviceClose (
- HANDLE UsbDeviceHandle
- )
- /*++
- Routine Description:
- This routine closes an open USB handle.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- Return Value:
- None.
- --*/
- {
- PUSB_DEVICE Device;
- if (UsbDeviceHandle == INVALID_HANDLE) {
- return;
- }
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- UsbpDeviceReleaseReference(Device);
- return;
- }
- USB_API
- PUSB_TRANSFER
- UsbAllocateTransfer (
- HANDLE UsbDeviceHandle,
- UCHAR EndpointNumber,
- ULONG MaxTransferSize,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine allocates a new USB transfer structure. This routine must be
- used to allocate transfers.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- EndpointNumber - Supplies the endpoint number that the transfer will go to.
- MaxTransferSize - Supplies the maximum length, in bytes, of the transfer.
- Attempts to submit a transfer with lengths longer than this initialized
- length will fail. Longer transfer sizes do require more resources as
- they are split into subpackets, so try to be reasonable.
- Flags - Supplies a bitfield of flags regarding the transaction. See
- USB_TRANSFER_FLAG_* definitions.
- Return Value:
- Returns a pointer to the new USB transfer on success.
- NULL when there are insufficient resources to complete the request.
- --*/
- {
- PUSB_TRANSFER Transfer;
- Transfer = UsbpAllocateTransfer((PUSB_DEVICE)UsbDeviceHandle,
- EndpointNumber,
- MaxTransferSize,
- Flags);
- return Transfer;
- }
- USB_API
- VOID
- UsbDestroyTransfer (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine destroys an allocated transfer. This transfer must not be
- actively transferring.
- Arguments:
- Transfer - Supplies a pointer to the transfer to destroy.
- Return Value:
- None.
- --*/
- {
- UsbTransferReleaseReference(Transfer);
- return;
- }
- USB_API
- KSTATUS
- UsbSubmitTransfer (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine submits a USB transfer. The routine returns immediately,
- indicating only whether the transfer was submitted successfully. When the
- transfer actually completes, the callback routine will be called.
- Arguments:
- Transfer - Supplies a pointer to the transfer to submit.
- Return Value:
- STATUS_SUCCESS if the transfer was submitted to the USB host controller's
- queue.
- STATUS_INVALID_PARAMETER if one or more of the transfer fields is not
- properly filled out.
- Failing status codes if the request could not be submitted.
- --*/
- {
- return UsbpSubmitTransfer(Transfer, 0, FALSE);
- }
- USB_API
- KSTATUS
- UsbSubmitSynchronousTransfer (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine submits a USB transfer, and does not return until the transfer
- is completed successfully or with an error. This routine must be called at
- low level.
- Arguments:
- Transfer - Supplies a pointer to the transfer to submit.
- Return Value:
- STATUS_SUCCESS if the transfer was submitted to the USB host controller's
- queue.
- STATUS_INVALID_PARAMETER if one or more of the transfer fields is not
- properly filled out.
- Failing status codes if the request could not be submitted.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- KeSignalEvent(CompleteTransfer->Event, SignalOptionUnsignal);
- Status = UsbpSubmitTransfer(Transfer,
- USB_TRANSFER_PRIVATE_SYNCHRONOUS,
- FALSE);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Wait for the transfer to complete.
- //
- KeWaitForEvent(CompleteTransfer->Event, FALSE, WAIT_TIME_INDEFINITE);
- //
- // Assert that the transfer is now inactive. The caller should coordinate
- // not re-submitting this transfer before this call returns the status.
- //
- ASSERT(CompleteTransfer->State == TransferInactive);
- return Transfer->Status;
- }
- USB_API
- KSTATUS
- UsbSubmitPolledTransfer (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine submits a USB transfer, and does not return until the transfer
- is completed successfully or with an error. This routine is meant to be
- called in critical code paths at high level.
- Arguments:
- Transfer - Supplies a pointer to the transfer to submit.
- Return Value:
- Status code.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- ULONG OriginalState;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- ASSERT(Transfer->CallbackRoutine == NULL);
- Transfer->Flags |= USB_TRANSFER_FLAG_NO_INTERRUPT_ON_COMPLETION;
- Status = UsbpSubmitTransfer(Transfer,
- USB_TRANSFER_PRIVATE_SYNCHRONOUS,
- TRUE);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // If the transfer was successful, then it should be in the active state.
- // Flip it back to inactive.
- //
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- OriginalState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferInactive,
- TransferActive);
- ASSERT(OriginalState == TransferActive);
- return Status;
- }
- USB_API
- KSTATUS
- UsbCancelTransfer (
- PUSB_TRANSFER Transfer,
- BOOL Wait
- )
- /*++
- Routine Description:
- This routine cancels a USB transfer, waiting for the transfer to enter the
- inactive state before returning. Must be called at low level.
- Arguments:
- Transfer - Supplies a pointer to the transfer to cancel.
- Wait - Supplies a boolean indicating that the caller wants to wait for the
- transfer the reach the inactive state. Specify TRUE if unsure.
- Return Value:
- Returns STATUS_SUCCESS if the transfer was successfully cancelled.
- Returns STATUS_TOO_LATE if the transfer was not cancelled, but moved to the
- inactive state.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Attempt to cancel the transfer.
- //
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- Status = UsbpCancelTransfer(CompleteTransfer);
- //
- // If desired, wait until the transfer has entered the inactive state.
- //
- if (Wait != FALSE) {
- while (CompleteTransfer->State != TransferInactive) {
- KeYield();
- }
- //
- // If the transfer was successfully pulled off the hardware queue, then
- // it really shouldn't be active. If it was too late to cancel, then it
- // may be active again. Tough luck.
- //
- ASSERT(!KSUCCESS(Status) ||
- (CompleteTransfer->State == TransferInactive));
- }
- return Status;
- }
- USB_API
- KSTATUS
- UsbInitializePagingDeviceTransfers (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the USB core to handle special paging device
- transfers that are serviced on their own work queue.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue;
- PVOID OriginalQueue;
- KSTATUS Status;
- //
- // If the paging device transfer completion queue is already initialized,
- // then all is ready to go.
- //
- if (UsbCorePagingCompletionQueue != NULL) {
- return STATUS_SUCCESS;
- }
- //
- // Otherwise initialize a transfer completion queue.
- //
- AllocationSize = sizeof(USB_TRANSFER_COMPLETION_QUEUE);
- CompletionQueue = MmAllocateNonPagedPool(AllocationSize,
- USB_CORE_ALLOCATION_TAG);
- if (CompletionQueue == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializePagingDeviceTransfersEnd;
- }
- Status = UsbpInitializeTransferCompletionQueue(CompletionQueue, TRUE);
- if (!KSUCCESS(Status)) {
- goto InitializePagingDeviceTransfersEnd;
- }
- //
- // Now try make this new transfer completion queue the global queue.
- //
- OriginalQueue = (PVOID)RtlAtomicCompareExchange(
- (volatile UINTN *)&UsbCorePagingCompletionQueue,
- (UINTN)CompletionQueue,
- (UINTN)NULL);
- //
- // If the original queue value was still NULL, then this completion queue
- // won the race, do not destroy it below.
- //
- if (OriginalQueue == NULL) {
- CompletionQueue = NULL;
- }
- Status = STATUS_SUCCESS;
- InitializePagingDeviceTransfersEnd:
- if (CompletionQueue != NULL) {
- UsbpDestroyTransferCompletionQueue(CompletionQueue);
- MmFreeNonPagedPool(CompletionQueue);
- }
- return Status;
- }
- USB_API
- ULONG
- UsbTransferAddReference (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine adds a reference to a USB transfer.
- Arguments:
- Transfer - Supplies a pointer to the transfer that is to be referenced.
- Return Value:
- Returns the old reference count.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- ULONG OldReferenceCount;
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- OldReferenceCount = RtlAtomicAdd32(&(CompleteTransfer->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- return OldReferenceCount;
- }
- USB_API
- ULONG
- UsbTransferReleaseReference (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine releases a reference on a USB transfer.
- Arguments:
- Transfer - Supplies a pointer to the transfer that is to be reference.
- Return Value:
- Returns the old reference count.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- ULONG OldReferenceCount;
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- OldReferenceCount = RtlAtomicAdd32(&(CompleteTransfer->ReferenceCount),
- (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- UsbpDestroyTransfer(Transfer);
- }
- return OldReferenceCount;
- }
- USB_API
- KSTATUS
- UsbGetStatus (
- HANDLE UsbDeviceHandle,
- UCHAR RequestRecipient,
- USHORT Index,
- PUSHORT Data
- )
- /*++
- Routine Description:
- This routine gets the status from the given device, interface, or endpoint,
- as determined based on the request type and index. This routine must be
- called at low level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- RequestRecipient - Supplies the recipient of this get status request.
- Index - Supplies the index of this get status request. This can be
- zero for devices, an interface number, or an endpoint number.
- Data - Supplies a pointer that receives the status from the request.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- ULONG LengthTransferred;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Validate the arguments.
- //
- if ((UsbDeviceHandle == INVALID_HANDLE) ||
- ((RequestRecipient != USB_SETUP_REQUEST_DEVICE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_INTERFACE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_ENDPOINT_RECIPIENT))) {
- Status = STATUS_INVALID_PARAMETER;
- goto GetStatusEnd;
- }
- //
- // Initialize the setup packet to send the device.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = RequestRecipient | USB_SETUP_REQUEST_TO_HOST;
- SetupPacket.Request = USB_REQUEST_GET_STATUS;
- SetupPacket.Value = 0;
- SetupPacket.Index = Index;
- SetupPacket.Length = sizeof(USHORT);
- //
- // Send the transfer.
- //
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &SetupPacket,
- Data,
- sizeof(USHORT),
- &LengthTransferred);
- //
- // Return failure if the transfer succeeded, but not enough bytes were
- // returned.
- //
- if (KSUCCESS(Status) && (LengthTransferred < sizeof(USHORT))) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto GetStatusEnd;
- }
- GetStatusEnd:
- return Status;
- }
- USB_API
- KSTATUS
- UsbSetFeature (
- HANDLE UsbDeviceHandle,
- UCHAR RequestRecipient,
- USHORT Feature,
- USHORT Index
- )
- /*++
- Routine Description:
- This routine sets the given feature for a device, interface or endpoint,
- as specified by the request type and index. This routine must be called at
- low level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- RequestRecipient - Supplies the recipient of this clear feature request.
- Feature - Supplies the value of this clear feature request.
- Index - Supplies the index of this clear feature request. This can be
- zero for devices, an interface number, or an endpoint number.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Validate the arguments.
- //
- if ((UsbDeviceHandle == INVALID_HANDLE) ||
- ((RequestRecipient != USB_SETUP_REQUEST_DEVICE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_INTERFACE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_ENDPOINT_RECIPIENT)) ||
- ((RequestRecipient == USB_SETUP_REQUEST_ENDPOINT_RECIPIENT) &&
- (Feature != USB_FEATURE_ENDPOINT_HALT)) ||
- ((RequestRecipient == USB_SETUP_REQUEST_DEVICE_RECIPIENT) &&
- (Feature != USB_FEATURE_DEVICE_REMOTE_WAKEUP))) {
- Status = STATUS_INVALID_PARAMETER;
- goto SetFeatureEnd;
- }
- //
- // There are no interface features defined in the USB specification.
- //
- ASSERT(RequestRecipient != USB_SETUP_REQUEST_INTERFACE_RECIPIENT);
- //
- // The test mode feature is not allowed to be cleared.
- //
- ASSERT(Feature != USB_FEATURE_DEVICE_TEST_MODE);
- //
- // Initialize the setup packet to send the device.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = RequestRecipient | USB_SETUP_REQUEST_TO_DEVICE;
- SetupPacket.Request = USB_REQUEST_SET_FEATURE;
- SetupPacket.Value = Feature;
- SetupPacket.Index = Index;
- SetupPacket.Length = 0;
- //
- // Send the transfer.
- //
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket,
- NULL,
- 0,
- NULL);
- if (!KSUCCESS(Status)) {
- goto SetFeatureEnd;
- }
- SetFeatureEnd:
- return Status;
- }
- USB_API
- KSTATUS
- UsbClearFeature (
- HANDLE UsbDeviceHandle,
- UCHAR RequestRecipient,
- USHORT Feature,
- USHORT Index
- )
- /*++
- Routine Description:
- This routine clears the given feature from a device, interface or endpoint,
- as specified by the request type and index. This routine must be called at
- low level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- RequestRecipient - Supplies the recipient of this clear feature request.
- Feature - Supplies the value of this clear feature request.
- Index - Supplies the index of this clear feature request. This can be
- zero for devices, an interface number, or an endpoint number.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Validate the arguments.
- //
- if ((UsbDeviceHandle == INVALID_HANDLE) ||
- ((RequestRecipient != USB_SETUP_REQUEST_DEVICE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_INTERFACE_RECIPIENT) &&
- (RequestRecipient != USB_SETUP_REQUEST_ENDPOINT_RECIPIENT)) ||
- ((RequestRecipient == USB_SETUP_REQUEST_ENDPOINT_RECIPIENT) &&
- (Feature != USB_FEATURE_ENDPOINT_HALT)) ||
- ((RequestRecipient == USB_SETUP_REQUEST_DEVICE_RECIPIENT) &&
- (Feature != USB_FEATURE_DEVICE_REMOTE_WAKEUP))) {
- Status = STATUS_INVALID_PARAMETER;
- goto ClearFeatureEnd;
- }
- //
- // There are no interface features defined in the USB specification.
- //
- ASSERT(RequestRecipient != USB_SETUP_REQUEST_INTERFACE_RECIPIENT);
- //
- // The test mode feature is not allowed to be cleared.
- //
- ASSERT(Feature != USB_FEATURE_DEVICE_TEST_MODE);
- //
- // Initialize the setup packet to send the device.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = RequestRecipient | USB_SETUP_REQUEST_TO_DEVICE;
- SetupPacket.Request = USB_REQUEST_CLEAR_FEATURE;
- SetupPacket.Value = Feature;
- SetupPacket.Index = Index;
- SetupPacket.Length = 0;
- //
- // Send the transfer.
- //
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket,
- NULL,
- 0,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ClearFeatureEnd;
- }
- //
- // If this was a successful attempt to clear an endpoint's HALT feature,
- // then the endpoint's data toggle needs to be unset, ensuring that the
- // next transfer on the endpoint will use DATA0.
- //
- if ((RequestRecipient == USB_SETUP_REQUEST_ENDPOINT_RECIPIENT) &&
- (Feature == USB_FEATURE_ENDPOINT_HALT)) {
- Endpoint = UsbpGetDeviceEndpoint(Device, Index);
- if (Endpoint == NULL) {
- ASSERT(Endpoint != NULL);
- Status = STATUS_NOT_FOUND;
- goto ClearFeatureEnd;
- }
- UsbpResetEndpoint(Device, Endpoint);
- }
- ClearFeatureEnd:
- return Status;
- }
- USB_API
- ULONG
- UsbGetConfigurationCount (
- HANDLE UsbDeviceHandle
- )
- /*++
- Routine Description:
- This routine gets the number of possible configurations in a given device.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- Return Value:
- Returns the number of configurations in the device.
- --*/
- {
- PUSB_DEVICE Device;
- if (UsbDeviceHandle == INVALID_HANDLE) {
- return 0;
- }
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- return Device->ConfigurationCount;
- }
- USB_API
- KSTATUS
- UsbGetConfiguration (
- HANDLE UsbDeviceHandle,
- UCHAR ConfigurationNumber,
- BOOL NumberIsIndex,
- PUSB_CONFIGURATION_DESCRIPTION *Configuration
- )
- /*++
- Routine Description:
- This routine gets a configuration out of the given device. This routine will
- send a blocking request to the device. This routine must be called at low
- level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- ConfigurationNumber - Supplies the index or configuration value of the
- configuration to get.
- NumberIsIndex - Supplies a boolean indicating whether the configuration
- number is an index (TRUE) or a specific configuration value (FALSE).
- Configuration - Supplies a pointer where a pointer to the desired
- configuration will be returned.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- PUSB_CONFIGURATION InternalConfiguration;
- KSTATUS Status;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Status = UsbpGetConfiguration(Device,
- ConfigurationNumber,
- NumberIsIndex,
- &InternalConfiguration);
- *Configuration = &(InternalConfiguration->Description);
- return Status;
- }
- USB_API
- PUSB_CONFIGURATION_DESCRIPTION
- UsbGetActiveConfiguration (
- HANDLE UsbDeviceHandle
- )
- /*++
- Routine Description:
- This routine gets the currently active configuration set in the device.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- Return Value:
- Returns a pointer to the current configuration.
- NULL if the device is not currently configured.
- --*/
- {
- PUSB_DEVICE Device;
- if (UsbDeviceHandle == INVALID_HANDLE) {
- return NULL;
- }
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- if (Device->ActiveConfiguration == NULL) {
- return NULL;
- }
- return &(Device->ActiveConfiguration->Description);
- }
- USB_API
- KSTATUS
- UsbSetConfiguration (
- HANDLE UsbDeviceHandle,
- UCHAR ConfigurationNumber,
- BOOL NumberIsIndex
- )
- /*++
- Routine Description:
- This routine sets the configuration to the given configuration value. This
- routine must be called at low level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- ConfigurationNumber - Supplies the configuration index or value to set.
- NumberIsIndex - Supplies a boolean indicating whether the configuration
- number is an index (TRUE) or a specific configuration value (FALSE).
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- PLIST_ENTRY CurrentEndpointEntry;
- PLIST_ENTRY CurrentInterfaceEntry;
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- PUSB_INTERFACE Interface;
- PLIST_ENTRY InterfaceListHead;
- ULONG LengthTransferred;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // First, get the configuration being described.
- //
- Status = UsbpGetConfiguration(Device,
- ConfigurationNumber,
- NumberIsIndex,
- &Configuration);
- if (!KSUCCESS(Status)) {
- goto SetConfigurationEnd;
- }
- //
- // Initialize the setup packet to send the device.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_TO_DEVICE |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- SetupPacket.Request = USB_DEVICE_REQUEST_SET_CONFIGURATION;
- SetupPacket.Value =
- Configuration->Description.Descriptor.ConfigurationValue;
- SetupPacket.Index = 0;
- SetupPacket.Length = 0;
- //
- // Lock the device and send the set request. The device is locked to avoid
- // getting the active configuration variable out of sync with what the
- // device actually has set.
- //
- KeAcquireQueuedLock(Device->ConfigurationLock);
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket,
- NULL,
- 0,
- &LengthTransferred);
- if (KSUCCESS(Status)) {
- Device->ActiveConfiguration = Configuration;
- }
- KeReleaseQueuedLock(Device->ConfigurationLock);
- //
- // Setting the configuration resets the DATA toggle for every endpoint on
- // the device. See Section 9.1.1.5 of the USB 2.0 Specification.
- //
- if (KSUCCESS(Status)) {
- UsbpResetEndpoint(Device, Device->EndpointZero);
- InterfaceListHead = &(Configuration->Description.InterfaceListHead);
- CurrentInterfaceEntry = InterfaceListHead->Next;
- while (CurrentInterfaceEntry != InterfaceListHead) {
- Interface = LIST_VALUE(CurrentInterfaceEntry,
- USB_INTERFACE,
- Description.ListEntry);
- CurrentEndpointEntry = Interface->EndpointList.Next;
- CurrentInterfaceEntry = CurrentInterfaceEntry->Next;
- while (CurrentEndpointEntry != &(Interface->EndpointList)) {
- Endpoint = LIST_VALUE(CurrentEndpointEntry,
- USB_ENDPOINT,
- ListEntry);
- UsbpResetEndpoint(Device, Endpoint);
- CurrentEndpointEntry = CurrentEndpointEntry->Next;
- }
- }
- }
- SetConfigurationEnd:
- return Status;
- }
- USB_API
- KSTATUS
- UsbClaimInterface (
- HANDLE UsbDeviceHandle,
- UCHAR InterfaceNumber
- )
- /*++
- Routine Description:
- This routine claims an interface, preparing it for I/O use. An interface
- can be claimed more than once. This routine must be called at low level.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- InterfaceNumber - Supplies the number of the interface to claim.
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- PLIST_ENTRY CurrentEntry;
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- PUSB_INTERFACE Interface;
- KSTATUS Status;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Interface = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Lock the device.
- //
- KeAcquireQueuedLock(Device->ConfigurationLock);
- //
- // If no interface has been set on the device yet, then an interface
- // cannot be claimed.
- //
- Configuration = Device->ActiveConfiguration;
- if (Configuration == NULL) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ClaimInterfaceEnd;
- }
- //
- // Loop through looking for the requested interface.
- //
- CurrentEntry = Configuration->Description.InterfaceListHead.Next;
- while (CurrentEntry != &(Configuration->Description.InterfaceListHead)) {
- Interface = LIST_VALUE(CurrentEntry,
- USB_INTERFACE,
- Description.ListEntry);
- if (Interface->Description.Descriptor.InterfaceNumber ==
- InterfaceNumber) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &(Configuration->Description.InterfaceListHead)) {
- Status = STATUS_NOT_FOUND;
- goto ClaimInterfaceEnd;
- }
- //
- // If the interface isn't supposed to have any endpoints, then finish.
- //
- if (LIST_EMPTY(&(Interface->Description.EndpointListHead)) != FALSE) {
- Status = STATUS_SUCCESS;
- goto ClaimInterfaceEnd;
- }
- //
- // If there are no endpoints yet, they'll have to be created now.
- //
- if (LIST_EMPTY(&(Interface->EndpointList)) != FALSE) {
- Status = UsbpCreateEndpointsForInterface(Device, Interface);
- if (!KSUCCESS(Status)) {
- goto ClaimInterfaceEnd;
- }
- //
- // The endpoints are there, up the reference counts on them.
- //
- } else {
- CurrentEntry = Interface->EndpointList.Next;
- while (CurrentEntry != &(Interface->EndpointList)) {
- Endpoint = LIST_VALUE(CurrentEntry, USB_ENDPOINT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- UsbpEndpointAddReference(Endpoint);
- }
- }
- Status = STATUS_SUCCESS;
- ClaimInterfaceEnd:
- KeReleaseQueuedLock(Device->ConfigurationLock);
- return Status;
- }
- USB_API
- VOID
- UsbReleaseInterface (
- HANDLE UsbDeviceHandle,
- UCHAR InterfaceNumber
- )
- /*++
- Routine Description:
- This routine releases an interface that was previously claimed for I/O.
- After this call, the caller that had claimed the interface should not use
- it again without reclaiming it.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- InterfaceNumber - Supplies the number of the interface to release.
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- PLIST_ENTRY CurrentEntry;
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- PUSB_INTERFACE Interface;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Interface = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Lock the device.
- //
- KeAcquireQueuedLock(Device->ConfigurationLock);
- //
- // If no interface has been set on the device yet, then an interface
- // cannot be claimed.
- //
- Configuration = Device->ActiveConfiguration;
- if (Configuration == NULL) {
- goto ClaimInterfaceEnd;
- }
- //
- // Loop through looking for the requested interface.
- //
- CurrentEntry = Configuration->Description.InterfaceListHead.Next;
- while (CurrentEntry != &(Configuration->Description.InterfaceListHead)) {
- Interface = LIST_VALUE(CurrentEntry,
- USB_INTERFACE,
- Description.ListEntry);
- if (Interface->Description.Descriptor.InterfaceNumber ==
- InterfaceNumber) {
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry == &(Configuration->Description.InterfaceListHead)) {
- goto ClaimInterfaceEnd;
- }
- //
- // If the interface isn't supposed to have any endpoints, then finish.
- //
- if (LIST_EMPTY(&(Interface->Description.EndpointListHead)) != FALSE) {
- goto ClaimInterfaceEnd;
- }
- //
- // Decrement the reference count on each endpoint. It's important to move
- // to the next list entry before releasing the reference, as doing so may
- // cause the endpoint to get unlinked and released.
- //
- CurrentEntry = Interface->EndpointList.Next;
- while (CurrentEntry != &(Interface->EndpointList)) {
- Endpoint = LIST_VALUE(CurrentEntry, USB_ENDPOINT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- UsbpEndpointReleaseReference(Device, Endpoint);
- }
- ClaimInterfaceEnd:
- KeReleaseQueuedLock(Device->ConfigurationLock);
- return;
- }
- USB_API
- KSTATUS
- UsbSendControlTransfer (
- HANDLE UsbDeviceHandle,
- USB_TRANSFER_DIRECTION TransferDirection,
- PUSB_SETUP_PACKET SetupPacket,
- PVOID Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred
- )
- /*++
- Routine Description:
- This routine sends a syncrhonous control transfer to or from the given USB
- device.
- Arguments:
- UsbDeviceHandle - Supplies a pointer to the device to talk to.
- TransferDirection - Supplies whether or not the transfer is to the device
- or to the host.
- SetupPacket - Supplies a pointer to the setup packet.
- Buffer - Supplies a pointer to the buffer to be sent or received. This does
- not include the setup packet, this is the optional data portion only.
- BufferLength - Supplies the length of the buffer, not including the setup
- packet.
- LengthTransferred - Supplies a pointer where the number of bytes that were
- actually transfered (not including the setup packet) will be returned.
- Return Value:
- Status code.
- --*/
- {
- UINTN AllocationSize;
- UINTN BufferAlignment;
- PUSB_DEVICE Device;
- PIO_BUFFER IoBuffer;
- ULONG IoBufferFlags;
- KSTATUS Status;
- PUSB_TRANSFER Transfer;
- PVOID TransferBuffer;
- ULONG TransferLength;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Transfer = NULL;
- if (LengthTransferred != NULL) {
- *LengthTransferred = 0;
- }
- ASSERT(TransferDirection != UsbTransferDirectionInvalid);
- //
- // Create the I/O buffer that will be used for the transfer.
- //
- TransferLength = BufferLength + sizeof(USB_SETUP_PACKET);
- BufferAlignment = MmGetIoBufferAlignment();
- AllocationSize = ALIGN_RANGE_UP(TransferLength, BufferAlignment);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- IoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- BufferAlignment,
- AllocationSize,
- IoBufferFlags);
- if (IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SendControlTransferEnd;
- }
- ASSERT(IoBuffer->FragmentCount == 1);
- TransferBuffer = IoBuffer->Fragment[0].VirtualAddress;
- RtlCopyMemory(TransferBuffer, SetupPacket, sizeof(USB_SETUP_PACKET));
- if ((TransferDirection == UsbTransferDirectionOut) &&
- (BufferLength != 0)) {
- RtlCopyMemory(TransferBuffer + sizeof(USB_SETUP_PACKET),
- Buffer,
- BufferLength);
- }
- //
- // Create a USB transfer.
- //
- Transfer = UsbpAllocateTransfer(Device, 0, AllocationSize, 0);
- if (Transfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SendControlTransferEnd;
- }
- Transfer->Direction = TransferDirection;
- Transfer->Length = TransferLength;
- Transfer->Buffer = IoBuffer->Fragment[0].VirtualAddress;
- Transfer->BufferPhysicalAddress = IoBuffer->Fragment[0].PhysicalAddress;
- Transfer->BufferActualLength = IoBuffer->Fragment[0].Size;
- //
- // Submit the transfer and wait for it to complete.
- //
- Status = UsbSubmitSynchronousTransfer(Transfer);
- if (!KSUCCESS(Status)) {
- goto SendControlTransferEnd;
- }
- ASSERT(KSUCCESS(Transfer->Status));
- //
- // Copy the results into the caller's buffer.
- //
- ASSERT(Transfer->LengthTransferred >= sizeof(USB_SETUP_PACKET));
- ASSERT(Transfer->LengthTransferred - sizeof(USB_SETUP_PACKET) <=
- BufferLength);
- if ((TransferDirection == UsbTransferDirectionIn) &&
- (Transfer->LengthTransferred > sizeof(USB_SETUP_PACKET))) {
- if (LengthTransferred != NULL) {
- *LengthTransferred = Transfer->LengthTransferred -
- sizeof(USB_SETUP_PACKET);
- }
- RtlCopyMemory(Buffer,
- Transfer->Buffer + sizeof(USB_SETUP_PACKET),
- Transfer->LengthTransferred - sizeof(USB_SETUP_PACKET));
- }
- Status = STATUS_SUCCESS;
- SendControlTransferEnd:
- if (Transfer != NULL) {
- UsbDestroyTransfer(Transfer);
- }
- if (IoBuffer != NULL) {
- MmFreeIoBuffer(IoBuffer);
- }
- return Status;
- }
- PUSB_TRANSFER
- UsbpAllocateTransfer (
- PUSB_DEVICE Device,
- UCHAR EndpointNumber,
- ULONG MaxTransferSize,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine allocates a new USB transfer structure. This routine must be
- used to allocate transfers.
- Arguments:
- Device - Supplies a pointer to the device the transfer will eventually be
- submitted to. This must not be changed by the caller in the transfer
- structure once set.
- EndpointNumber - Supplies the endpoint number that the transfer will go to.
- MaxTransferSize - Supplies the maximum length, in bytes, of the transfer.
- Attempts to submit a transfer with lengths longer than this initialized
- length will fail. Longer transfer sizes do require more resources as
- they are split into subpackets, so try to be reasonable.
- Flags - Supplies a bitfield of flags regarding the transaction. See
- USB_TRANSFER_FLAG_* definitions.
- Return Value:
- Returns a pointer to the new USB transfer on success.
- NULL when there are insufficient resources to complete the request.
- --*/
- {
- ULONG AllocationSize;
- PUSB_HOST_CREATE_TRANSFER CreateTransfer;
- PUSB_HOST_DESTROY_TRANSFER DestroyTransfer;
- PUSB_ENDPOINT Endpoint;
- PVOID HostControllerContext;
- BOOL ReleaseLock;
- KSTATUS Status;
- PUSB_TRANSFER_PRIVATE Transfer;
- BOOL TransferCreated;
- CreateTransfer = Device->Controller->Device.CreateTransfer;
- DestroyTransfer = Device->Controller->Device.DestroyTransfer;
- Endpoint = NULL;
- HostControllerContext = Device->Controller->Device.HostControllerContext;
- ReleaseLock = FALSE;
- Transfer = NULL;
- TransferCreated = FALSE;
- //
- // Add a reference to the device to account for the transfer. This is to
- // potentially allow a driver to roll through the removal IRP destroying
- // everything except for some pending transfer which depends on the USB
- // core. The USB core device will get cleaned up when said transfer get
- // destroyed, releasing this reference.
- //
- UsbpDeviceAddReference(Device);
- //
- // Find the endpoint associated with this transfer.
- //
- Endpoint = UsbpGetDeviceEndpoint(Device, EndpointNumber);
- if (Endpoint == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- goto AllocateTransferEnd;
- }
- //
- // Allocate the transfer.
- //
- AllocationSize = sizeof(USB_TRANSFER_PRIVATE);
- Transfer = MmAllocateNonPagedPool(AllocationSize, USB_CORE_ALLOCATION_TAG);
- if (Transfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AllocateTransferEnd;
- }
- RtlZeroMemory(Transfer, AllocationSize);
- Transfer->Magic = USB_TRANSFER_INTERNAL_MAGIC;
- Transfer->ReferenceCount = 1;
- Transfer->Device = Device;
- Transfer->Protected.DeviceAddress = Device->BusAddress;
- Transfer->Protected.EndpointNumber = EndpointNumber;
- Transfer->Protected.Type = Endpoint->Type;
- Transfer->MaxTransferSize = MaxTransferSize;
- Transfer->Endpoint = Endpoint;
- Transfer->Protected.Public.Flags = Flags;
- Transfer->Event = KeCreateEvent(NULL);
- if (Transfer->Event == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AllocateTransferEnd;
- }
- ASSERT(Transfer->State == TransferInvalid);
- ASSERT(Transfer->CompletionListEntry.Next == NULL);
- //
- // Don't let a new transfer be created for a disconnected device.
- //
- KeAcquireQueuedLock(Device->Lock);
- ReleaseLock = TRUE;
- if (Device->Connected == FALSE) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto AllocateTransferEnd;
- }
- //
- // Call into the host controller to allocate any of its needed structures.
- //
- Status = CreateTransfer(HostControllerContext,
- Endpoint->HostControllerContext,
- MaxTransferSize,
- Flags,
- &(Transfer->HostControllerContext));
- if (!KSUCCESS(Status)) {
- goto AllocateTransferEnd;
- }
- //
- // Now that the transfer is successfully created, mark it as inactive and
- // add it to the USB device's list of transfers.
- //
- Transfer->State = TransferInactive;
- INSERT_BEFORE(&(Transfer->DeviceListEntry), &(Device->TransferList));
- KeReleaseQueuedLock(Device->Lock);
- ReleaseLock = FALSE;
- TransferCreated = TRUE;
- Status = STATUS_SUCCESS;
- AllocateTransferEnd:
- if (!KSUCCESS(Status)) {
- if (Transfer != NULL) {
- if (TransferCreated != FALSE) {
- DestroyTransfer(HostControllerContext,
- Endpoint->HostControllerContext,
- Transfer->HostControllerContext);
- }
- if (Transfer->Event != NULL) {
- KeDestroyEvent(Transfer->Event);
- }
- MmFreeNonPagedPool(Transfer);
- Transfer = NULL;
- }
- if (ReleaseLock != FALSE) {
- KeReleaseQueuedLock(Device->Lock);
- }
- UsbpDeviceReleaseReference(Device);
- }
- return (PUSB_TRANSFER)Transfer;
- }
- VOID
- UsbpCancelAllTransfers (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine cancels all transfers for the given USB core device. The
- device must be disconnected before calling into this routine.
- Arguments:
- Device - Supplies the core handle to the device whose transfers are
- to be cancelled.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PUSB_TRANSFER_PRIVATE Transfer;
- ASSERT(Device != NULL);
- ASSERT(Device->Connected == FALSE);
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Loop through the transfers and add a reference to each. This way the
- // device lock does not need to be held while going through the cancel
- // process, potentially impeding a transfer's ability to fail resubmission.
- //
- KeAcquireQueuedLock(Device->Lock);
- CurrentEntry = Device->TransferList.Next;
- while (CurrentEntry != &(Device->TransferList)) {
- Transfer = (PUSB_TRANSFER_PRIVATE)LIST_VALUE(CurrentEntry,
- USB_TRANSFER_PRIVATE,
- DeviceListEntry);
- UsbTransferAddReference((PUSB_TRANSFER)Transfer);
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Release the lock. It is safe to proceed outside the lock because a
- // reference has been added to each transfer to prevent deletion and
- // because the device has been disconnected, preventing insertion.
- //
- KeReleaseQueuedLock(Device->Lock);
- //
- // Loop through the transfers again and cancel them all.
- //
- CurrentEntry = Device->TransferList.Next;
- while (CurrentEntry != &(Device->TransferList)) {
- Transfer = (PUSB_TRANSFER_PRIVATE)LIST_VALUE(CurrentEntry,
- USB_TRANSFER_PRIVATE,
- DeviceListEntry);
- UsbpCancelTransfer(Transfer);
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Now wait on all transfers to enter the inactive state.
- //
- CurrentEntry = Device->TransferList.Next;
- while (CurrentEntry != &(Device->TransferList)) {
- Transfer = (PUSB_TRANSFER_PRIVATE)LIST_VALUE(CurrentEntry,
- USB_TRANSFER_PRIVATE,
- DeviceListEntry);
- while (Transfer->State != TransferInactive) {
- KeYield();
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Loop one last time, releasing the references. Be aware that this could
- // be the last reference on some transfers, meaning the lock cannot be
- // held because the release could trigger deletion.
- //
- CurrentEntry = Device->TransferList.Next;
- while (CurrentEntry != &(Device->TransferList)) {
- Transfer = (PUSB_TRANSFER_PRIVATE)LIST_VALUE(CurrentEntry,
- USB_TRANSFER_PRIVATE,
- DeviceListEntry);
- CurrentEntry = CurrentEntry->Next;
- UsbTransferReleaseReference((PUSB_TRANSFER)Transfer);
- }
- return;
- }
- KSTATUS
- UsbpReadConfigurationDescriptors (
- PUSB_DEVICE Device,
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
- )
- /*++
- Routine Description:
- This routine attempts to read all configuration descriptors from the device.
- Arguments:
- Device - Supplies a pointer to the device to query.
- DeviceDescriptor - Supplies a pointer to the device descriptor.
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- UCHAR ConfigurationCount;
- UCHAR ConfigurationIndex;
- KSTATUS OverallStatus;
- KSTATUS Status;
- OverallStatus = STATUS_SUCCESS;
- ConfigurationCount = DeviceDescriptor->ConfigurationCount;
- for (ConfigurationIndex = 0;
- ConfigurationIndex < ConfigurationCount;
- ConfigurationIndex += 1) {
- Status = UsbpGetConfiguration(Device,
- ConfigurationIndex,
- TRUE,
- &Configuration);
- if (!KSUCCESS(Status)) {
- OverallStatus = Status;
- }
- }
- return OverallStatus;
- }
- USB_API
- PVOID
- UsbGetDeviceToken (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine returns the system device token associated with the given USB
- device.
- Arguments:
- Device - Supplies a pointer to a USB device.
- Return Value:
- Returns a system device token.
- --*/
- {
- return Device->Device;
- }
- KSTATUS
- UsbpInitializeTransferCompletionQueue (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue,
- BOOL PrivateWorkQueue
- )
- /*++
- Routine Description:
- This routine initializes the given transfer completion queue.
- Arguments:
- CompletionQueue - Supplies a pointer to a USB transfer completion queue
- that is to be initialized.
- PrivateWorkQueue - Supplies a boolean indicating whether or not the
- completion queue requires a private work queue for queuing its work
- item.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- ULONG WorkQueueFlags;
- RtlZeroMemory(CompletionQueue, sizeof(USB_TRANSFER_COMPLETION_QUEUE));
- INITIALIZE_LIST_HEAD(&(CompletionQueue->CompletedTransfersList));
- KeInitializeSpinLock(&(CompletionQueue->CompletedTransfersListLock));
- if (PrivateWorkQueue != FALSE) {
- WorkQueueFlags = WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL;
- CompletionQueue->WorkQueue = KeCreateWorkQueue(WorkQueueFlags,
- "UsbCorePrivateWorker");
- if (CompletionQueue->WorkQueue == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeTransferCompletionQueueEnd;
- }
- } else {
- CompletionQueue->WorkQueue = UsbCoreWorkQueue;
- }
- ASSERT(CompletionQueue->WorkQueue != NULL);
- CompletionQueue->WorkItem = KeCreateWorkItem(CompletionQueue->WorkQueue,
- WorkPriorityNormal,
- UsbpCompletedTransferWorker,
- CompletionQueue,
- USB_CORE_ALLOCATION_TAG);
- if (CompletionQueue->WorkItem == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeTransferCompletionQueueEnd;
- }
- Status = STATUS_SUCCESS;
- InitializeTransferCompletionQueueEnd:
- if (!KSUCCESS(Status)) {
- UsbpDestroyTransferCompletionQueue(CompletionQueue);
- }
- return Status;
- }
- VOID
- UsbpDestroyTransferCompletionQueue (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue
- )
- /*++
- Routine Description:
- This routine destroys the given transfer completion queue. It does not
- release the completion queue's memory.
- Arguments:
- CompletionQueue - Supplies a pointer to a USB transfer completion queue
- that is to be destroyed.
- Return Value:
- Status code.
- --*/
- {
- if (CompletionQueue->WorkItem != NULL) {
- KeDestroyWorkItem(CompletionQueue->WorkItem);
- }
- if ((CompletionQueue->WorkQueue != NULL) &&
- (CompletionQueue->WorkQueue != UsbCoreWorkQueue)) {
- KeDestroyWorkQueue(CompletionQueue->WorkQueue);
- }
- return;
- }
- VOID
- UsbpProcessCompletedTransfer (
- PUSB_TRANSFER_INTERNAL Transfer
- )
- /*++
- Routine Description:
- This routine processes the completed transfer. It will either signal
- synchronous transfers or queue asynchronous transfers on the correct
- transfer completion queue so that its callback routine can be completed at
- low level. This routine is called at dispatch.
- Arguments:
- Transfer - Supplies a pointer to a completed transfer.
- Return Value:
- None.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue;
- PUSB_HOST_CONTROLLER Controller;
- ULONG FlushAlignment;
- ULONG FlushLength;
- RUNLEVEL OldRunLevel;
- USB_TRANSFER_STATE OldState;
- ULONG PrivateFlags;
- BOOL QueueWorkItem;
- KSTATUS Status;
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- ASSERT(KeGetRunLevel() == RunLevelDispatch);
- ASSERT(CompleteTransfer->CompletionListEntry.Next == NULL);
- //
- // For any transfer that read data (i.e. all but the out transfers),
- // invalidate the data cache again so that the consumer reads the correct
- // data.
- //
- if (Transfer->Public.Direction != UsbTransferDirectionOut) {
- ASSERT((Transfer->Public.Direction == UsbTransferDirectionIn) ||
- (Transfer->Public.Direction == UsbTransferBidirectional));
- FlushAlignment = MmGetIoBufferAlignment();
- ASSERT(POWER_OF_2(FlushAlignment) != FALSE);
- FlushLength = ALIGN_RANGE_UP(Transfer->Public.LengthTransferred,
- FlushAlignment);
- MmFlushBufferForDataIn(Transfer->Public.Buffer, FlushLength);
- }
- //
- // For synchronous transfers, fire the event.
- //
- PrivateFlags = CompleteTransfer->PrivateFlags;
- if ((PrivateFlags & USB_TRANSFER_PRIVATE_SYNCHRONOUS) != 0) {
- //
- // Mark that the transfer is no longer in flight.
- //
- OldState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferInactive,
- TransferActive);
- ASSERT(OldState == TransferActive);
- KeSignalEvent(CompleteTransfer->Event, SignalOptionSignalAll);
- //
- // USB core is done with this transfer, so release the reference taken
- // on submit.
- //
- UsbTransferReleaseReference((PUSB_TRANSFER)Transfer);
- //
- // Queue all non-synchronous transfers to handle the callback at low-level.
- //
- } else {
- //
- // If this is a paging device transfer, then use the paging device
- // completion queue.
- //
- if ((Transfer->Public.Flags & USB_TRANSFER_FLAG_PAGING_DEVICE) != 0) {
- ASSERT(UsbCorePagingCompletionQueue != NULL);
- CompletionQueue = UsbCorePagingCompletionQueue;
- //
- // Otherwise use the controller's completion queue.
- //
- } else {
- Controller = CompleteTransfer->Device->Controller;
- CompletionQueue = &(Controller->TransferCompletionQueue);
- }
- //
- // Add the transfer to the completion list and potentially queue the
- // work item to empty the list.
- //
- OldRunLevel = UsbpAcquireCompletedTransfersLock(CompletionQueue);
- //
- // If the list is currently empty, then the work item needs to be
- // queued to process this new insertion.
- //
- if (LIST_EMPTY(&(CompletionQueue->CompletedTransfersList)) != FALSE) {
- QueueWorkItem = TRUE;
- //
- // If it is not empty, then the work item is already queued and the
- // insertion below will be picked up.
- //
- } else {
- QueueWorkItem = FALSE;
- }
- INSERT_BEFORE(&(CompleteTransfer->CompletionListEntry),
- &(CompletionQueue->CompletedTransfersList));
- if (QueueWorkItem != FALSE) {
- Status = KeQueueWorkItem(CompletionQueue->WorkItem);
- ASSERT(KSUCCESS(Status));
- }
- UsbpReleaseCompletedTransfersLock(CompletionQueue, OldRunLevel);
- }
- return;
- }
- USB_API
- BOOL
- UsbIsPolledIoSupported (
- HANDLE UsbDeviceHandle
- )
- /*++
- Routine Description:
- This routine returns a boolean indicating whether or not the given USB
- device's controller supports polled I/O mode. Polled I/O should only be
- used in dire circumstances. That is, during system failure when a crash
- dump file needs to be written over USB Mass Storage at high run level with
- interrupts disabled.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- Return Value:
- Returns a boolean indicating if polled I/O is supported (TRUE) or not
- (FALSE).
- --*/
- {
- PUSB_DEVICE Device;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- if (Device->Controller->Device.SubmitPolledTransfer != NULL) {
- return TRUE;
- }
- return FALSE;
- }
- USB_API
- KSTATUS
- UsbResetEndpoint (
- HANDLE UsbDeviceHandle,
- UCHAR EndpointNumber
- )
- /*++
- Routine Description:
- This routine resets the given endpoint for the given USB device. This
- includes resetting the data toggle to DATA 0.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- EndpointNumber - Supplies the number of the endpoint to be reset.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- KSTATUS Status;
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Endpoint = UsbpGetDeviceEndpoint(Device, EndpointNumber);
- if (Endpoint == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- goto ResetEndpointEnd;
- }
- UsbpResetEndpoint(Device, Endpoint);
- Status = STATUS_SUCCESS;
- ResetEndpointEnd:
- return Status;
- }
- USB_API
- KSTATUS
- UsbFlushEndpoint (
- HANDLE UsbDeviceHandle,
- UCHAR EndpointNumber,
- PULONG TransferCount
- )
- /*++
- Routine Description:
- This routine flushes the given endpoint for the given USB device. This
- includes busily waiting for all active transfers to complete. This is only
- meant to be used at high run level when preparing to write a crash dump
- file using USB Mass Storage.
- Arguments:
- UsbDeviceHandle - Supplies the handle returned when the device was opened.
- EndpointNumber - Supplies the number of the endpoint to be reset.
- TransferCount - Supplies a pointer that receives the total number of
- transfers that were flushed.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Device = (PUSB_DEVICE)UsbDeviceHandle;
- Endpoint = UsbpGetDeviceEndpoint(Device, EndpointNumber);
- if (Endpoint == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- goto FlushEndpointEnd;
- }
- Status = UsbpFlushEndpoint(Device, Endpoint, TransferCount);
- if (!KSUCCESS(Status)) {
- goto FlushEndpointEnd;
- }
- FlushEndpointEnd:
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- UsbpCancelTransfer (
- PUSB_TRANSFER_PRIVATE Transfer
- )
- /*++
- Routine Description:
- This routine cancels a USB transfer.
- Arguments:
- Transfer - Supplies a pointer to the transfer to cancel.
- Return Value:
- Status code.
- --*/
- {
- PUSB_HOST_CANCEL_TRANSFER CancelTransfer;
- PUSB_HOST_CONTROLLER Controller;
- PUSB_ENDPOINT Endpoint;
- KSTATUS Status;
- Endpoint = Transfer->Endpoint;
- Controller = Transfer->Device->Controller;
- CancelTransfer = Controller->Device.CancelTransfer;
- //
- // Try to cancel the transfer. This only makes an attempt at cancelling
- // the transfer and does not guarantee success or that the transfer is
- // out of USB core's domain. The caller needs to handle the various failure
- // cases. If the transfer is currently inactive, just return that the
- // cancel is too early.
- //
- if (Transfer->State == TransferInactive) {
- Status = STATUS_TOO_EARLY;
- } else {
- Status = CancelTransfer(Controller->Device.HostControllerContext,
- Endpoint->HostControllerContext,
- (PUSB_TRANSFER_INTERNAL)Transfer,
- Transfer->HostControllerContext);
- if (!KSUCCESS(Status)) {
- ASSERT(Status == STATUS_TOO_LATE);
- }
- }
- return Status;
- }
- VOID
- UsbpDestroyTransfer (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine destroys an allocated transfer. This transfer must not be
- actively transferring.
- Arguments:
- Transfer - Supplies a pointer to the transfer to destroy.
- Return Value:
- None.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- PUSB_HOST_DESTROY_TRANSFER DestroyTransfer;
- PUSB_HOST_CONTROLLER HostController;
- PVOID HostControllerContext;
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- ASSERT(CompleteTransfer->CompletionListEntry.Next == NULL);
- ASSERT(CompleteTransfer->Magic == USB_TRANSFER_INTERNAL_MAGIC);
- ASSERT(CompleteTransfer->State == TransferInactive);
- //
- // Remove the transfer from its USB device's list of transfers.
- //
- KeAcquireQueuedLock(CompleteTransfer->Device->Lock);
- LIST_REMOVE(&(CompleteTransfer->DeviceListEntry));
- KeReleaseQueuedLock(CompleteTransfer->Device->Lock);
- //
- // Call the host controller to destroy the transfer.
- //
- HostController = CompleteTransfer->Device->Controller;
- DestroyTransfer = HostController->Device.DestroyTransfer;
- HostControllerContext = HostController->Device.HostControllerContext;
- DestroyTransfer(HostControllerContext,
- CompleteTransfer->Endpoint->HostControllerContext,
- CompleteTransfer->HostControllerContext);
- KeDestroyEvent(CompleteTransfer->Event);
- //
- // Releae the reference the transfer took on the device.
- //
- UsbpDeviceReleaseReference(CompleteTransfer->Device);
- //
- // Destroy the transfer itself.
- //
- MmFreeNonPagedPool(CompleteTransfer);
- return;
- }
- KSTATUS
- UsbpGetConfiguration (
- PUSB_DEVICE Device,
- UCHAR ConfigurationNumber,
- BOOL NumberIsIndex,
- PUSB_CONFIGURATION *Configuration
- )
- /*++
- Routine Description:
- This routine gets a configuration out of the given device. This routine
- will send a blocking request to the device. This routine must be called at
- low level.
- Arguments:
- Device - Supplies a pointer to the device.
- ConfigurationNumber - Supplies the index or configuration value of the
- configuration to get.
- NumberIsIndex - Supplies a boolean indicating whether the configuration
- number is an index (TRUE) or a specific configuration value (FALSE).
- Configuration - Supplies a pointer where a pointer to the created
- configuration will be returned.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- PUCHAR BufferPointer;
- PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
- UCHAR ConfigurationValue;
- PUSB_CONFIGURATION CurrentConfiguration;
- PLIST_ENTRY CurrentEntry;
- PUSB_INTERFACE CurrentInterface;
- PUSB_CONFIGURATION_DESCRIPTION Description;
- UCHAR DescriptorLength;
- UCHAR DescriptorType;
- PUSB_ENDPOINT_DESCRIPTION Endpoint;
- ULONG EndpointCount;
- ULONG InterfaceCount;
- ULONG Length;
- ULONG LengthTransferred;
- PUCHAR NewBufferPointer;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- USHORT TotalLength;
- PUSB_UNKNOWN_DESCRIPTION Unknown;
- ULONG UnknownCount;
- ULONG UnknownSize;
- *Configuration = NULL;
- ConfigurationDescriptor = NULL;
- CurrentConfiguration = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- KeAcquireQueuedLock(Device->ConfigurationLock);
- //
- // First look to see if the configuration already exists.
- //
- CurrentEntry = Device->ConfigurationList.Next;
- while (CurrentEntry != &(Device->ConfigurationList)) {
- CurrentConfiguration = LIST_VALUE(CurrentEntry,
- USB_CONFIGURATION,
- ListEntry);
- //
- // Match on either the index or the value.
- //
- Description = &(CurrentConfiguration->Description);
- if (NumberIsIndex != FALSE) {
- if (ConfigurationNumber == Description->Index) {
- break;
- }
- } else {
- ConfigurationValue = Description->Descriptor.ConfigurationValue;
- if (ConfigurationNumber == ConfigurationValue) {
- break;
- }
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if (CurrentEntry != &(Device->ConfigurationList)) {
- Status = STATUS_SUCCESS;
- goto GetConfigurationEnd;
- }
- CurrentConfiguration = NULL;
- //
- // The USB spec does not support requesting descriptors by value, so this
- // had better be a "by-index" request.
- //
- ASSERT(NumberIsIndex != FALSE);
- //
- // Allocate space for the entire descriptor, which includes all of the
- // interface and endpoint descriptors (hopefully).
- //
- ConfigurationDescriptor = MmAllocatePagedPool(
- USB_INITIAL_CONFIGURATION_LENGTH,
- USB_CORE_ALLOCATION_TAG);
- if (ConfigurationDescriptor == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetConfigurationEnd;
- }
- //
- // Read in the configuration descriptor.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- SetupPacket.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
- SetupPacket.Value = (UsbDescriptorTypeConfiguration << 8) |
- ConfigurationNumber;
- SetupPacket.Index = 0;
- SetupPacket.Length = USB_INITIAL_CONFIGURATION_LENGTH;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &SetupPacket,
- ConfigurationDescriptor,
- USB_INITIAL_CONFIGURATION_LENGTH,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- goto GetConfigurationEnd;
- }
- if (LengthTransferred < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- //
- // If the buffer was too small, allocate a bigger one and read it in again.
- //
- TotalLength = ConfigurationDescriptor->TotalLength;
- if (TotalLength > USB_INITIAL_CONFIGURATION_LENGTH) {
- MmFreePagedPool(ConfigurationDescriptor);
- ConfigurationDescriptor = MmAllocatePagedPool(TotalLength,
- USB_CORE_ALLOCATION_TAG);
- if (ConfigurationDescriptor == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetConfigurationEnd;
- }
- SetupPacket.Length = TotalLength;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &SetupPacket,
- ConfigurationDescriptor,
- TotalLength,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- goto GetConfigurationEnd;
- }
- if (LengthTransferred != TotalLength) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- }
- //
- // Count the number of interfaces and endpoints to determine the allocation
- // size for the description.
- //
- InterfaceCount = 0;
- EndpointCount = 0;
- UnknownCount = 0;
- UnknownSize = 0;
- Length = ConfigurationDescriptor->Length;
- BufferPointer = (PUCHAR)ConfigurationDescriptor +
- ConfigurationDescriptor->Length;
- while (Length + 1 < LengthTransferred) {
- //
- // Get this descriptor and count it.
- //
- DescriptorLength = *BufferPointer;
- DescriptorType = *(BufferPointer + 1);
- if (DescriptorType == UsbDescriptorTypeInterface) {
- InterfaceCount += 1;
- } else if (DescriptorType == UsbDescriptorTypeEndpoint) {
- EndpointCount += 1;
- } else {
- UnknownCount += 1;
- UnknownSize += DescriptorLength + sizeof(ULONGLONG) - 1;
- }
- //
- // Move on to the next descriptor.
- //
- BufferPointer += DescriptorLength;
- Length += DescriptorLength;
- }
- //
- // Now allocate space for the configuration description.
- //
- AllocationSize = sizeof(USB_CONFIGURATION) +
- (InterfaceCount * sizeof(USB_INTERFACE)) +
- (EndpointCount * sizeof(USB_ENDPOINT_DESCRIPTION)) +
- (UnknownCount * sizeof(USB_UNKNOWN_DESCRIPTION)) +
- UnknownSize;
- CurrentConfiguration = MmAllocatePagedPool(AllocationSize,
- USB_CORE_ALLOCATION_TAG);
- if (CurrentConfiguration == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetConfigurationEnd;
- }
- RtlZeroMemory(CurrentConfiguration, AllocationSize);
- CurrentConfiguration->Description.Index = ConfigurationNumber;
- RtlCopyMemory(&(CurrentConfiguration->Description.Descriptor),
- ConfigurationDescriptor,
- sizeof(USB_CONFIGURATION_DESCRIPTOR));
- INITIALIZE_LIST_HEAD(
- &(CurrentConfiguration->Description.InterfaceListHead));
- //
- // Go through the descriptor again and create analogous structures for them.
- //
- CurrentInterface = NULL;
- Length = ConfigurationDescriptor->Length;
- BufferPointer = (PUCHAR)ConfigurationDescriptor +
- ConfigurationDescriptor->Length;
- NewBufferPointer = (PUCHAR)(CurrentConfiguration + 1);
- while (Length + 1 < LengthTransferred) {
- //
- // Get this descriptor and create the analogous structure.
- //
- DescriptorLength = *BufferPointer;
- DescriptorType = *(BufferPointer + 1);
- if (Length + DescriptorLength > LengthTransferred) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- if (DescriptorType == UsbDescriptorTypeInterface) {
- CurrentInterface = (PUSB_INTERFACE)NewBufferPointer;
- if (DescriptorLength < sizeof(USB_INTERFACE_DESCRIPTOR)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- RtlCopyMemory(&(CurrentInterface->Description.Descriptor),
- BufferPointer,
- sizeof(USB_INTERFACE_DESCRIPTOR));
- INITIALIZE_LIST_HEAD(
- &(CurrentInterface->Description.EndpointListHead));
- INITIALIZE_LIST_HEAD(
- &(CurrentInterface->Description.UnknownListHead));
- INITIALIZE_LIST_HEAD(&(CurrentInterface->EndpointList));
- INSERT_BEFORE(
- &(CurrentInterface->Description.ListEntry),
- &(CurrentConfiguration->Description.InterfaceListHead));
- NewBufferPointer = (PUCHAR)(CurrentInterface + 1);
- } else if (DescriptorType == UsbDescriptorTypeEndpoint) {
- //
- // If an endpoint came with no interface, that's illegal.
- //
- if (CurrentInterface == NULL) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- Endpoint = (PUSB_ENDPOINT_DESCRIPTION)NewBufferPointer;
- if (DescriptorLength < sizeof(USB_ENDPOINT_DESCRIPTOR)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto GetConfigurationEnd;
- }
- RtlCopyMemory(&(Endpoint->Descriptor),
- BufferPointer,
- sizeof(USB_ENDPOINT_DESCRIPTOR));
- INSERT_BEFORE(&(Endpoint->ListEntry),
- &(CurrentInterface->Description.EndpointListHead));
- NewBufferPointer = (PUCHAR)(Endpoint + 1);
- //
- // Add an unknown descriptor to the interface if there is one. HID
- // descriptors are nestled in this way.
- //
- } else {
- if (CurrentInterface != NULL) {
- Unknown = (PUSB_UNKNOWN_DESCRIPTION)NewBufferPointer;
- Unknown->Descriptor = (PUCHAR)(Unknown + 1);
- RtlCopyMemory(Unknown->Descriptor,
- BufferPointer,
- DescriptorLength);
- INSERT_BEFORE(&(Unknown->ListEntry),
- &(CurrentInterface->Description.UnknownListHead));
- NewBufferPointer =
- ALIGN_POINTER_UP(Unknown->Descriptor + DescriptorLength,
- sizeof(ULONGLONG));
- }
- }
- //
- // Move on to the next descriptor.
- //
- BufferPointer += DescriptorLength;
- Length += DescriptorLength;
- }
- ASSERT((UINTN)NewBufferPointer - (UINTN)CurrentConfiguration <=
- AllocationSize);
- //
- // Insert the new configuration onto the global list to cache it for
- // future calls.
- //
- INSERT_BEFORE(&(CurrentConfiguration->ListEntry),
- &(Device->ConfigurationList));
- GetConfigurationEnd:
- KeReleaseQueuedLock(Device->ConfigurationLock);
- if (!KSUCCESS(Status)) {
- if (CurrentConfiguration != NULL) {
- MmFreePagedPool(CurrentConfiguration);
- CurrentConfiguration = NULL;
- }
- }
- if (ConfigurationDescriptor != NULL) {
- MmFreePagedPool(ConfigurationDescriptor);
- }
- *Configuration = CurrentConfiguration;
- return Status;
- }
- KSTATUS
- UsbpSubmitTransfer (
- PUSB_TRANSFER Transfer,
- ULONG PrivateFlags,
- BOOL PolledMode
- )
- /*++
- Routine Description:
- This routine submits a USB transfer. The routine returns immediately,
- indicating only whether the transfer was submitted successfully. When the
- transfer actually completes, the callback routine will be called.
- Arguments:
- Transfer - Supplies a pointer to the transfer to destroy.
- PrivateFlags - Supplies an optional bitfield of private flags regarding the
- transfer. See USB_TRANSFER_PRIVATE_* definitions.
- PolledMode - Supplies a boolean indicating whether the I/O should be done
- in polled mode or not. This is reserved for I/O paths after a critical
- system error.
- Return Value:
- STATUS_SUCCESS if the transfer was submitted to the USB host controller's
- queue.
- STATUS_INVALID_PARAMETER if one or more of the transfer fields is not
- properly filled out.
- Failing status codes if the request could not be submitted.
- --*/
- {
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- PUSB_HOST_CONTROLLER Controller;
- PUSB_DEVICE Device;
- PUSB_ENDPOINT Endpoint;
- ULONG FlushAlignment;
- ULONG FlushLength;
- USB_TRANSFER_STATE OriginalState;
- BOOL PacketQueued;
- BOOL ReleaseDeviceLock;
- PUSB_SETUP_PACKET Setup;
- KSTATUS Status;
- PUSB_HOST_SUBMIT_TRANSFER SubmitTransfer;
- ASSERT(Transfer != NULL);
- CompleteTransfer = (PUSB_TRANSFER_PRIVATE)Transfer;
- Endpoint = CompleteTransfer->Endpoint;
- Controller = CompleteTransfer->Device->Controller;
- Device = (PUSB_DEVICE)CompleteTransfer->Device;
- PacketQueued = FALSE;
- ReleaseDeviceLock = FALSE;
- //
- // Reference the transfer.
- //
- UsbTransferAddReference(Transfer);
- //
- // Callers are not allowed to allocate their own transfer structures, nor
- // are they allowed to resubmit packets that have not completed.
- //
- if (CompleteTransfer->Magic != USB_TRANSFER_INTERNAL_MAGIC) {
- ASSERT(FALSE);
- Transfer->Error = UsbErrorTransferAllocatedIncorrectly;
- Status = STATUS_INVALID_PARAMETER;
- goto SubmitTransferEnd;
- }
- //
- // Also fail if a transfer is submitted while it is still in-flight. It
- // should either be inactive or in the middle of the callback.
- //
- if (CompleteTransfer->State == TransferActive) {
- ASSERT(FALSE);
- Transfer->Error = UsbErrorTransferSubmittedWhileStillActive;
- Status = STATUS_RESOURCE_IN_USE;
- goto SubmitTransferEnd;
- }
- ASSERT(CompleteTransfer->CompletionListEntry.Next == NULL);
- //
- // Validate the transfer.
- //
- if ((Transfer->Length == 0) ||
- (Transfer->Length > CompleteTransfer->MaxTransferSize) ||
- (Transfer->Buffer == NULL) ||
- (Transfer->BufferPhysicalAddress == INVALID_PHYSICAL_ADDRESS) ||
- (Transfer->BufferActualLength < Transfer->Length) ||
- ((Transfer->Direction != UsbTransferDirectionIn) &&
- (Transfer->Direction != UsbTransferDirectionOut))) {
- ASSERT(FALSE);
- Transfer->Error = UsbErrorTransferIncorrectlyFilledOut;
- Status = STATUS_INVALID_PARAMETER;
- goto SubmitTransferEnd;
- }
- if ((PrivateFlags & USB_TRANSFER_PRIVATE_SYNCHRONOUS) != 0) {
- CompleteTransfer->PrivateFlags |= USB_TRANSFER_PRIVATE_SYNCHRONOUS;
- } else {
- CompleteTransfer->PrivateFlags &= ~USB_TRANSFER_PRIVATE_SYNCHRONOUS;
- if (Transfer->CallbackRoutine == NULL) {
- Transfer->Error = UsbErrorTransferIncorrectlyFilledOut;
- Status = STATUS_INVALID_PARAMETER;
- goto SubmitTransferEnd;
- }
- }
- Transfer->Status = STATUS_NOT_STARTED;
- Transfer->Error = UsbErrorTransferNotStarted;
- Transfer->LengthTransferred = 0;
- if (PolledMode == FALSE) {
- SubmitTransfer = Controller->Device.SubmitTransfer;
- ASSERT(SubmitTransfer != NULL);
- } else {
- SubmitTransfer = Controller->Device.SubmitPolledTransfer;
- if (SubmitTransfer == NULL) {
- Status = STATUS_NOT_SUPPORTED;
- goto SubmitTransferEnd;
- }
- }
- //
- // Clean the data buffer in preparation for the USB controller doing DMA
- // to/from it. Control transfers always have an outgoing portion.
- //
- FlushAlignment = MmGetIoBufferAlignment();
- ASSERT(POWER_OF_2(FlushAlignment) != FALSE);
- FlushLength = ALIGN_RANGE_UP(Transfer->Length, FlushAlignment);
- if ((ALIGN_RANGE_DOWN((UINTN)Transfer->Buffer, FlushAlignment) !=
- (UINTN)Transfer->Buffer) ||
- (FlushLength > Transfer->BufferActualLength)) {
- ASSERT(FALSE);
- Transfer->Error = UsbErrorTransferBufferNotAligned;
- Status = STATUS_INVALID_PARAMETER;
- Transfer->Status = Status;
- goto SubmitTransferEnd;
- }
- //
- // Print out any debug information. The transfer isn't guaranteed to be
- // submitted after this point, but this touches the transfer buffer, which
- // needs to be flushed and then not touched.
- //
- if ((UsbDebugFlags & USB_DEBUG_TRANSFERS) != 0) {
- if ((UsbDebugDeviceAddress == 0) ||
- (UsbDebugDeviceAddress ==
- CompleteTransfer->Protected.DeviceAddress)) {
- ASSERT(Transfer->Direction < UsbTransferDirectionCount);
- ASSERT(CompleteTransfer->Protected.Type < UsbTransferTypeCount);
- RtlDebugPrint(
- "USB: Transfer (0x%08x) %s dev %d, EP%x, %s, "
- "Buffer 0x%x, Length 0x%x\n",
- Transfer,
- UsbTransferDirectionStrings[Transfer->Direction],
- CompleteTransfer->Protected.DeviceAddress,
- CompleteTransfer->Protected.EndpointNumber,
- UsbTransferTypeStrings[CompleteTransfer->Protected.Type],
- Transfer->Buffer,
- Transfer->Length);
- if (CompleteTransfer->Protected.Type == UsbTransferTypeControl) {
- ASSERT(Transfer->Length >= sizeof(USB_SETUP_PACKET));
- Setup = Transfer->Buffer;
- RtlDebugPrint("USB: RequestType 0x%x, Request 0x%x, "
- "Value 0x%x, Index 0x%x, Length 0x%x\n",
- Setup->RequestType,
- Setup->Request,
- Setup->Value,
- Setup->Index,
- Setup->Length);
- }
- }
- }
- //
- // Flush the transfer buffer. Do not access the buffer beyond this point.
- //
- if (CompleteTransfer->Endpoint->Type == UsbTransferTypeControl) {
- if (Transfer->Direction == UsbTransferDirectionOut) {
- MmFlushBufferForDataOut(Transfer->Buffer, FlushLength);
- } else {
- MmFlushBufferForDataIo(Transfer->Buffer, FlushLength);
- }
- //
- // Bulk, interrupt, and isochronous transfers really only go the direction
- // they claim.
- //
- } else {
- if (Transfer->Direction == UsbTransferDirectionOut) {
- MmFlushBufferForDataOut(Transfer->Buffer, FlushLength);
- } else {
- ASSERT(Transfer->Direction == UsbTransferDirectionIn);
- MmFlushBufferForDataIn(Transfer->Buffer, FlushLength);
- }
- }
- //
- // Acquire the USB device's lock to check the status. Transfers should not
- // be submitted to disconnected devices.
- //
- if (PolledMode == FALSE) {
- KeAcquireQueuedLock(Device->Lock);
- ReleaseDeviceLock = TRUE;
- }
- if (Device->Connected == FALSE) {
- Transfer->Error = UsbErrorTransferDeviceNotConnected;
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto SubmitTransferEnd;
- }
- //
- // Update the transfer state to 'active' before submission to the host
- // controller. This could be a transition from either the callback state
- // or the inactive state.
- //
- OriginalState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferActive,
- TransferInCallback);
- if (OriginalState != TransferInCallback) {
- OriginalState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferActive,
- TransferInactive);
- if (OriginalState != TransferInactive) {
- KeCrashSystem(CRASH_USB_ERROR,
- UsbErrorTransferSubmittedWhileStillActive,
- (UINTN)Transfer,
- CompleteTransfer->State,
- 0);
- }
- }
- //
- // Submit the transfer to the host controller.
- //
- Status = SubmitTransfer(Controller->Device.HostControllerContext,
- Endpoint->HostControllerContext,
- &(CompleteTransfer->Protected),
- CompleteTransfer->HostControllerContext);
- if (!KSUCCESS(Status)) {
- Transfer->Error = UsbErrorTransferFailedToSubmit;
- //
- // Flip the transfer state to inactive, always.
- //
- OriginalState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferInactive,
- TransferActive);
- ASSERT(OriginalState == TransferActive);
- goto SubmitTransferEnd;
- }
- if (PolledMode == FALSE) {
- KeReleaseQueuedLock(Device->Lock);
- ReleaseDeviceLock = FALSE;
- }
- PacketQueued = TRUE;
- Status = STATUS_SUCCESS;
- SubmitTransferEnd:
- if (!KSUCCESS(Status)) {
- //
- // Release the device lock, if necessary.
- //
- if (ReleaseDeviceLock != FALSE) {
- ASSERT(PolledMode == FALSE);
- KeReleaseQueuedLock(Device->Lock);
- }
- //
- // Report transfer failures.
- //
- if ((UsbDebugFlags & (USB_DEBUG_TRANSFERS | USB_DEBUG_ERRORS)) != 0) {
- if ((UsbDebugDeviceAddress == 0) ||
- (UsbDebugDeviceAddress ==
- CompleteTransfer->Protected.DeviceAddress)) {
- RtlDebugPrint(
- "USB: Submit failed, transfer (0x%08x) %s "
- "dev %d, EP%x, %s, Buffer 0x%x, Len 0x%x. Status %d\n",
- Transfer,
- UsbTransferDirectionStrings[Transfer->Direction],
- CompleteTransfer->Protected.DeviceAddress,
- CompleteTransfer->Protected.EndpointNumber,
- UsbTransferTypeStrings[CompleteTransfer->Protected.Type],
- Transfer->Buffer,
- Transfer->Length,
- Status);
- }
- }
- //
- // Upon failure, cancel the transfer if it was submitted. This will
- // modify the transfer state. Also, it could fail if the transfer went
- // through very quickly. This, however, is not currently a valid error
- // path - just future proofing.
- //
- if (PacketQueued != FALSE) {
- UsbCancelTransfer(Transfer, TRUE);
- //
- // Relese the reference on failure. If the cancel path was taken, then
- // the reference will be released after the callback. Also set the
- // transfer status here; the cancel path does that as well.
- //
- } else {
- Transfer->Status = Status;
- UsbTransferReleaseReference(Transfer);
- }
- }
- return Status;
- }
- KSTATUS
- UsbpCreateEndpointsForInterface (
- PUSB_DEVICE Device,
- PUSB_INTERFACE Interface
- )
- /*++
- Routine Description:
- This routine creates endpoints for the given interface.
- Arguments:
- Device - Supplies a pointer to the device owning the interface and
- endpoints.
- Interface - Supplies a pointer to the interface to create endpoints for.
- Return Value:
- Status code.
- --*/
- {
- UCHAR Attributes;
- PLIST_ENTRY CurrentEntry;
- USB_TRANSFER_DIRECTION Direction;
- PUSB_ENDPOINT Endpoint;
- PUSB_ENDPOINT_DESCRIPTION EndpointDescription;
- UCHAR EndpointNumber;
- ULONG MaxPacketSize;
- ULONG PollRate;
- KSTATUS Status;
- USB_TRANSFER_TYPE Type;
- //
- // Loop through all the endpoint descriptions.
- //
- CurrentEntry = Interface->Description.EndpointListHead.Next;
- while (CurrentEntry != &(Interface->Description.EndpointListHead)) {
- EndpointDescription = LIST_VALUE(CurrentEntry,
- USB_ENDPOINT_DESCRIPTION,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- PollRate = 0;
- //
- // Get the endpoint number.
- //
- EndpointNumber = EndpointDescription->Descriptor.EndpointAddress;
- //
- // Get the endpoint type.
- //
- Attributes = EndpointDescription->Descriptor.Attributes;
- switch (Attributes & USB_ENDPOINT_ATTRIBUTES_TYPE_MASK) {
- case USB_ENDPOINT_ATTRIBUTES_TYPE_CONTROL:
- Type = UsbTransferTypeControl;
- break;
- case USB_ENDPOINT_ATTRIBUTES_TYPE_ISOCHRONOUS:
- Type = UsbTransferTypeIsochronous;
- PollRate = EndpointDescription->Descriptor.Interval;
- break;
- case USB_ENDPOINT_ATTRIBUTES_TYPE_BULK:
- Type = UsbTransferTypeBulk;
- if ((EndpointNumber & USB_ENDPOINT_ADDRESS_DIRECTION_IN) == 0) {
- PollRate = EndpointDescription->Descriptor.Interval;
- }
- break;
- case USB_ENDPOINT_ATTRIBUTES_TYPE_INTERRUPT:
- default:
- Type = UsbTransferTypeInterrupt;
- PollRate = EndpointDescription->Descriptor.Interval;
- break;
- }
- //
- // Get the direction.
- //
- if (Type == UsbTransferTypeControl) {
- Direction = UsbTransferBidirectional;
- } else {
- Direction = UsbTransferDirectionOut;
- if ((EndpointNumber & USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
- Direction = UsbTransferDirectionIn;
- }
- }
- MaxPacketSize = EndpointDescription->Descriptor.MaxPacketSize;
- Status = UsbpCreateEndpoint(Device,
- EndpointNumber,
- Direction,
- Type,
- MaxPacketSize,
- PollRate,
- &Endpoint);
- if (!KSUCCESS(Status)) {
- goto CreateEndpointsForInterfaceEnd;
- }
- INSERT_BEFORE(&(Endpoint->ListEntry), &(Interface->EndpointList));
- }
- Status = STATUS_SUCCESS;
- CreateEndpointsForInterfaceEnd:
- if (!KSUCCESS(Status)) {
- //
- // Loop through and free any endpoints that were created.
- //
- CurrentEntry = Interface->EndpointList.Next;
- while (CurrentEntry != &(Interface->EndpointList)) {
- Endpoint = LIST_VALUE(CurrentEntry, USB_ENDPOINT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- ASSERT(Endpoint->ReferenceCount == 1);
- UsbpEndpointReleaseReference(Device, Endpoint);
- }
- }
- return Status;
- }
- PUSB_ENDPOINT
- UsbpGetDeviceEndpoint (
- PUSB_DEVICE Device,
- UCHAR EndpointNumber
- )
- /*++
- Routine Description:
- This routine looks up a USB endpoint for the given device.
- Arguments:
- Device - Supplies a pointer to a USB device.
- EndpointNumber - Supplies the number of the desired endpoint.
- Return Value:
- Returns a pointer to a USB endpoint on success, or NULL if the given
- endpoint does not exist for the given device.
- --*/
- {
- PUSB_CONFIGURATION ActiveConfiguration;
- PLIST_ENTRY CurrentEndpointEntry;
- PLIST_ENTRY CurrentInterfaceEntry;
- PUSB_ENDPOINT Endpoint;
- PUSB_INTERFACE Interface;
- PLIST_ENTRY InterfaceListHead;
- //
- // Endpoint zero is easy to retrieve.
- //
- if (EndpointNumber == 0) {
- return Device->EndpointZero;
- }
- //
- // Run through the list of interfaces and associated endpoints to find
- // non-zero endpoints.
- //
- ASSERT(Device->ActiveConfiguration != NULL);
- ActiveConfiguration = Device->ActiveConfiguration;
- InterfaceListHead = &(ActiveConfiguration->Description.InterfaceListHead);
- CurrentInterfaceEntry = InterfaceListHead->Next;
- Endpoint = NULL;
- while (CurrentInterfaceEntry != InterfaceListHead) {
- Interface = LIST_VALUE(CurrentInterfaceEntry,
- USB_INTERFACE,
- Description.ListEntry);
- CurrentEndpointEntry = Interface->EndpointList.Next;
- CurrentInterfaceEntry = CurrentInterfaceEntry->Next;
- while (CurrentEndpointEntry != &(Interface->EndpointList)) {
- Endpoint = LIST_VALUE(CurrentEndpointEntry,
- USB_ENDPOINT,
- ListEntry);
- CurrentEndpointEntry = CurrentEndpointEntry->Next;
- if (Endpoint->Number == EndpointNumber) {
- break;
- }
- }
- if ((Endpoint != NULL) && (Endpoint->Number == EndpointNumber)) {
- break;
- }
- }
- return Endpoint;
- }
- VOID
- UsbpCompletedTransferWorker (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine processes completed USB transfers.
- Arguments:
- Parameter - Supplies a pointer to the USB host controller.
- Return Value:
- None.
- --*/
- {
- PUSB_TRANSFER_CALLBACK CallbackRoutine;
- PUSB_TRANSFER_PRIVATE CompleteTransfer;
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue;
- PLIST_ENTRY CurrentEntry;
- RUNLEVEL OldRunLevel;
- USB_TRANSFER_STATE OldState;
- LIST_ENTRY TransferList;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- CompletionQueue = (PUSB_TRANSFER_COMPLETION_QUEUE)Parameter;
- //
- // Acquire the lock and pull all transfers off of the list. Once the list
- // is empty and the lock is released, other completed transfers will know
- // that the work item needs to be queued.
- //
- ASSERT(LIST_EMPTY(&(CompletionQueue->CompletedTransfersList)) == FALSE);
- OldRunLevel = UsbpAcquireCompletedTransfersLock(CompletionQueue);
- MOVE_LIST(&(CompletionQueue->CompletedTransfersList), &TransferList);
- INITIALIZE_LIST_HEAD(&(CompletionQueue->CompletedTransfersList));
- UsbpReleaseCompletedTransfersLock(CompletionQueue, OldRunLevel);
- //
- // Now that the lock is released and execution is at low level, process the
- // work items.
- //
- while (LIST_EMPTY(&TransferList) == FALSE) {
- CurrentEntry = TransferList.Next;
- LIST_REMOVE(CurrentEntry);
- CompleteTransfer = LIST_VALUE(CurrentEntry,
- USB_TRANSFER_PRIVATE,
- CompletionListEntry);
- ASSERT(CompleteTransfer->Magic == USB_TRANSFER_INTERNAL_MAGIC);
- //
- // Mark that the transfer is no longer in flight, but in the callback.
- //
- OldState = RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferInCallback,
- TransferActive);
- ASSERT(OldState == TransferActive);
- //
- // Call the callback routine.
- //
- CompleteTransfer->CompletionListEntry.Next = NULL;
- CallbackRoutine = CompleteTransfer->Protected.Public.CallbackRoutine;
- CallbackRoutine(&(CompleteTransfer->Protected.Public));
- //
- // If the callback did not resubmit the transfer, then move it to the
- // inactive state. See the submit routine for how this change
- // synchronizes with re-submits that are outside the callback (e.g. in
- // a work item).
- //
- RtlAtomicCompareExchange32(&(CompleteTransfer->State),
- TransferInactive,
- TransferInCallback);
- //
- // Once the callback is called, USB core is done with this transfer;
- // release the reference taken during submit.
- //
- UsbTransferReleaseReference((PUSB_TRANSFER)CompleteTransfer);
- }
- return;
- }
- RUNLEVEL
- UsbpAcquireCompletedTransfersLock (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue
- )
- /*++
- Routine Description:
- This routine acquires the given completion queue's completed transfers lock
- at dispatch level.
- Arguments:
- CompletionQueue - Supplies a pointer to the completion queue to lock.
- Return Value:
- Returns the previous run-level, which must be passed in when the completion
- queue is unlocked.
- --*/
- {
- RUNLEVEL OldRunLevel;
- OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
- KeAcquireSpinLock(&(CompletionQueue->CompletedTransfersListLock));
- return OldRunLevel;
- }
- VOID
- UsbpReleaseCompletedTransfersLock (
- PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue,
- RUNLEVEL OldRunLevel
- )
- /*++
- Routine Description:
- This routine releases the given completion queue's completed transfers
- lock, and returns the run-level to its previous value.
- Arguments:
- CompletionQueue - Supplies a pointer to the completion queue to unlock.
- OldRunLevel - Supplies the original run level returned when the lock was
- acquired.
- Return Value:
- None.
- --*/
- {
- KeReleaseSpinLock(&(CompletionQueue->CompletedTransfersListLock));
- KeLowerRunLevel(OldRunLevel);
- return;
- }
|