Writing to I/O Memory...

Hello,

I seem to have a strange behaviour when writing to an I/O memory mapped adress. My problem is that I can’t seem to write Data to the PCI card using Memory mapped address.

On the DEVICE_START PnP message, I look at the Translated Ressource PCM_DESCRIPTOR to identify if it’s a Port or Memory. If it is a Memory, I will call MmMapIoSpace and keep the returned adress. If it’s a Port, I simply keep the Translated address.

I can read/write when accessing I/O ports but when accessing the memory, I can only read. Flags on the MEM give me 0 (so READ and WRITE access). From my limited knowledge, it seems the WRITE_REGISTER is waiting for some sort of trigger to send the data to the PCI card. The I/O ports work instantly.

Do any of you have an idea about this problem?
WinDDK build 6000

Here is the code (yes I know C++…):


NTSTATUS CIoRange::Initialize( PCM_RESOURCE_LIST ResTransList,
PCM_RESOURCE_LIST ResRawList,
ULONG MemoryBar)
{
PCM_FULL_RESOURCE_DESCRIPTOR pRawFullDescriptor, pTranslatedFullDescriptor;
PCM_PARTIAL_RESOURCE_LIST raw, translated;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
PAGED_CODE();
if ((NULL != ResTransList) && (NULL != ResRawList))
{

pTranslatedFullDescriptor = ResTransList->List;
pRawFullDescriptor = ResRawList->List;
raw = &pRawFullDescriptor->PartialResourceList;
translated = &pTranslatedFullDescriptor->PartialResourceList;

if(MemoryBar < translated->Count)
{
ERROR((“Getting memory BAR %d\n”,MemoryBar));
pPartialDescriptor = &translated->PartialDescriptors[MemoryBar];

switch (pPartialDescriptor->Type)
{
default:
case CmResourceTypeInterrupt:
case CmResourceTypeDma:
break;
case CmResourceTypePort:
ERROR((“I/O\n”));
if (m_BaseAddress == NULL)
{
m_Type = IO;
m_PhysicalBaseAddress = pPartialDescriptor->u.Memory.Start;
m_Size = pPartialDescriptor->u.Memory.Length;
m_BaseAddress = &m_PhysicalBaseAddress.LowPart;

if(m_BaseAddress == NULL)
{
ERROR((“Could not map IO \n”));
return STATUS_NO_MEMORY;
}
ERROR((“IO_BAR Physical Base is: 0x%03X \n”, m_PhysicalBaseAddress));
ERROR((“IO_Length of mapping is 0x%03X \n”, m_Size));
ERROR((“IO_BAR Virtual Base is: 0x%03X \n”, m_BaseAddress));
} // End if NULL
break;
case CmResourceTypeMemory:
ERROR((“Mem\n”));
if (m_BaseAddress == NULL)
{
m_Type = MEMORY;
m_PhysicalBaseAddress = pPartialDescriptor->u.Memory.Start;
m_Size = pPartialDescriptor->u.Memory.Length;
m_BaseAddress = (PVOID) MmMapIoSpace (m_PhysicalBaseAddress, m_Size,MmNonCached);

if(m_BaseAddress == NULL)
{
ERROR((“Could not map memory \n”));
return STATUS_NO_MEMORY;
}
ERROR((“MEM_BAR Physical Base is: 0x%03X \n”, m_PhysicalBaseAddress));
ERROR((“MEM_Length of mapping is 0x%03X \n”, m_Size));
ERROR((“MEM_BAR Virtual Base is: 0x%03X \n”, m_BaseAddress));
ERROR((“MEM_BAR Flags is: 0x%03X \n”, pPartialDescriptor->Flags));
} // End if NULL
break;
} // End Switch
} // End if memory bar
} // End Res != NULL
return STATUS_SUCCESS;
}

To access memory I use the following functions:

