📄 datatransfer.cpp
字号:
}
_buffer_size = packet_count * packet_size;
_urb_size = GET_ISO_URB_SIZE(packet_count);
}
break;
case UsbdPipeTypeBulk:
{
if(_p_current_config->getUsbSpeed()==1) //high speed
{
packet_size = 512;
if(_media_type == 1) //audio, the reason is with low-rate transfer,we can't wait for long time to play
{
packet_count = 2;
}
else
{
//MS:Maximum Transfer Sizes for Bulk and Interrupt Pipes is 256,000 bytes.
packet_count = 320;
}
}
else //full speed
{
packet_size = 64;
packet_count = 4;
}
_buffer_size = packet_count * packet_size;
_urb_size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
_is_bulk = 1;
}
break;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS DataTransfer::start()
{
initializeTransfer();
NTSTATUS status = STATUS_SUCCESS;
DWORD i;
for(i = 0; i < _buffers_need; i++)
{
PBUFFER_ENTRY p_buffer = allocateBuffer();
if(p_buffer)
{
p_buffer->buffer_id = i;
sendBuffer(p_buffer);
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
if(!NT_SUCCESS(status))
{
break;
}
}
if(_buffer_count)
{
//We have some outstanding buffers, start the buffer parsing thread
status = startThread();
}
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID DataTransfer::stop()
{
if(!_stop_thread)
{
_stop_thread = TRUE;
if(_p_thread_object)
{
//Release the completion thread if it is waiting on buffers
_buffer_complete_queue.cancelWaits();
//Wait for the buffer complete thread to exit
KeWaitForSingleObject(
_p_thread_object,
Executive,
KernelMode,
TRUE,
NULL);
_p_thread_object = NULL;
}
//Abort any outstanding requests
_p_usb->UsbAbortPipe(_pipe, _interface);
//Wait for all outstanding buffers to complete and remove them from the
// buffer complete queue.
while(_buffer_count)
{
PBUFFER_ENTRY p_buffer = _buffer_complete_queue.getBuffer();
while(p_buffer)
{
freeBuffer(p_buffer);
p_buffer = _buffer_complete_queue.getBuffer();
}
if(_buffer_count && !p_buffer)
{
_buffer_complete_queue.waitForBuffers(500);
p_buffer = _buffer_complete_queue.getBuffer();
}
}
// need to store the flag
_digital_stream = 0;
_is_bulk = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS DataTransfer::sendBuffer(PBUFFER_ENTRY p_buffer)
{
//Initialize our completion context
p_buffer->p_data_transfer = this;
p_buffer->read_context.pIrp = p_buffer->p_irp;
p_buffer->read_context.pUrb = p_buffer->p_urb;
p_buffer->read_context.pCompletion = (USBCOMPLETION)static_BufferComplete;
p_buffer->read_context.UserContext = p_buffer;
p_buffer->bytes_completed = 0;
//Start a data transfer
NTSTATUS status = _p_usb->UsbAsyncIo(
_pipe,
_interface,
p_buffer->p_buffer,
_buffer_size,
NULL,
&(p_buffer->read_context));
if(NT_SUCCESS(status))
{
return STATUS_SUCCESS;
}
//We have a failure. Free the buffer. (Should we wait and retry if this fails?)
KdPrint(("Error sending buffer to USB bus driver. status = %x\n", status));
//If we failed, the completion routine may not get called, so we need to avoid
// losing the buffer. Add the buffer to the complete queue.
_buffer_complete_queue.addBuffer(p_buffer);
// call datatransfer stop() to stop all operations
// This is the only way to recover from race condition.
// once there is a problem with USB transfer, either it could be surprise removal or
// pipe broke issue. once the transfer is not ok, then in the present case the p_buffer is
// added to complete queue, and data transfer thread inner while loop sees the buffer always
// with bytes_completed as zero, and that too this thread runs at HIGH_PRIORITY-3 level,
// nobody else gets priority than the while loop. To avoid this race condition, we need to
// stop the complete operation as if top layer sent stop() command.
// stop data transfer which will avoid double while loop of scheduling new IRP's
// other wise system will be in these while loops forever because of its High Priority
// If we decrease the priority, Movie maker fails to record the good video. So the data
// transfer thread has to run at high priority.
//stop();
return STATUS_UNSUCCESSFUL;
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID DataTransfer::static_BufferComplete(PBUFFER_ENTRY p_context,
NTSTATUS status,
ULONG transfer_size,
PVOID p_read_context)
{
if(p_context)
{
DataTransfer* p_this = p_context->p_data_transfer;
if((status == STATUS_SUCCESS) && (transfer_size > 0))
{
p_context->bytes_completed = transfer_size;
if( p_this->_digital_stream)
{
p_this->_polaris_engine_fail_count = 0;
}
}
else
{
// KdPrint(("DataTransfer::static_BufferComplete is failed, type = %x,transfer_size = %d\n",p_this->getType(),transfer_size));
p_context->bytes_completed = 0;
if( p_this->_digital_stream)
{
p_this->_polaris_engine_fail_count++;
}
}
//if the buffer was not on the complete queue already, add it there.
//Put the buffer in the buffer complete queue
p_this->_buffer_complete_queue.addBuffer(p_context);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID DataTransfer::static_ThreadFunction(DataTransfer* p_this)
{
p_this->parseBufferThread();
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID DataTransfer::parseBufferThread()
{
PBUFFER_ENTRY p_buffer_entry = NULL;
ULONG fail_counter = 0;
BOOL bUnrecoverableError = FALSE;
NTSTATUS status=STATUS_UNSUCCESSFUL;
// Initialize the variables for digital path
if(_digital_stream)
{
_polaris_engine_fail_count=0;
_ts_Data.Initialize(_p_usb_firmware);
}
KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY-3 );
while(!_stop_thread)
{
p_buffer_entry = _buffer_complete_queue.getBuffer();
while(p_buffer_entry)
{
if(_stop_thread)
{
break;
}
if(p_buffer_entry->bytes_completed != 0)
{
fail_counter = 0;
if(_is_bulk)//bulk
{
if( _digital_stream)
{
_ts_Data.submitDataBuffer(
p_buffer_entry->p_buffer,
_buffer_size);
}
else
{
if (_media_type == 1) //Audio without HANC
{
_data_parser.submitDataBuffer(
p_buffer_entry->p_buffer,
_buffer_size,1);
}
else // other cases
{
_data_parser.submitDataBuffer(
p_buffer_entry->p_buffer,
_buffer_size,0);
}
}
}
else //iso
{
struct _URB_ISOCH_TRANSFER *pIso =
(struct _URB_ISOCH_TRANSFER *)p_buffer_entry->p_urb;
for (ULONG i = 0; i < pIso->NumberOfPackets; i++)
{
if (pIso->IsoPacket[i].Length)
{
if( _digital_stream)
{
// Digital path working
_ts_Data.submitDataBuffer(
p_buffer_entry->p_buffer + pIso->IsoPacket[i].Offset,
pIso->IsoPacket[i].Length);
}
else
{
// Analog path working
if (_media_type == 1) // Audio without HANC
{
_data_parser.submitDataBuffer(
p_buffer_entry->p_buffer + pIso->IsoPacket[i].Offset,
pIso->IsoPacket[i].Length,1);
}
else
{
_data_parser.submitDataBuffer(
p_buffer_entry->p_buffer + pIso->IsoPacket[i].Offset,
pIso->IsoPacket[i].Length,0);
}
}
}
}
}
}
else
{
fail_counter++;
if(fail_counter == 50)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -