You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
685 lines
17 KiB
685 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1991-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pccard.c
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) 1-Jan-01
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
--*/
|
|
#include "pch.h"
|
|
|
|
|
|
NTSTATUS
|
|
PcCardReadWrite(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN ULONG startOffset,
|
|
IN PVOID UserBuffer,
|
|
IN ULONG lengthToCopy,
|
|
IN BOOLEAN writeOperation
|
|
);
|
|
|
|
NTSTATUS
|
|
PcCardRead(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PcCardWrite(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PcCardInitialize(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PcCardDeleteDevice(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PcCardGetDiskParameters(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
PcCardIsWriteProtected(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
ULONG
|
|
PcCardGetCapacityFromCIS(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
ULONG
|
|
PcCardGetCapacityFromBootSector(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
ULONG
|
|
PcCardProbeForCapacity(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,PcCardRead)
|
|
#pragma alloc_text(PAGE,PcCardWrite)
|
|
#pragma alloc_text(PAGE,PcCardInitialize)
|
|
#pragma alloc_text(PAGE,PcCardDeleteDevice)
|
|
#pragma alloc_text(PAGE,PcCardGetDiskParameters)
|
|
#pragma alloc_text(PAGE,PcCardIsWriteProtected)
|
|
#pragma alloc_text(PAGE,PcCardGetCapacityFromCIS)
|
|
#pragma alloc_text(PAGE,PcCardGetCapacityFromBootSector)
|
|
#pragma alloc_text(PAGE,PcCardProbeForCapacity)
|
|
#endif
|
|
|
|
|
|
SFFDISK_FUNCTION_BLOCK PcCardSupportFns = {
|
|
PcCardInitialize,
|
|
PcCardDeleteDevice,
|
|
PcCardGetDiskParameters,
|
|
PcCardIsWriteProtected,
|
|
PcCardRead,
|
|
PcCardWrite
|
|
};
|
|
|
|
|
|
//
|
|
// macros for ReadWriteMemory
|
|
//
|
|
|
|
#define SFFDISK_READ(Extension, Offset, Buffer, Size) \
|
|
PcCardReadWrite(Extension, Offset, Buffer, Size, FALSE)
|
|
|
|
#define SFFDISK_WRITE(Extension, Offset, Buffer, Size) \
|
|
PcCardReadWrite(Extension, Offset, Buffer, Size, TRUE)
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardInitialize(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
KEVENT event;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
//
|
|
// Get pcmcia interfaces
|
|
//
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, sffdiskExtension->UnderlyingPDO,
|
|
NULL, 0, 0, &event, &statusBlock);
|
|
|
|
if (!irp) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
irpSp->Parameters.QueryInterface.InterfaceType= &GUID_PCMCIA_INTERFACE_STANDARD;
|
|
irpSp->Parameters.QueryInterface.Size = sizeof(PCMCIA_INTERFACE_STANDARD);
|
|
irpSp->Parameters.QueryInterface.Version = 1;
|
|
irpSp->Parameters.QueryInterface.Interface = (PINTERFACE) &sffdiskExtension->PcmciaInterface;
|
|
|
|
status = IoCallDriver(sffdiskExtension->UnderlyingPDO, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = statusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, sffdiskExtension->UnderlyingPDO,
|
|
NULL, 0, 0, &event, &statusBlock);
|
|
|
|
if (!irp) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
// irpSp->Parameters.QueryInterface.InterfaceType= &GUID_PCMCIA_BUS_INTERFACE_STANDARD;
|
|
irpSp->Parameters.QueryInterface.InterfaceType= &GUID_BUS_INTERFACE_STANDARD;
|
|
// irpSp->Parameters.QueryInterface.Size = sizeof(PCMCIA_BUS_INTERFACE_STANDARD);
|
|
irpSp->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
|
|
irpSp->Parameters.QueryInterface.Version = 1;
|
|
irpSp->Parameters.QueryInterface.Interface = (PINTERFACE) &sffdiskExtension->PcmciaBusInterface;
|
|
|
|
status = IoCallDriver(sffdiskExtension->UnderlyingPDO, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = statusBlock.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardDeleteDevice(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
PcCardIsWriteProtected(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return((sffdiskExtension->PcmciaInterface.IsWriteProtected)(sffdiskExtension->UnderlyingPDO));
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardRead(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to read/write data to/from the memory card.
|
|
It breaks the request into pieces based on the size of our memory
|
|
window.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device
|
|
that I/O is to be done on.
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the packet was successfully read or written; the
|
|
appropriate error is propogated otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
status = SFFDISK_READ(sffdiskExtension,
|
|
irpSp->Parameters.Read.ByteOffset.LowPart,
|
|
MmGetSystemAddressForMdl(Irp->MdlAddress),
|
|
irpSp->Parameters.Read.Length);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardWrite(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to read/write data to/from the memory card.
|
|
It breaks the request into pieces based on the size of our memory
|
|
window.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device
|
|
that I/O is to be done on.
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the packet was successfully read or written; the
|
|
appropriate error is propogated otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
status = SFFDISK_WRITE(sffdiskExtension,
|
|
irpSp->Parameters.Write.ByteOffset.LowPart,
|
|
MmGetSystemAddressForMdl(Irp->MdlAddress),
|
|
irpSp->Parameters.Write.Length);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardReadWrite(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension,
|
|
IN ULONG startOffset,
|
|
IN PVOID UserBuffer,
|
|
IN ULONG lengthToCopy,
|
|
IN BOOLEAN writeOperation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to read/write data to/from the memory card.
|
|
It breaks the request into pieces based on the size of our memory
|
|
window.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device
|
|
that I/O is to be done on.
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the packet was successfully read or written; the
|
|
appropriate error is propogated otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PCHAR userBuffer = UserBuffer;
|
|
ULONG windowOffset;
|
|
ULONG singleCopyLength;
|
|
BOOLEAN bSuccess;
|
|
ULONGLONG CardBase;
|
|
|
|
if (writeOperation && PcCardIsWriteProtected(sffdiskExtension)) {
|
|
return STATUS_MEDIA_WRITE_PROTECTED;
|
|
}
|
|
|
|
// pcmcia controller is 4k page granular
|
|
windowOffset = startOffset % 4096;
|
|
CardBase = startOffset - windowOffset;
|
|
|
|
while(lengthToCopy) {
|
|
|
|
bSuccess = (sffdiskExtension->PcmciaInterface.ModifyMemoryWindow) (
|
|
sffdiskExtension->UnderlyingPDO,
|
|
sffdiskExtension->HostBase,
|
|
CardBase,
|
|
TRUE,
|
|
sffdiskExtension->MemoryWindowSize,
|
|
0, 0, FALSE);
|
|
|
|
if (!bSuccess) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
break;
|
|
}
|
|
|
|
singleCopyLength = (lengthToCopy <= (sffdiskExtension->MemoryWindowSize - windowOffset)) ?
|
|
lengthToCopy :
|
|
(sffdiskExtension->MemoryWindowSize - windowOffset);
|
|
|
|
|
|
SffDiskDump(SFFDISKRW,("SffDisk: COPY %.8x (devbase %.8x) %s buffer %.8x, len %x\n",
|
|
sffdiskExtension->MemoryWindowBase+windowOffset,
|
|
(ULONG)(CardBase+windowOffset),
|
|
(writeOperation ? "<=" : "=>"),
|
|
userBuffer,
|
|
singleCopyLength));
|
|
|
|
if (writeOperation) {
|
|
|
|
RtlCopyMemory(sffdiskExtension->MemoryWindowBase+windowOffset,
|
|
userBuffer,
|
|
singleCopyLength);
|
|
|
|
} else {
|
|
|
|
RtlCopyMemory(userBuffer,
|
|
sffdiskExtension->MemoryWindowBase+windowOffset,
|
|
singleCopyLength);
|
|
|
|
}
|
|
|
|
lengthToCopy -= singleCopyLength;
|
|
userBuffer += singleCopyLength;
|
|
|
|
CardBase += sffdiskExtension->MemoryWindowSize;
|
|
windowOffset = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcCardGetDiskParameters(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
device extension for the card
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG capacity;
|
|
|
|
capacity = PcCardGetCapacityFromCIS(sffdiskExtension);
|
|
|
|
if (!capacity) {
|
|
capacity = PcCardGetCapacityFromBootSector(sffdiskExtension);
|
|
|
|
if (!capacity) {
|
|
capacity = PcCardProbeForCapacity(sffdiskExtension);
|
|
}
|
|
}
|
|
|
|
|
|
if (!capacity) {
|
|
return STATUS_UNRECOGNIZED_MEDIA;
|
|
}
|
|
|
|
sffdiskExtension->ByteCapacity = capacity;
|
|
sffdiskExtension->Cylinders = sffdiskExtension->ByteCapacity / (8 * 2 * 512);
|
|
sffdiskExtension->TracksPerCylinder = 2;
|
|
sffdiskExtension->SectorsPerTrack = 8;
|
|
sffdiskExtension->BytesPerSector = 512;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
PcCardGetCapacityFromBootSector(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
device extension for the card
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
BOOT_SECTOR_INFO BootSector;
|
|
ULONG capacity = 0;
|
|
|
|
status = SFFDISK_READ(sffdiskExtension, 0, &BootSector, sizeof(BootSector));
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
#define BYTES_PER_SECTOR 512
|
|
//
|
|
// see if this really looks like a boot sector
|
|
// These are the same tests done in the win9x sram support
|
|
//
|
|
if ((BootSector.JumpByte == 0xE9 || BootSector.JumpByte == 0xEB) &&
|
|
|
|
BootSector.BytesPerSector == BYTES_PER_SECTOR &&
|
|
|
|
BootSector.SectorsPerCluster != 0 &&
|
|
|
|
BootSector.ReservedSectors == 1 &&
|
|
|
|
(BootSector.NumberOfFATs == 1 || BootSector.NumberOfFATs == 2) &&
|
|
|
|
BootSector.RootEntries != 0 && (BootSector.RootEntries & 15) == 0 &&
|
|
|
|
(BootSector.TotalSectors != 0 || BootSector.BigTotalSectors != 0) &&
|
|
|
|
BootSector.SectorsPerFAT != 0 &&
|
|
|
|
BootSector.SectorsPerTrack != 0 &&
|
|
|
|
BootSector.Heads != 0 &&
|
|
|
|
BootSector.MediaDescriptor >= 0xF0) {
|
|
|
|
//
|
|
// Finally it appears valid, return total size of region.
|
|
//
|
|
capacity = BootSector.TotalSectors * BYTES_PER_SECTOR;
|
|
|
|
}
|
|
}
|
|
return capacity;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
PcCardGetCapacityFromCIS(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a quick and dirty routine to read the tuples of the card, if they
|
|
exist, to get the capacity.
|
|
|
|
Arguments:
|
|
|
|
device extension for the card
|
|
|
|
Return Value:
|
|
|
|
The # of bytes of memory on the device
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR tupleData[16];
|
|
ULONG bytesRead;
|
|
ULONG dataCount;
|
|
ULONG unitSize;
|
|
ULONG unitCount;
|
|
ULONG i;
|
|
|
|
//
|
|
// get device capacity
|
|
// all this stuff should really be in the bus driver
|
|
//
|
|
|
|
bytesRead = (sffdiskExtension->PcmciaBusInterface.GetBusData)(sffdiskExtension->UnderlyingPDO,
|
|
PCCARD_ATTRIBUTE_MEMORY,
|
|
tupleData,
|
|
0,
|
|
16);
|
|
|
|
if ((bytesRead != 16) || (tupleData[0] != 1)){
|
|
return 0;
|
|
}
|
|
|
|
dataCount = (ULONG)tupleData[1];
|
|
|
|
if ((dataCount < 2) || (dataCount>14)){
|
|
return 0;
|
|
}
|
|
|
|
i = 3;
|
|
if ((tupleData[2] & 7) == 7) {
|
|
while(tupleData[i] & 0x80) {
|
|
if ((i-2) > dataCount) {
|
|
return 0;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if ((tupleData[i]&7) == 7) {
|
|
return 0;
|
|
}
|
|
unitSize = 512 << ((tupleData[i]&7)*2);
|
|
unitCount = (tupleData[i]>>3)+1;
|
|
|
|
return(unitCount * unitSize);
|
|
}
|
|
|
|
|
|
ULONG
|
|
PcCardProbeForCapacity(
|
|
IN PSFFDISK_EXTENSION sffdiskExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Since we were unable to determine the card capacity through other means,
|
|
here we actually write stuff out on the card to check how big it is.
|
|
This algorithm for testing the card capacity was ported from win9x.
|
|
|
|
Arguments:
|
|
|
|
device extension for the card
|
|
|
|
Return Value:
|
|
|
|
byte capacity of device
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG capacity = 0;
|
|
USHORT origValue, ChkValue, StartValue;
|
|
USHORT mcSig = 'Mc';
|
|
USHORT zeroes = 0;
|
|
#define SRAM_BLK_SIZE (16*1024)
|
|
ULONG CardOff = SRAM_BLK_SIZE;
|
|
USHORT CurValue;
|
|
|
|
if ((sffdiskExtension->PcmciaInterface.IsWriteProtected)(sffdiskExtension->UnderlyingPDO)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//
|
|
if (!NT_SUCCESS(SFFDISK_READ (sffdiskExtension, 0, &origValue, sizeof(origValue))) ||
|
|
!NT_SUCCESS(SFFDISK_WRITE(sffdiskExtension, 0, &mcSig, sizeof(mcSig))) ||
|
|
!NT_SUCCESS(SFFDISK_READ (sffdiskExtension, 0, &ChkValue, sizeof(ChkValue)))) {
|
|
return 0;
|
|
}
|
|
|
|
if (ChkValue != mcSig) {
|
|
//
|
|
// not sram
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
for (;;) {
|
|
if (!NT_SUCCESS(SFFDISK_READ (sffdiskExtension, CardOff, &CurValue, sizeof(CurValue))) ||
|
|
!NT_SUCCESS(SFFDISK_WRITE(sffdiskExtension, CardOff, &zeroes, sizeof(zeroes))) ||
|
|
!NT_SUCCESS(SFFDISK_READ (sffdiskExtension, CardOff, &ChkValue, sizeof(ChkValue))) ||
|
|
!NT_SUCCESS(SFFDISK_READ (sffdiskExtension, 0, &StartValue, sizeof(StartValue)))) {
|
|
break;
|
|
}
|
|
|
|
// We stop when either we can't write 0 anymore or the 0
|
|
// has wrapped over the 0x9090 at card offset 0
|
|
|
|
if (ChkValue != zeroes || StartValue == zeroes) {
|
|
capacity = CardOff;
|
|
break;
|
|
}
|
|
|
|
// Restore the saved value from the start of the block.
|
|
|
|
if (!NT_SUCCESS(SFFDISK_WRITE(sffdiskExtension, CardOff, &CurValue, sizeof(CurValue)))) {
|
|
break;
|
|
}
|
|
CardOff += SRAM_BLK_SIZE; // increment to the next block
|
|
}
|
|
|
|
//
|
|
// try to restore original value
|
|
//
|
|
SFFDISK_WRITE(sffdiskExtension, 0, &origValue, sizeof(origValue));
|
|
|
|
return capacity;
|
|
}
|
|
|