ULONG CIoRange::ReadDWord(ULONG Offset)
{
if(Offset < m_Size && m_BaseAddress != NULL)
{
PULONG RealOffset;
ULONG ulValue;
if(m_Type == MEMORY)
{
RealOffset = (PULONG) ((PUCHAR) (m_BaseAddress) + (UCHAR) Offset);
ulValue = READ_REGISTER_ULONG(RealOffset);
ERROR((“Read DWord Reg @ 0x%X => 0x%X”,RealOffset,ulValue));
}
else
{
RealOffset = (PULONG) ((PUCHAR) (m_PhysicalBaseAddress.LowPart) + (UCHAR) Offset);
ulValue = READ_PORT_ULONG(RealOffset);
ERROR((“Read DWord @ 0x%X => 0x%X”,RealOffset,ulValue));
}
return ulValue;
}
else
return 0xFFFFFFFF;
}

AND

void CIoRange::WriteBufferDWord(ULONG Offset, ULONG* ptrBuffer, ULONG Size)
{
if(Offset < m_Size && m_BaseAddress != NULL)
{
PULONG RealOffset;
if(m_Type == MEMORY)
{
RealOffset = (PULONG) ((PUCHAR) (m_BaseAddress) + (UCHAR) Offset);
// This function should put DWORD by DWORD to the RealOffset
WRITE_REGISTER_BUFFER_ULONG(RealOffset,ptrBuffer,Size);
ERROR((“Write Buffer DWord Reg @ 0x%X => 0x%X - %d” ,RealOffset,ptrBuffer[0],Size));
}
else
{
RealOffset = (PULONG) ((PUCHAR) (m_PhysicalBaseAddress.LowPart) + (UCHAR) Offset);
WRITE_PORT_BUFFER_ULONG(RealOffset,ptrBuffer,Size);
}
}
}


Send a smile, make someone laugh, have some fun! Start now!
http://www.freemessengeremoticons.ca/?icid=EMENCA122

In addittion to calling MmMapIoSpace, you must allocate a MDL to describe the memory range and building the allocated MDL. Something like the following code:

iHardwareBaseAddress = MmMapIoSpace(…)

