123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523 |
- /*++
- Copyright (c) 2014 Evan Green
- Module Name:
- sd.c
- Abstract:
- This module implements the SD/MMC driver.
- Author:
- Evan Green 27-Feb-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Define away the API decorator.
- //
- #define SD_API
- #include <minoca/kernel/driver.h>
- #include <minoca/intrface/disk.h>
- #include <minoca/sd/sd.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the maximum number of slots that can be on one device. On current
- // implementations this is limited by the number of PCI BARs, where each
- // slot gets a BAR.
- //
- #define MAX_SD_SLOTS 6
- //
- // Define the amount of time in microseconds to wait after an insertion event
- // to allow the card to simmer down in the slot.
- //
- #define SD_INSERTION_SETTLE_DELAY 50000
- //
- // Define the set of flags for an SD disk.
- //
- #define SD_DISK_FLAG_DMA_SUPPORTED 0x00000001
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _SD_DEVICE_TYPE {
- SdDeviceInvalid,
- SdDeviceBus,
- SdDeviceSlot,
- SdDeviceDisk
- } SD_DEVICE_TYPE, *PSD_DEVICE_TYPE;
- typedef struct _SD_BUS SD_BUS, *PSD_BUS;
- typedef struct _SD_SLOT SD_SLOT, *PSD_SLOT;
- /*++
- Structure Description:
- This structure describes an SD/MMC disk context (the context used by the
- bus driver for the disk device).
- Members:
- Type - Stores the type identifying this as an SD disk structure.
- ReferenceCount - Stores a reference count for the disk.
- Device - Stores a pointer to the OS device for the disk.
- Parent - Stores a pointer to the parent slot.
- Controller - Stores a pointer to the SD controller structure.
- ControllerLock - Stores a pointer to the lock used to serialize access to
- the controller. This is owned by the parent slot.
- Irp - Stores a pointer to the current IRP running on this disk.
- Flags - Stores a bitmask of flags describing the disk state. See
- SD_DISK_FLAG_* for definitions;
- BlockShift - Stores the block size shift of the disk.
- BlockCount - Stores the number of blocks on the disk.
- DiskInterface - Stores the disk interface presented to the system.
- --*/
- typedef struct _SD_DISK {
- SD_DEVICE_TYPE Type;
- volatile ULONG ReferenceCount;
- PDEVICE Device;
- PSD_SLOT Parent;
- PSD_CONTROLLER Controller;
- PQUEUED_LOCK ControllerLock;
- PIRP Irp;
- ULONG Flags;
- ULONG BlockShift;
- ULONGLONG BlockCount;
- DISK_INTERFACE DiskInterface;
- } SD_DISK, *PSD_DISK;
- /*++
- Structure Description:
- This structure describes an SD/MMC slot (the context used by the bus driver
- for the individual SD slot).
- Members:
- Type - Stores the type identifying this as an SD slot.
- Device - Stores a pointer to the OS device for the slot.
- Controller - Stores a pointer to the SD controller structure.
- ControllerBase - Stores the virtual address of the base of the controller
- registers.
- Resource - Stores a pointer to the resource describing the location of the
- controller.
- ChildIndex - Stores the child index of this device.
- Parent - Stores a pointer back to the parent.
- Disk - Stores a pointer to the child disk context.
- Lock - Stores a pointer to a lock used to serialize access to the
- controller.
- --*/
- struct _SD_SLOT {
- SD_DEVICE_TYPE Type;
- PDEVICE Device;
- PSD_CONTROLLER Controller;
- PVOID ControllerBase;
- PRESOURCE_ALLOCATION Resource;
- UINTN ChildIndex;
- PSD_BUS Parent;
- PSD_DISK Disk;
- PQUEUED_LOCK Lock;
- };
- /*++
- Structure Description:
- This structure describes an SD/MMC driver context (the function driver
- context for the SD bus controller).
- Members:
- Type - Stores the type identifying this as an SD controller.
- Slots - Stores the array of SD slots.
- Handle - Stores the connected interrupt handle.
- InterruptLine - Stores ths interrupt line of the controller.
- InterruptVector - Stores the interrupt vector of the controller.
- InterruptResourcesFound - Stores a boolean indicating whether or not
- interrupt resources were located for this device.
- --*/
- struct _SD_BUS {
- SD_DEVICE_TYPE Type;
- SD_SLOT Slots[MAX_SD_SLOTS];
- HANDLE InterruptHandle;
- ULONGLONG InterruptLine;
- ULONGLONG InterruptVector;
- BOOL InterruptResourcesFound;
- };
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- SdAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- SdDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- SdDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- SdDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- SdDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- SdDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- INTERRUPT_STATUS
- SdBusInterruptService (
- PVOID Context
- );
- INTERRUPT_STATUS
- SdBusInterruptServiceDispatch (
- PVOID Context
- );
- VOID
- SdpBusDispatchStateChange (
- PIRP Irp,
- PSD_BUS Bus
- );
- VOID
- SdpSlotDispatchStateChange (
- PIRP Irp,
- PSD_SLOT Slot
- );
- VOID
- SdpDiskDispatchStateChange (
- PIRP Irp,
- PSD_DISK Disk
- );
- KSTATUS
- SdpBusProcessResourceRequirements (
- PIRP Irp,
- PSD_BUS Bus
- );
- KSTATUS
- SdpBusStartDevice (
- PIRP Irp,
- PSD_BUS Bus
- );
- KSTATUS
- SdpBusQueryChildren (
- PIRP Irp,
- PSD_BUS Context
- );
- KSTATUS
- SdpSlotStartDevice (
- PIRP Irp,
- PSD_SLOT Slot
- );
- KSTATUS
- SdpSlotQueryChildren (
- PIRP Irp,
- PSD_SLOT Slot
- );
- PSD_DISK
- SdpCreateDisk (
- PSD_SLOT Slot
- );
- VOID
- SdpDestroyDisk (
- PSD_DISK Disk
- );
- VOID
- SdpDiskAddReference (
- PSD_DISK Disk
- );
- VOID
- SdpDiskReleaseReference (
- PSD_DISK Disk
- );
- VOID
- SdpDmaCompletion (
- PSD_CONTROLLER Controller,
- PVOID Context,
- UINTN BytesTransferred,
- KSTATUS Status
- );
- KSTATUS
- SdpDiskBlockIoReset (
- PVOID DiskToken
- );
- KSTATUS
- SdpDiskBlockIoRead (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- SdpDiskBlockIoWrite (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- SdpPerformIoPolled (
- PIRP_READ_WRITE IrpReadWrite,
- PSD_DISK Disk,
- BOOL Write,
- BOOL LockRequired
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER SdDriver = NULL;
- UUID SdDiskInterfaceUuid = UUID_DISK_INTERFACE;
- DISK_INTERFACE SdDiskInterfaceTemplate = {
- DISK_INTERFACE_VERSION,
- NULL,
- 0,
- 0,
- NULL,
- SdpDiskBlockIoReset,
- SdpDiskBlockIoRead,
- SdpDiskBlockIoWrite
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the SD/MMC driver. It registers its
- other dispatch functions, and performs driver-wide initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- SdDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = SdAddDevice;
- FunctionTable.DispatchStateChange = SdDispatchStateChange;
- FunctionTable.DispatchOpen = SdDispatchOpen;
- FunctionTable.DispatchClose = SdDispatchClose;
- FunctionTable.DispatchIo = SdDispatchIo;
- FunctionTable.DispatchSystemControl = SdDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- SdAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a device is detected for which the SD/MMC driver
- acts as the function driver. The driver will attach itself to the stack.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- PSD_BUS Context;
- PSD_SLOT Slot;
- UINTN SlotIndex;
- KSTATUS Status;
- Context = MmAllocateNonPagedPool(sizeof(SD_BUS), SD_ALLOCATION_TAG);
- if (Context == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(Context, sizeof(SD_BUS));
- Context->Type = SdDeviceBus;
- Context->InterruptHandle = INVALID_HANDLE;
- for (SlotIndex = 0; SlotIndex < MAX_SD_SLOTS; SlotIndex += 1) {
- Slot = &(Context->Slots[SlotIndex]);
- Slot->Type = SdDeviceSlot;
- Slot->ChildIndex = SlotIndex;
- Slot->Parent = Context;
- }
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Context);
- if (!KSUCCESS(Status)) {
- MmFreeNonPagedPool(Context);
- }
- return Status;
- }
- VOID
- SdDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSD_BUS Context;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- Context = (PSD_BUS)DeviceContext;
- switch (Context->Type) {
- case SdDeviceBus:
- SdpBusDispatchStateChange(Irp, Context);
- break;
- case SdDeviceSlot:
- SdpSlotDispatchStateChange(Irp, (PSD_SLOT)Context);
- break;
- case SdDeviceDisk:
- SdpDiskDispatchStateChange(Irp, (PSD_DISK)Context);
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- VOID
- SdDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSD_DISK Disk;
- Disk = DeviceContext;
- if (Disk->Type != SdDeviceDisk) {
- return;
- }
- SdpDiskAddReference(Disk);
- IoCompleteIrp(SdDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- SdDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSD_DISK Disk;
- Disk = DeviceContext;
- if (Disk->Type != SdDeviceDisk) {
- return;
- }
- SdpDiskReleaseReference(Disk);
- IoCompleteIrp(SdDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- SdDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- UINTN BlockCount;
- ULONGLONG BlockOffset;
- UINTN BytesToComplete;
- BOOL CompleteIrp;
- PSD_CONTROLLER Controller;
- PSD_DISK Disk;
- IO_OFFSET IoOffset;
- ULONG IrpReadWriteFlags;
- KSTATUS IrpStatus;
- KSTATUS Status;
- BOOL Write;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Disk = DeviceContext;
- if (Disk->Type != SdDeviceDisk) {
- ASSERT(FALSE);
- return;
- }
- CompleteIrp = TRUE;
- Write = FALSE;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- Write = TRUE;
- }
- //
- // Polled I/O is shared by a few code paths and prepares the IRP for I/O
- // further down the stack. It should also only be hit in the down direction
- // path as it always completes the IRP.
- //
- if ((Disk->Flags & SD_DISK_FLAG_DMA_SUPPORTED) == 0) {
- ASSERT(Irp->Direction == IrpDown);
- Status = SdpPerformIoPolled(&(Irp->U.ReadWrite), Disk, Write, TRUE);
- goto DispatchIoEnd;
- }
- //
- // Set the IRP read/write flags for the preparation and completion steps.
- //
- IrpReadWriteFlags = IRP_READ_WRITE_FLAG_DMA;
- if (Write != FALSE) {
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- Controller = Disk->Controller;
- if (Irp->Direction == IrpDown) {
- Controller->Try = 0;
- }
- //
- // If the IRP is on the way up, then clean up after the DMA as this IRP is
- // still sitting in the channel. An IRP going up is already complete.
- //
- if (Irp->Direction == IrpUp) {
- ASSERT (Irp == Disk->Irp);
- Disk->Irp = NULL;
- //
- // Try to recover on failure.
- //
- IrpStatus = IoGetIrpStatus(Irp);
- if (!KSUCCESS(IrpStatus)) {
- Status = SdErrorRecovery(Controller);
- if (!KSUCCESS(Status)) {
- IrpStatus = Status;
- IoUpdateIrpStatus(Irp, IrpStatus);
- }
- //
- // Do not make further attempts if the media is gone or enough
- // attempts have been made.
- //
- if (((Controller->Flags &
- SD_CONTROLLER_FLAG_MEDIA_CHANGED) != 0) ||
- ((Controller->Flags &
- SD_CONTROLLER_FLAG_MEDIA_PRESENT) == 0) ||
- (Controller->Try >= SD_MAX_IO_RETRIES)) {
- IrpStatus = STATUS_SUCCESS;
- } else {
- Controller->Try += 1;
- }
- }
- KeReleaseQueuedLock(Disk->ControllerLock);
- Status = IoCompleteReadWriteIrp(&(Irp->U.ReadWrite),
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- IoUpdateIrpStatus(Irp, Status);
- }
- //
- // Potentially return the completed IRP.
- //
- if (KSUCCESS(IrpStatus)) {
- CompleteIrp = FALSE;
- goto DispatchIoEnd;
- }
- }
- //
- // Start the DMA on the way down.
- //
- BytesToComplete = Irp->U.ReadWrite.IoSizeInBytes;
- IoOffset = Irp->U.ReadWrite.IoOffset;
- Irp->U.ReadWrite.IoBytesCompleted = 0;
- ASSERT((Disk->BlockCount != 0) && (Disk->BlockShift != 0));
- ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
- ASSERT(IS_ALIGNED(IoOffset, 1 << Disk->BlockShift) != FALSE);
- ASSERT(IS_ALIGNED(BytesToComplete, 1 << Disk->BlockShift) != FALSE);
- //
- // Before acquiring the controller's lock and starting the DMA, prepare
- // the I/O context for SD (i.e. it must use physical addresses that
- // are less than 4GB and be sector size aligned).
- //
- Status = IoPrepareReadWriteIrp(&(Irp->U.ReadWrite),
- 1 << Disk->BlockShift,
- 0,
- MAX_ULONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- //
- // Lock the controller to serialize access to the hardware.
- //
- KeAcquireQueuedLock(Disk->ControllerLock);
- if (((Controller->Flags & SD_CONTROLLER_FLAG_MEDIA_PRESENT) == 0) ||
- ((Controller->Flags & SD_CONTROLLER_FLAG_MEDIA_CHANGED) != 0)) {
- Status = STATUS_NO_MEDIA;
- if ((Controller->Flags & SD_CONTROLLER_FLAG_MEDIA_CHANGED) != 0) {
- Status = STATUS_MEDIA_CHANGED;
- }
- KeReleaseQueuedLock(Disk->ControllerLock);
- IoCompleteReadWriteIrp(&(Irp->U.ReadWrite), IrpReadWriteFlags);
- goto DispatchIoEnd;
- }
- //
- // Pend the IRP and fire up the DMA.
- //
- Irp->U.ReadWrite.NewIoOffset = Irp->U.ReadWrite.IoOffset;
- Disk->Irp = Irp;
- BlockOffset = IoOffset >> Disk->BlockShift;
- BlockCount = BytesToComplete >> Disk->BlockShift;
- CompleteIrp = FALSE;
- IoPendIrp(SdDriver, Irp);
- //
- // Make sure the system isn't trying to do I/O off the end of the disk.
- //
- ASSERT(BlockOffset < Disk->BlockCount);
- ASSERT(BlockCount >= 1);
- SdStandardBlockIoDma(Controller,
- BlockOffset,
- BlockCount,
- Irp->U.ReadWrite.IoBuffer,
- 0,
- Write,
- SdpDmaCompletion,
- Disk);
- //
- // DMA transfers are self perpetuating, so after kicking off this first
- // transfer, return. This returns with the lock held because I/O is
- // still in progress.
- //
- ASSERT(KeIsQueuedLockHeld(Disk->ControllerLock) != FALSE);
- ASSERT(CompleteIrp == FALSE);
- DispatchIoEnd:
- if (CompleteIrp != FALSE) {
- IoCompleteIrp(SdDriver, Irp, Status);
- }
- return;
- }
- VOID
- SdDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PVOID Context;
- PSD_DISK Disk;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- Context = Irp->U.SystemControl.SystemContext;
- Disk = DeviceContext;
- //
- // Only disk devices are supported.
- //
- if (Disk->Type != SdDeviceDisk) {
- return;
- }
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlLookup:
- Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
- Status = STATUS_PATH_NOT_FOUND;
- if (Lookup->Root != FALSE) {
- //
- // Enable opening of the root as a single file.
- //
- Properties = &(Lookup->Properties);
- Properties->FileId = 0;
- Properties->Type = IoObjectBlockDevice;
- Properties->HardLinkCount = 1;
- Properties->BlockCount = Disk->BlockCount;
- Properties->BlockSize = 1 << Disk->BlockShift;
- WRITE_INT64_SYNC(&(Properties->FileSize),
- Disk->BlockCount << Disk->BlockShift);
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(SdDriver, Irp, Status);
- break;
- //
- // Writes to the disk's properties are not allowed. Fail if the data
- // has changed.
- //
- case IrpMinorSystemControlWriteFileProperties:
- FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
- Properties = FileOperation->FileProperties;
- READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectBlockDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != (1 << Disk->BlockShift)) ||
- (Properties->BlockCount != Disk->BlockCount) ||
- (PropertiesFileSize != (Disk->BlockCount << Disk->BlockShift))) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(SdDriver, Irp, Status);
- break;
- //
- // Do not support hard disk device truncation.
- //
- case IrpMinorSystemControlTruncate:
- IoCompleteIrp(SdDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- //
- // Gather and return device information.
- //
- case IrpMinorSystemControlDeviceInformation:
- break;
- case IrpMinorSystemControlSynchronize:
- IoCompleteIrp(SdDriver, Irp, STATUS_SUCCESS);
- break;
- //
- // Ignore everything unrecognized.
- //
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- INTERRUPT_STATUS
- SdBusInterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the interrupt service routine for an SD bus.
- Arguments:
- Context - Supplies a pointer to the device context.
- Return Value:
- Returns whether or not the SD controller caused the interrupt.
- --*/
- {
- PSD_BUS Bus;
- PSD_SLOT Slot;
- UINTN SlotIndex;
- INTERRUPT_STATUS Status;
- INTERRUPT_STATUS TotalStatus;
- Bus = Context;
- TotalStatus = InterruptStatusNotClaimed;
- for (SlotIndex = 0; SlotIndex < MAX_SD_SLOTS; SlotIndex += 1) {
- Slot = &(Bus->Slots[SlotIndex]);
- if (Slot->Controller == NULL) {
- break;
- }
- Status = SdStandardInterruptService(Slot->Controller);
- if (Status != InterruptStatusNotClaimed) {
- TotalStatus = Status;
- }
- }
- return TotalStatus;
- }
- INTERRUPT_STATUS
- SdBusInterruptServiceDispatch (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the dispatch level interrupt service routine for an
- SD bus.
- Arguments:
- Context - Supplies a pointer to the device context.
- Return Value:
- Returns whether or not the SD controller caused the interrupt.
- --*/
- {
- PSD_BUS Bus;
- PSD_SLOT Slot;
- UINTN SlotIndex;
- INTERRUPT_STATUS Status;
- INTERRUPT_STATUS TotalStatus;
- Bus = Context;
- TotalStatus = InterruptStatusNotClaimed;
- for (SlotIndex = 0; SlotIndex < MAX_SD_SLOTS; SlotIndex += 1) {
- Slot = &(Bus->Slots[SlotIndex]);
- if (Slot->Controller == NULL) {
- break;
- }
- Status = SdStandardInterruptServiceDispatch(Slot->Controller);
- if (Status != InterruptStatusNotClaimed) {
- TotalStatus = Status;
- }
- }
- return TotalStatus;
- }
- VOID
- SdpBusDispatchStateChange (
- PIRP Irp,
- PSD_BUS Bus
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs for the SD bus device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Bus - Supplies a pointer to the SD bus.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- if (Irp->Direction == IrpUp) {
- if (!KSUCCESS(IoGetIrpStatus(Irp))) {
- return;
- }
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- Status = SdpBusProcessResourceRequirements(Irp, Bus);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(SdDriver, Irp, Status);
- }
- break;
- case IrpMinorStartDevice:
- Status = SdpBusStartDevice(Irp, Bus);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(SdDriver, Irp, Status);
- }
- break;
- case IrpMinorQueryChildren:
- Status = SdpBusQueryChildren(Irp, Bus);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(SdDriver, Irp, Status);
- }
- break;
- default:
- break;
- }
- }
- return;
- }
- VOID
- SdpSlotDispatchStateChange (
- PIRP Irp,
- PSD_SLOT Slot
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs for the SD bus device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Slot - Supplies a pointer to the SD slot.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- //
- // Actively handle IRPs as the bus driver for the slot.
- //
- if (Irp->Direction == IrpDown) {
- switch (Irp->MinorCode) {
- case IrpMinorStartDevice:
- Status = SdpSlotStartDevice(Irp, Slot);
- IoCompleteIrp(SdDriver, Irp, Status);
- break;
- case IrpMinorQueryResources:
- IoCompleteIrp(SdDriver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorQueryChildren:
- Status = SdpSlotQueryChildren(Irp, Slot);
- IoCompleteIrp(SdDriver, Irp, Status);
- break;
- default:
- break;
- }
- }
- return;
- }
- VOID
- SdpDiskDispatchStateChange (
- PIRP Irp,
- PSD_DISK Disk
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs for a parent device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Disk - Supplies a pointer to the SD disk.
- Return Value:
- None.
- --*/
- {
- BOOL CompleteIrp;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- //
- // The IRP is on its way down the stack. Do most processing here.
- //
- if (Irp->Direction == IrpDown) {
- Status = STATUS_NOT_SUPPORTED;
- CompleteIrp = TRUE;
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- Status = STATUS_SUCCESS;
- break;
- case IrpMinorStartDevice:
- //
- // Publish the disk interface.
- //
- Status = STATUS_SUCCESS;
- if (Disk->DiskInterface.DiskToken == NULL) {
- RtlCopyMemory(&(Disk->DiskInterface),
- &SdDiskInterfaceTemplate,
- sizeof(DISK_INTERFACE));
- Disk->DiskInterface.DiskToken = Disk;
- Disk->DiskInterface.BlockSize = 1 << Disk->BlockShift;
- Disk->DiskInterface.BlockCount = Disk->BlockCount;
- Status = IoCreateInterface(&SdDiskInterfaceUuid,
- Disk->Device,
- &(Disk->DiskInterface),
- sizeof(DISK_INTERFACE));
- if (!KSUCCESS(Status)) {
- Disk->DiskInterface.DiskToken = NULL;
- }
- }
- break;
- case IrpMinorQueryChildren:
- Irp->U.QueryChildren.Children = NULL;
- Irp->U.QueryChildren.ChildCount = 0;
- Status = STATUS_SUCCESS;
- break;
- case IrpMinorQueryInterface:
- break;
- case IrpMinorRemoveDevice:
- if (Disk->DiskInterface.DiskToken != NULL) {
- Status = IoDestroyInterface(&SdDiskInterfaceUuid,
- Disk->Device,
- &(Disk->DiskInterface));
- ASSERT(KSUCCESS(Status));
- Disk->DiskInterface.DiskToken = NULL;
- }
- SdpDiskReleaseReference(Disk);
- Status = STATUS_SUCCESS;
- break;
- //
- // Pass all other IRPs down.
- //
- default:
- CompleteIrp = FALSE;
- break;
- }
- //
- // Complete the IRP unless there's a reason not to.
- //
- if (CompleteIrp != FALSE) {
- IoCompleteIrp(SdDriver, Irp, Status);
- }
- //
- // The IRP is completed and is on its way back up.
- //
- } else {
- ASSERT(Irp->Direction == IrpUp);
- }
- return;
- }
- KSTATUS
- SdpBusProcessResourceRequirements (
- PIRP Irp,
- PSD_BUS Bus
- )
- /*++
- Routine Description:
- This routine filters through the resource requirements presented by the
- bus for a SD Bus controller. It adds an interrupt vector requirement
- for any interrupt line requested.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Bus - Supplies a pointer to the bus context.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_CONFIGURATION_LIST Requirements;
- KSTATUS Status;
- RESOURCE_REQUIREMENT VectorRequirement;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryResources));
- //
- // Initialize a nice interrupt vector requirement in preparation.
- //
- RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
- VectorRequirement.Type = ResourceTypeInterruptVector;
- VectorRequirement.Minimum = 0;
- VectorRequirement.Maximum = -1;
- VectorRequirement.Length = 1;
- //
- // Loop through all configuration lists, creating a vector for each line.
- //
- Requirements = Irp->U.QueryResources.ResourceRequirements;
- Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
- &VectorRequirement);
- if (!KSUCCESS(Status)) {
- goto BusProcessResourceRequirementsEnd;
- }
- BusProcessResourceRequirementsEnd:
- return Status;
- }
- KSTATUS
- SdpBusStartDevice (
- PIRP Irp,
- PSD_BUS Bus
- )
- /*++
- Routine Description:
- This routine starts an SD bus device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Bus - Supplies a pointer to the bus context.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- IO_CONNECT_INTERRUPT_PARAMETERS Connect;
- PRESOURCE_ALLOCATION LineAllocation;
- UINTN SlotIndex;
- KSTATUS Status;
- for (SlotIndex = 0; SlotIndex < MAX_SD_SLOTS; SlotIndex += 1) {
- Bus->Slots[SlotIndex].Resource = NULL;
- ASSERT(Bus->Slots[SlotIndex].Controller == NULL);
- }
- SlotIndex = 0;
- //
- // Loop through the allocated resources to get the controller base and the
- // interrupt.
- //
- AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
- ASSERT(AllocationList != NULL);
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- //
- // If the resource is an interrupt vector, then it should have an
- // owning interrupt line allocation.
- //
- if (Allocation->Type == ResourceTypeInterruptVector) {
- //
- // Currently only one interrupt resource is expected.
- //
- ASSERT(Bus->InterruptResourcesFound == FALSE);
- ASSERT(Allocation->OwningAllocation != NULL);
- //
- // Save the line and vector number.
- //
- LineAllocation = Allocation->OwningAllocation;
- Bus->InterruptLine = LineAllocation->Allocation;
- Bus->InterruptVector = Allocation->Allocation;
- Bus->InterruptResourcesFound = TRUE;
- } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
- if ((SlotIndex < MAX_SD_SLOTS) && (Allocation->Length > 0)) {
- Bus->Slots[SlotIndex].Resource = Allocation;
- SlotIndex += 1;
- }
- }
- //
- // Get the next allocation in the list.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- //
- // Attempt to connect the interrupt.
- //
- if (Bus->InterruptHandle == INVALID_HANDLE) {
- RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
- Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
- Connect.Device = Irp->Device;
- Connect.LineNumber = Bus->InterruptLine;
- Connect.Vector = Bus->InterruptVector;
- Connect.InterruptServiceRoutine = SdBusInterruptService;
- Connect.DispatchServiceRoutine = SdBusInterruptServiceDispatch;
- Connect.Context = Bus;
- Connect.Interrupt = &(Bus->InterruptHandle);
- Status = IoConnectInterrupt(&Connect);
- if (!KSUCCESS(Status)) {
- goto StartDeviceEnd;
- }
- }
- Status = STATUS_SUCCESS;
- StartDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Bus->InterruptHandle != INVALID_HANDLE) {
- IoDisconnectInterrupt(Bus->InterruptHandle);
- Bus->InterruptHandle = INVALID_HANDLE;
- }
- }
- return Status;
- }
- KSTATUS
- SdpBusQueryChildren (
- PIRP Irp,
- PSD_BUS Context
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs for the SD bus device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Context - Supplies a pointer to the bus context.
- Return Value:
- Status code.
- --*/
- {
- UINTN ChildCount;
- UINTN ChildIndex;
- PDEVICE Children[MAX_SD_SLOTS];
- PSD_SLOT Slot;
- KSTATUS Status;
- ChildCount = 0;
- for (ChildIndex = 0; ChildIndex < MAX_SD_SLOTS; ChildIndex += 1) {
- Slot = &(Context->Slots[ChildIndex]);
- if (Slot->Resource != NULL) {
- if (Slot->Device == NULL) {
- Status = IoCreateDevice(SdDriver,
- Slot,
- Irp->Device,
- SD_SLOT_DEVICE_ID,
- NULL,
- NULL,
- &(Slot->Device));
- if (!KSUCCESS(Status)) {
- goto BusQueryChildrenEnd;
- }
- }
- Children[ChildCount] = Slot->Device;
- ChildCount += 1;
- }
- }
- if (ChildCount != 0) {
- Status = IoMergeChildArrays(Irp,
- Children,
- ChildCount,
- SD_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto BusQueryChildrenEnd;
- }
- }
- Status = STATUS_SUCCESS;
- BusQueryChildrenEnd:
- return Status;
- }
- KSTATUS
- SdpSlotStartDevice (
- PIRP Irp,
- PSD_SLOT Slot
- )
- /*++
- Routine Description:
- This routine starts an SD slot device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Slot - Supplies a pointer to the slot context.
- Return Value:
- Status code.
- --*/
- {
- SD_INITIALIZATION_BLOCK Parameters;
- KSTATUS Status;
- ASSERT(Slot->Resource != NULL);
- //
- // Initialize the controller base.
- //
- if (Slot->ControllerBase == NULL) {
- Slot->ControllerBase = MmMapPhysicalAddress(Slot->Resource->Allocation,
- Slot->Resource->Length,
- TRUE,
- FALSE,
- TRUE);
- if (Slot->ControllerBase == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto StartDeviceEnd;
- }
- }
- if (Slot->Lock == NULL) {
- Slot->Lock = KeCreateQueuedLock();
- if (Slot->Lock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto StartDeviceEnd;
- }
- }
- //
- // Initialize the standard SD controller.
- //
- if (Slot->Controller == NULL) {
- RtlZeroMemory(&Parameters, sizeof(SD_INITIALIZATION_BLOCK));
- Parameters.ConsumerContext = Slot;
- Parameters.StandardControllerBase = Slot->ControllerBase;
- Parameters.HostCapabilities = SD_MODE_AUTO_CMD12 |
- SD_MODE_4BIT |
- SD_MODE_RESPONSE136_SHIFTED |
- SD_MODE_CMD23;
- Parameters.OsDevice = Slot->Device;
- Slot->Controller = SdCreateController(&Parameters);
- if (Slot->Controller == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto StartDeviceEnd;
- }
- Slot->Controller->InterruptHandle = Slot->Parent->InterruptHandle;
- }
- Status = STATUS_SUCCESS;
- StartDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Slot->Lock != NULL) {
- KeDestroyQueuedLock(Slot->Lock);
- }
- if (Slot->Controller != NULL) {
- SdDestroyController(Slot->Controller);
- Slot->Controller = NULL;
- }
- }
- return Status;
- }
- KSTATUS
- SdpSlotQueryChildren (
- PIRP Irp,
- PSD_SLOT Slot
- )
- /*++
- Routine Description:
- This routine potentially enumerates an SD card in a given slot.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Slot - Supplies a pointer to the SD slot that may contain the card.
- Return Value:
- Status code.
- --*/
- {
- ULONG BlockSize;
- PSTR DeviceId;
- ULONG FlagsMask;
- PSD_DISK NewDisk;
- ULONG OldFlags;
- KSTATUS Status;
- NewDisk = NULL;
- //
- // Collect the current pending status.
- //
- FlagsMask = ~(SD_CONTROLLER_FLAG_INSERTION_PENDING |
- SD_CONTROLLER_FLAG_REMOVAL_PENDING);
- OldFlags = RtlAtomicAnd32(&(Slot->Controller->Flags), FlagsMask);
- //
- // If either removal or insertion is pending, remove the existing disk. In
- // theory, an insertion should always follow a removal, but this does not
- // appear to be the case in practice when cards are quickly removed and
- // inserted.
- //
- FlagsMask = SD_CONTROLLER_FLAG_INSERTION_PENDING |
- SD_CONTROLLER_FLAG_REMOVAL_PENDING;
- if ((OldFlags & FlagsMask) != 0) {
- if (Slot->Disk != NULL) {
- KeAcquireQueuedLock(Slot->Lock);
- RtlAtomicAnd32(&(Slot->Disk->Controller->Flags),
- ~SD_CONTROLLER_FLAG_MEDIA_PRESENT);
- KeReleaseQueuedLock(Slot->Lock);
- Slot->Disk = NULL;
- }
- }
- //
- // Check to see if there's an insertion pending, re-initialize the
- // controller and create a new disk if there is one present.
- //
- if ((OldFlags & SD_CONTROLLER_FLAG_INSERTION_PENDING) != 0) {
- ASSERT(Slot->Disk == NULL);
- KeDelayExecution(FALSE, FALSE, SD_INSERTION_SETTLE_DELAY);
- RtlAtomicAnd32(&(Slot->Controller->Flags),
- ~SD_CONTROLLER_FLAG_MEDIA_CHANGED);
- Status = SdInitializeController(Slot->Controller, TRUE);
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_TIMEOUT) {
- Status = STATUS_SUCCESS;
- }
- goto SlotQueryChildrenEnd;
- }
- //
- // Allocate a new disk context for the slot. The disk was at least
- // present long enough to be enumerated.
- //
- NewDisk = SdpCreateDisk(Slot);
- if (NewDisk == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto SlotQueryChildrenEnd;
- }
- //
- // The slot just got a new disk, set the block size and count. Ignore
- // cases where the card immediately got removed. Act like it was never
- // seen.
- //
- BlockSize = 0;
- Status = SdGetMediaParameters(NewDisk->Controller,
- &(NewDisk->BlockCount),
- &BlockSize);
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_NO_MEDIA) {
- Status = STATUS_SUCCESS;
- }
- goto SlotQueryChildrenEnd;
- }
- ASSERT(POWER_OF_2(BlockSize) != FALSE);
- NewDisk->BlockShift = RtlCountTrailingZeros32(BlockSize);
- //
- // Initialize DMA support, but it's okay if it doesn't succeed. Again,
- // don't bother reporting the disk if it got removed.
- //
- Status = SdStandardInitializeDma(NewDisk->Controller);
- if (KSUCCESS(Status)) {
- NewDisk->Flags |= SD_DISK_FLAG_DMA_SUPPORTED;
- } else if (Status == STATUS_NO_MEDIA) {
- Status = STATUS_SUCCESS;
- goto SlotQueryChildrenEnd;
- }
- //
- // Create the OS device for the disk.
- //
- DeviceId = SD_MMC_DEVICE_ID;
- if (SD_IS_CARD_SD(NewDisk->Controller)) {
- DeviceId = SD_CARD_DEVICE_ID;
- }
- Status = IoCreateDevice(SdDriver,
- NewDisk,
- Irp->Device,
- DeviceId,
- DISK_CLASS_ID,
- NULL,
- &(NewDisk->Device));
- if (!KSUCCESS(Status)) {
- goto SlotQueryChildrenEnd;
- }
- //
- // The disk for the slot is all set to go.
- //
- Slot->Disk = NewDisk;
- NewDisk = NULL;
- }
- //
- // If there's no disk, don't enumerate it.
- //
- if (Slot->Disk == NULL) {
- Status = STATUS_SUCCESS;
- goto SlotQueryChildrenEnd;
- }
- ASSERT((Slot->Disk != NULL) && (Slot->Disk->Device != NULL));
- //
- // Enumerate the one child.
- //
- Status = IoMergeChildArrays(Irp,
- &(Slot->Disk->Device),
- 1,
- SD_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto SlotQueryChildrenEnd;
- }
- SlotQueryChildrenEnd:
- if (NewDisk != NULL) {
- ASSERT(NewDisk->Device == NULL);
- SdpDiskReleaseReference(NewDisk);
- }
- return Status;
- }
- PSD_DISK
- SdpCreateDisk (
- PSD_SLOT Slot
- )
- /*++
- Routine Description:
- This routine creates an SD disk context.
- Arguments:
- Slot - Supplies a pointer to the SD slot to which the disk belongs.
- Return Value:
- Returns a pointer to the new SD disk on success or NULL on failure.
- --*/
- {
- PSD_DISK Disk;
- Disk = MmAllocateNonPagedPool(sizeof(SD_DISK), SD_ALLOCATION_TAG);
- if (Disk == NULL) {
- return NULL;
- }
- RtlZeroMemory(Disk, sizeof(SD_DISK));
- Disk->Type = SdDeviceDisk;
- Disk->Parent = Slot;
- Disk->Controller = Slot->Controller;
- Disk->ControllerLock = Slot->Lock;
- Disk->ReferenceCount = 1;
- return Disk;
- }
- VOID
- SdpDestroyDisk (
- PSD_DISK Disk
- )
- /*++
- Routine Description:
- This routine destroys the given SD disk.
- Arguments:
- Disk - Supplies a pointer to the SD disk to destroy.
- Return Value:
- None.
- --*/
- {
- ASSERT(Disk->DiskInterface.DiskToken == NULL);
- ASSERT(Disk->Irp == NULL);
- MmFreeNonPagedPool(Disk);
- return;
- }
- VOID
- SdpDiskAddReference (
- PSD_DISK Disk
- )
- /*++
- Routine Description:
- This routine adds a reference to SD disk.
- Arguments:
- Disk - Supplies a pointer to the SD disk.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Disk->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- return;
- }
- VOID
- SdpDiskReleaseReference (
- PSD_DISK Disk
- )
- /*++
- Routine Description:
- This routine releases a reference from the SD disk.
- Arguments:
- Disk - Supplies a pointer to the SD disk.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Disk->ReferenceCount), (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- SdpDestroyDisk(Disk);
- }
- return;
- }
- VOID
- SdpDmaCompletion (
- PSD_CONTROLLER Controller,
- PVOID Context,
- UINTN BytesTransferred,
- KSTATUS Status
- )
- /*++
- Routine Description:
- This routine is called by the SD library when a DMA transfer completes.
- This routine is called from a DPC and, as a result, can get called back
- at dispatch level.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the library when the DMA
- request was issued.
- BytesTransferred - Supplies the number of bytes transferred in the request.
- Status - Supplies the status code representing the completion of the I/O.
- Return Value:
- None.
- --*/
- {
- UINTN BlockCount;
- ULONGLONG BlockOffset;
- PSD_DISK Disk;
- ULONGLONG IoOffset;
- UINTN IoSize;
- PIRP Irp;
- BOOL Write;
- Disk = Context;
- Irp = Disk->Irp;
- ASSERT(Irp != NULL);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("SD Failed: %x %I64x %x %x\n",
- Status,
- Irp->U.ReadWrite.IoOffset,
- Irp->U.ReadWrite.IoSizeInBytes,
- Irp->MinorCode);
- IoCompleteIrp(SdDriver, Irp, Status);
- return;
- }
- Irp->U.ReadWrite.IoBytesCompleted += BytesTransferred;
- Irp->U.ReadWrite.NewIoOffset += BytesTransferred;
- //
- // If this transfer's over, unlock and complete the IRP.
- //
- if (Irp->U.ReadWrite.IoBytesCompleted ==
- Irp->U.ReadWrite.IoSizeInBytes) {
- IoCompleteIrp(SdDriver, Irp, Status);
- return;
- }
- IoOffset = Irp->U.ReadWrite.NewIoOffset;
- ASSERT(IoOffset ==
- (Irp->U.ReadWrite.IoOffset + Irp->U.ReadWrite.IoBytesCompleted));
- BlockOffset = IoOffset >> Disk->BlockShift;
- IoSize = Irp->U.ReadWrite.IoSizeInBytes - Irp->U.ReadWrite.IoBytesCompleted;
- BlockCount = IoSize >> Disk->BlockShift;
- Write = FALSE;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- Write = TRUE;
- }
- SdStandardBlockIoDma(Disk->Controller,
- BlockOffset,
- BlockCount,
- Irp->U.ReadWrite.IoBuffer,
- Irp->U.ReadWrite.IoBytesCompleted,
- Write,
- SdpDmaCompletion,
- Disk);
- return;
- }
- KSTATUS
- SdpDiskBlockIoReset (
- PVOID DiskToken
- )
- /*++
- Routine Description:
- This routine must be called immediately before using the block read and
- write routines in order to allow the disk to reset any I/O channels in
- preparation for imminent block I/O. This routine is called at high run
- level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- Return Value:
- Status code.
- --*/
- {
- PSD_DISK Disk;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Disk = (PSD_DISK)DiskToken;
- //
- // Put the SD controller into critical execution mode.
- //
- SdSetCriticalMode(Disk->Controller, TRUE);
- //
- // Abort any current transaction that might have been left incomplete
- // when the crash occurred.
- //
- Status = SdAbortTransaction(Disk->Controller, FALSE);
- return Status;
- }
- KSTATUS
- SdpDiskBlockIoRead (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- )
- /*++
- Routine Description:
- This routine reads the block contents from the disk into the given I/O
- buffer using polled I/O. It does so without acquiring any locks or
- allocating any resources, as this routine is used for crash dump support
- when the system is in a very fragile state. This routine must be called at
- high level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- IoBuffer - Supplies a pointer to the I/O buffer where the data will be read.
- BlockAddress - Supplies the block index to read (for physical disk, this is
- the LBA).
- BlockCount - Supplies the number of blocks to read.
- BlocksCompleted - Supplies a pointer that receives the total number of
- blocks read.
- Return Value:
- Status code.
- --*/
- {
- PSD_DISK Disk;
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Disk = (PSD_DISK)DiskToken;
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress << Disk->BlockShift;
- IrpReadWrite.IoSizeInBytes = BlockCount << Disk->BlockShift;
- //
- // As this read routine is meant for critical code paths (crash dump),
- // indicate that the channel should not be locked when performing the I/O.
- // It may be that some other thread holds the lock, which would cause a
- // dead lock as all other processors and threads are likely frozen.
- //
- Status = SdpPerformIoPolled(&IrpReadWrite, Disk, FALSE, FALSE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted >> Disk->BlockShift;
- return Status;
- }
- KSTATUS
- SdpDiskBlockIoWrite (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- )
- /*++
- Routine Description:
- This routine writes the contents of the given I/O buffer to the disk using
- polled I/O. It does so without acquiring any locks or allocating any
- resources, as this routine is used for crash dump support when the system
- is in a very fragile state. This routine must be called at high level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- IoBuffer - Supplies a pointer to the I/O buffer containing the data to
- write.
- BlockAddress - Supplies the block index to write to (for physical disk,
- this is the LBA).
- BlockCount - Supplies the number of blocks to write.
- BlocksCompleted - Supplies a pointer that receives the total number of
- blocks written.
- Return Value:
- Status code.
- --*/
- {
- PSD_DISK Disk;
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Disk = (PSD_DISK)DiskToken;
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress << Disk->BlockShift;
- IrpReadWrite.IoSizeInBytes = BlockCount << Disk->BlockShift;
- //
- // As this write routine is meant for critical code paths (crash dump),
- // indicate that the channel should not be locked when performing the I/O.
- // It may be that some other thread holds the lock, which would cause a
- // dead lock as all other processors and threads are likely frozen.
- //
- Status = SdpPerformIoPolled(&IrpReadWrite, Disk, TRUE, FALSE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted >> Disk->BlockShift;
- return Status;
- }
- KSTATUS
- SdpPerformIoPolled (
- PIRP_READ_WRITE IrpReadWrite,
- PSD_DISK Disk,
- BOOL Write,
- BOOL LockRequired
- )
- /*++
- Routine Description:
- This routine performs polled I/O data transfers.
- Arguments:
- IrpReadWrite - Supplies a pointer to an IRP read/write context.
- Disk - Supplies a pointer to the SD disk device.
- Write - Supplies a boolean indicating if this is a read operation (TRUE) or
- a write operation (FALSE).
- LockRequired - Supplies a boolean indicating if the controller lock needs
- to be acquired (TRUE) or it does not (FALSE).
- Return Value:
- None.
- --*/
- {
- UINTN BlockCount;
- ULONGLONG BlockOffset;
- UINTN BytesRemaining;
- UINTN BytesThisRound;
- KSTATUS CompletionStatus;
- PSD_CONTROLLER Controller;
- PIO_BUFFER_FRAGMENT Fragment;
- UINTN FragmentIndex;
- UINTN FragmentOffset;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- ULONG IrpReadWriteFlags;
- BOOL LockHeld;
- BOOL ReadWriteIrpPrepared;
- KSTATUS Status;
- PVOID VirtualAddress;
- IrpReadWrite->IoBytesCompleted = 0;
- LockHeld = FALSE;
- ReadWriteIrpPrepared = FALSE;
- ASSERT(IrpReadWrite->IoBuffer != NULL);
- ASSERT((Disk->BlockCount != 0) && (Disk->BlockShift != 0));
- //
- // Validate the supplied I/O buffer is aligned and big enough.
- //
- IrpReadWriteFlags = IRP_READ_WRITE_FLAG_POLLED;
- if (Write != FALSE) {
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- Status = IoPrepareReadWriteIrp(IrpReadWrite,
- 1 << Disk->BlockShift,
- 0,
- MAX_ULONGLONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto PerformIoPolledEnd;
- }
- ReadWriteIrpPrepared = TRUE;
- //
- // Make sure the I/O buffer is mapped before use. SD depends on the buffer
- // being mapped.
- //
- IoBuffer = IrpReadWrite->IoBuffer;
- Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE);
- if (!KSUCCESS(Status)) {
- goto PerformIoPolledEnd;
- }
- //
- // Find the starting fragment based on the current offset.
- //
- IoBufferOffset = MmGetIoBufferCurrentOffset(IoBuffer);
- FragmentIndex = 0;
- FragmentOffset = 0;
- while (IoBufferOffset != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = &(IoBuffer->Fragment[FragmentIndex]);
- if (IoBufferOffset < Fragment->Size) {
- FragmentOffset = IoBufferOffset;
- break;
- }
- IoBufferOffset -= Fragment->Size;
- FragmentIndex += 1;
- }
- if (LockRequired != FALSE) {
- KeAcquireQueuedLock(Disk->ControllerLock);
- LockHeld = TRUE;
- }
- Controller = Disk->Controller;
- if ((Controller->Flags & SD_CONTROLLER_FLAG_MEDIA_CHANGED) != 0) {
- Status = STATUS_MEDIA_CHANGED;
- goto PerformIoPolledEnd;
- } else if ((Controller->Flags & SD_CONTROLLER_FLAG_MEDIA_PRESENT) == 0) {
- Status = STATUS_NO_MEDIA;
- goto PerformIoPolledEnd;
- }
- //
- // Loop reading in or writing out each fragment in the I/O buffer.
- //
- BytesRemaining = IrpReadWrite->IoSizeInBytes;
- ASSERT(IS_ALIGNED(BytesRemaining, 1 << Disk->BlockShift) != FALSE);
- ASSERT(IS_ALIGNED(IrpReadWrite->IoOffset, 1 << Disk->BlockShift) != FALSE);
- BlockOffset = IrpReadWrite->IoOffset >> Disk->BlockShift;
- while (BytesRemaining != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = (PIO_BUFFER_FRAGMENT)&(IoBuffer->Fragment[FragmentIndex]);
- VirtualAddress = Fragment->VirtualAddress + FragmentOffset;
- BytesThisRound = Fragment->Size - FragmentOffset;
- if (BytesRemaining < BytesThisRound) {
- BytesThisRound = BytesRemaining;
- }
- ASSERT(IS_ALIGNED(BytesThisRound, (1 << Disk->BlockShift)) != FALSE);
- BlockCount = BytesThisRound >> Disk->BlockShift;
- //
- // Make sure the system isn't trying to do I/O off the end of the disk.
- //
- ASSERT(BlockOffset < Disk->BlockCount);
- ASSERT(BlockCount >= 1);
- Status = SdBlockIoPolled(Disk->Controller,
- BlockOffset,
- BlockCount,
- VirtualAddress,
- Write);
- if (!KSUCCESS(Status)) {
- goto PerformIoPolledEnd;
- }
- BlockOffset += BlockCount;
- BytesRemaining -= BytesThisRound;
- IrpReadWrite->IoBytesCompleted += BytesThisRound;
- FragmentOffset += BytesThisRound;
- if (FragmentOffset >= Fragment->Size) {
- FragmentIndex += 1;
- FragmentOffset = 0;
- }
- }
- Status = STATUS_SUCCESS;
- PerformIoPolledEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Disk->ControllerLock);
- }
- if (ReadWriteIrpPrepared != FALSE) {
- CompletionStatus = IoCompleteReadWriteIrp(IrpReadWrite,
- IrpReadWriteFlags);
- if (!KSUCCESS(CompletionStatus) && KSUCCESS(Status)) {
- Status = CompletionStatus;
- }
- }
- IrpReadWrite->NewIoOffset = IrpReadWrite->IoOffset +
- IrpReadWrite->IoBytesCompleted;
- return Status;
- }
|