Никак не получается запустить mSGDMA (modular SGDMA (мануал прикреплен ниже)). Написал следующий код, который по идее должен стартовать DMA транзакцию, но ничего не выходит.
CODE
BOOLEAN
EvtProgramReadDma(
IN WDFDMATRANSACTION Transaction,
IN WDFDEVICE Device,
IN WDFCONTEXT Context,
IN WDF_DMA_DIRECTION Direction,
IN PSCATTER_GATHER_LIST SgList
)
{
PDEVICE_EXTENSION devExt;
size_t offset;
ULONG i;
UNREFERENCED_PARAMETER( Context );
UNREFERENCED_PARAMETER( Direction );
devExt = PLxGetDeviceContext(Device);
offset = WdfDmaTransactionGetBytesTransferred(Transaction);
WdfInterruptAcquireLock( devExt->Interrupt );
for (i=0; i < SgList->NumberOfElements; i++) {
//физический адрес начала памяти BAR0, полученный при инициализации устройства. Отсюда надо читать
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->ReadAddrLow, &devExt->ReadAddr.LowPart); //Read Address[31..0]
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->ReadAddrHigh, &devExt->ReadAddr.HighPart); //Read Address[63..32]
//физические адреса страниц, сооставляющих выделенный пользовательским приложением буффер. Сюда необходимо передать
//сформированный виндой Scatter/Gather List, соответствующий запросу от приложения
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->WriteAddrLow, SgList->Elements[i].Address.LowPart); //Write Address[31..0]
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->WriteAddrHigh, gList->Elements[i].Address.HighPart); //Write Address[63..32]
//длина каждой передаваемой страницы
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Length, SgList->Elements[i].Length); //Length[31..0]
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Burst_SeqNumber, 0);
WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Stride, 0x10001); //Write Stride[15..0], Read Stride[15..0]
{
union {
DESC_CONTROL bits;
ULONG ulong;
} DescCtrl;
DescCtrl.ulong =
READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc );
//первый пакет
if (i==0)
{
DescCtrl.bits.SOP = TRUE;
}
//последний пакет
else if (i==SgList->NumberOfElements-1)
{
DescCtrl.bits.EOP = TRUE;
DescCtrl.bits.TransferCOMP_IRQ = TRUE;
DescCtrl.bits.EARLY_IRQ = TRUE;
}
//одиночный пакет
else
{
DescCtrl.bits.SOP = TRUE;
DescCtrl.bits.EOP = TRUE;
DescCtrl.bits.TransferCOMP_IRQ = TRUE;
DescCtrl.bits.EARLY_IRQ = TRUE;
}
DescCtrl.bits.TransmitERR_IRQ = 0xFF;
DescCtrl.bits.Go = TRUE;
WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc,
DescCtrl.ulong );
}
}
//настройка управляющего регистра диспетчера
{
union {
DISP_CONTROL bits;
ULONG ulong;
} DispCtrl;
DispCtrl.ulong =
READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp );
//за что отвечает этот бит не совсем понял.
//разрешает прерывания или разрешает их если не заданы маски?
DispCtrl.bits.IntMask = TRUE;
WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp,
DispCtrl.ulong );
}
WdfInterruptReleaseLock( devExt->Interrupt );
return TRUE;
}
При этом, если пытаться отправить один пакет, то чтение статусного регистра диспетчера говорит, что дескрипторное фифо пусто, если отправлять 2 и более пакетов, то выставляется Busy статусного регистра диспетчера говорит, что в фифо что-то есть или идет передача, а Fill Level показывает количество занесеный в фифо дескрипторов. Но этот Busy стоит вечно, пока вручную не уберешь.
Выходит, что дескрипторы записываются, отправляются в фифо, откуда их должен вызывать диспетчер, но сам диспетчер передачу не запускает? потому они и остаются там висеть. Или же я не совсем верно заполняю эти дескрипторы?
В альтеровских дровах к модулю есть функции stop_dispatcher() и start_dispatcher(), смысл которых сводится к установке в 1 или 0 бита "Stop Dispatcher". Может быть стоит перед записью дескрипторов остановить диспетчер, а после записи запускать его? (почему-то не подумал об этом сразу).
Или же необходимо настраивать что-то еще?
Кстати, не совсем понял почему так происходит, но порой при установке бита "Global Interrupt Enable Mask" в диспетчере, компьютер намертво повисал. Может это было от того, что диспетчер засыпал его прерываниями, а я их толком не обработал? Прерывания либо вообще не приходят, либо система зависает намертво, но пока не выяснил чем именно это было вызвано. Есть какие-нибудь идеи у кого?
Буду очень признателен за любую помощь! Заранее спасибо, если хотя бы дочитали)