if (iHardwareBaseAddress)
{
pMdl = IoAllocateMdl(iHardwareBaseAddress, iMemoryRangeLength, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(pMdl);
}

Now you can use iHardwareBaseAddress as the starting address of your device memory maped IO address space.

Hope this helps,

Eugenio Barahona Marciel

Hello,
Thank you for the prompt reply. I made the changes. I also realized that in my Memory Access functions, I was converting my ULONG Offset to a UCHAR. I could only access Address below 256. I removed the UCHAR and everything started working (my Fifo was at 0x20000)

I tought MmMapIoSpace created a buffer in NonPagedMemory and you didn’t need to allocate a MDL if you we’re not doing DMA.

Date: Thu, 22 Nov 2007 11:07:45 -0500> From: ebarahona@ya.com> To: xxxxx@lists.osr.com> Subject: RE:[ntdev] Writing to I/O Memory…> > In addittion to calling MmMapIoSpace, you must allocate a MDL to describe the memory range and building the allocated MDL. Something like the following code:> > iHardwareBaseAddress = MmMapIoSpace(…)> > if (iHardwareBaseAddress)> {> pMdl = IoAllocateMdl(iHardwareBaseAddress, iMemoryRangeLength, FALSE, FALSE, NULL);> MmBuildMdlForNonPagedPool(pMdl);> }> > Now you can use iHardwareBaseAddress as the starting address of your device memory maped IO address space.> > Hope this helps,> > Eugenio Barahona Marciel > > —> NTDEV is sponsored by OSR> > For our schedule of WDF, WDM, debugging and other seminars visit: > http://www.osr.com/seminars\> > To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


Have fun while connecting on Messenger! Click here to learn more.
http://entertainment.sympatico.msn.ca/WindowsLiveMessenger

You do not need to allocate an MDL for the region mapped through
MmMapIoSpace. There is some other problem.

On Nov 22, 2007 11:45 AM, Frederick Guillemot
wrote:

> Hello,
>
> Thank you for the prompt reply. I made the changes. I also realized that
> in my Memory Access functions, I was converting my ULONG Offset to a UCHAR.
> I could only access Address below 256. I removed the UCHAR and everything
> started working (my Fifo was at 0x20000)
>
> I tought MmMapIoSpace created a buffer in NonPagedMemory and you didn’t
> need to allocate a MDL if you we’re not doing DMA.
>
> > Date: Thu, 22 Nov 2007 11:07:45 -0500
> > From: ebarahona@ya.com
> > To: xxxxx@lists.osr.com
> > Subject: RE:[ntdev] Writing to I/O Memory…
>
> >
> > In addittion to calling MmMapIoSpace, you must allocate a MDL to
> describe the memory range and building the allocated MDL. Something like the
> following code:
> >
> > iHardwareBaseAddress = MmMapIoSpace(…)
> >
> > if (iHardwareBaseAddress)
> > {
> > pMdl = IoAllocateMdl(iHardwareBaseAddress, iMemoryRangeLength, FALSE,
> FALSE, NULL);
> > MmBuildMdlForNonPagedPool(pMdl);
> > }
> >
> > Now you can use iHardwareBaseAddress as the starting address of your
> device memory maped IO address space.
> >
> > Hope this helps,
> >
> > Eugenio Barahona Marciel
> >
> > —
> > NTDEV is sponsored by OSR
> >
> > For our schedule of WDF, WDM, debugging and other seminars visit:
> > http://www.osr.com/seminars
> >
> > To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>
> ------------------------------
> Have fun while connecting on Messenger! Click here to learn more.http:
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy</http:>

Absolutely no need in this.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> In addittion to calling MmMapIoSpace, you must allocate a MDL to describe the
memory range and building the allocated MDL. Something like the following code:
>
> iHardwareBaseAddress = MmMapIoSpace(…)
>
> if (iHardwareBaseAddress)
> {
> pMdl = IoAllocateMdl(iHardwareBaseAddress, iMemoryRangeLength, FALSE,
FALSE, NULL);
> MmBuildMdlForNonPagedPool(pMdl);
> }
>
> Now you can use iHardwareBaseAddress as the starting address of your device
memory maped IO address space.
>
> Hope this helps,
>
> Eugenio Barahona Marciel
>

>I tought MmMapIoSpace created a buffer in NonPagedMemory

No. MmMapIoSpace allocates and sets the PTEs in system PTE range, it does not
allocate memory.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Frederick Guillemot wrote:


To access memory I use the following functions:

ULONG CIoRange::ReadDWord(ULONG Offset)
{
if(Offset < m_Size && m_BaseAddress != NULL)
{
PULONG RealOffset;
ULONG ulValue;
if(m_Type == MEMORY)
{
RealOffset = (PULONG) ((PUCHAR) (m_BaseAddress) + (UCHAR) Offset);
ulValue = READ_REGISTER_ULONG(RealOffset);
ERROR((“Read DWord Reg @ 0x%X => 0x%X”,RealOffset,ulValue));
}

Note that this reads exactly one dword at m_BaseAddress+Offset.

void CIoRange::WriteBufferDWord(ULONG Offset, ULONG* ptrBuffer, ULONG
Size)
{
if(Offset < m_Size && m_BaseAddress != NULL)
{
PULONG RealOffset;
if(m_Type == MEMORY)
{
RealOffset = (PULONG) ((PUCHAR) (m_BaseAddress) + (UCHAR) Offset);
// This function should put DWORD by DWORD to the RealOffset
WRITE_REGISTER_BUFFER_ULONG(RealOffset,ptrBuffer,Size);
ERROR((“Write Buffer DWord Reg @ 0x%X => 0x%X - %d”
,RealOffset,ptrBuffer[0],Size));
}

Remember that this uses the “rep movsd” instruction. The reason that’s
important is that “rep movsd” increments BOTH addresses. This does not
copy dwords repeatedly to m_BaseAddress+Offset. Instead, this assumes
that your device implements a RANGE of addresses. That it, it will copy
one dword to m_BaseAddress+Offset, the next to m_BaseAddress+Offset+4,
the next to m_BaseAddress+Offset+8, the next to m_BaseAddress+Offset+12,
etc.

If your device really has only one register at address “Offset”, then
you cannot use the WRITE_*BUFFER* APIs. You need to use a loop:

Size /= 4;
for(
RealOffset = (PULONG)((PUCHAR)m_BaseAddress + Offset);
Size;
Size–, ptrBuffer++
)
WRITE_REGISTER_ULONG( RealOffset, *ptrBuffer );


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.