Problems with USB Isoc transfers.

I am developing a simple driver for USB device. My driver should start Isoc transfers when device is connected.

So in the AddDevice function I configure device,I set altsetting.
Then I want to start Isoc transfers when IRP_MN_START_DEVICE arrive.There I start a new thread and try to send transfers. In completion routine I can see that
Irp->IoStatus.Status == 3221225485. But when I started Isoc transfers immediately
after configuring device, in addDevice function(whithout second thread), my isoc transfers succeedly passed, and I can recieve them from device. I have also tried to configure device in IRP_MN_START_DEVICE in second thread and it succeeds,but isoc transfers not performed. I think I hanle IRP_MN_START_DEVICE properly, i pass down synchronously irp, set the status of irp returned by IoCallDriver and do IoCompleteRequest.
And also I have problem of creating irps with IoAllocateIrp,it leads to windows restart.
And all irps for isoc transfers I create with IoBuildDeviceIoControlRequest.

Are there any ideas, please help.

Regards,
Tigran

xxxxx@yahoo.com wrote:

I am developing a simple driver for USB device. My driver should start Isoc transfers when device is connected.

So in the AddDevice function I configure device,I set altsetting.
Then I want to start Isoc transfers when IRP_MN_START_DEVICE arrive.

I’m not sure I agree with that timing. I wouldn’t expect you to
configure the device until IRP_MN_START_DEVICE. AddDevice is largely
intended to allow you to prepare for the operation of the device in a
software sense, whereas START_DEVICE is largely intended to start normal
operations. That’s a rather vague philosophical distinction, I admit.

There I start a new thread and try to send transfers. In completion routine I can see that
Irp->IoStatus.Status == 3221225485.

Kernel errors are always, always, always rendered in hex. 3221225485 is
C000000D. That’s STATUS_INVALID_PARAMETER. Are you specifying a frame
number, or are you using USBD_START_ISO_TRANSFER_ASAP? What data are
you sending? Is it data that you are generating inside the driver? Are
you doing both input and output pipes? What are the packet sizes and
intervals?

Why do you launch a thread for this? URBs are always asynchronous. It
doesn’t take any time to fire off a set of URBs, and then you return and
wait for the completion callbacks. I don’t see what you gain by
starting a thread.

And also I have problem of creating irps with IoAllocateIrp,it leads to windows restart.
And all irps for isoc transfers I create with IoBuildDeviceIoControlRequest.

How are you freeing the IRP? IoAllocateIrp must be paired with IoFreeIrp.


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

> I’m not sure I agree with that timing. I wouldn’t expect you to
configure the device until IRP_MN_START_DEVICE.

AddDevice is largely
intended to allow you to prepare for the operation of the device in a
software sense, whereas START_DEVICE is largely intended to start normal
operations.
That’s a rather vague philosophical distinction, I admit.

Yes you are right, I will cunfigure device after IRP_MN_START_DEVICE, I have done so and no problems.

Kernel errors are always, always, always rendered in hex. 3221225485 is
C000000D.
That’s STATUS_INVALID_PARAMETER. Are you specifying a frame
number, or are you using USBD_START_ISO_TRANSFER_ASAP?
What data are you sending?
Is it data that you are generating inside the driver?
Are you doing both input and output pipes?
What are the packet sizes and intervals?

Cuold you say me where to find description for error codes.
I set USBD_START_ISO_TRANSFER_ASAP flag, for all isoc transfers. And I have just read that this is restricted for first transaction on a newly opened or reset pipe.
I just send text. And I do only out transfers(so far, but I want in transfers to). Device enspoint’s maxpacket size is 64 and interval is 1.

Why do you launch a thread for this?
I don’t know, I think it is better to start thread after IRP_MN_START_DEVICE retrurn, then in thread submit URBs.

IoAllocateIrp must be paired with IoFreeIrp.

I have not done IoFreeIrp. Can it couse a reboot of system.

It is interesting that in same computer there are ports, when I connect them device, my driver runs only once, it configures device and fails isoc transfers(with above status). But when I connect device to other ports, my driver may run 3 or 4 times(IRP_MN_REMOVE_DEVICE then again AddDevice and IRP_MN_START_DEVICE ), after which windows says thay your device may perform faster if you connect it to usb2.0 … and isoc transfers SUCCEDS!!! and I can catch them from device.

Thanks.

xxxxx@yahoo.com wrote:

Cuold you say me where to find description for error codes.

That’s a pretty fundamental question. A bit of digging through the DDK
should have pointed you to ntstatus.h.

I set USBD_START_ISO_TRANSFER_ASAP flag, for all isoc transfers. And I have just read that this is restricted for first transaction on a newly opened or reset pipe.

In my opinion, this is more of a theoretical concern than a practical
one. There is a potential issue in a very heavily loaded system, when
the host controller cannot service its requests in time, but I have not
seen this occur in the real world.

I just send text. And I do only out transfers(so far, but I want in transfers to). Device enspoint’s maxpacket size is 64 and interval is 1.

That’s fine. Is it a USB 1 device, or a USB 2 device?

> Why do you launch a thread for this?
>
I don’t know, I think it is better to start thread after IRP_MN_START_DEVICE retrurn, then in thread submit URBs.

No. As a general rule, there are very few cases in which the typical
kernel driver needs to spawn a new thread. There are as many exceptions
to that general rule as there are driver programmers, of course, but
creating and submitting a bunch of URBs takes very little time.

I did have a case this week where I needed a driver thread; I have a USB
camera that requires a bunch of initialization, and because of a bug in
their I2C implementation, the initialization sequence takes 7 or 8
seconds. I didn’t want to hold off START_DEVICE for that long…

> IoAllocateIrp must be paired with IoFreeIrp.
>

I have not done IoFreeIrp. Can it couse a reboot of system.

If you keep doing IoAllocateIrp without freeing them, eventually you
will run out of non-paged pool memory and cause a blue screen. The
default action for a blue screen today is to reboot.

> It is interesting that in same computer there are ports, when I connect them device, my driver runs only once, it configures device and fails isoc transfers(with above status). But when I connect device to other ports, my driver may run 3 or 4 times(IRP_MN_REMOVE_DEVICE then again AddDevice and IRP_MN_START_DEVICE ), after which windows says thay your device may perform faster if you connect it to usb2.0 … and isoc transfers SUCCEDS!!! and I can catch them from device.
>

I have seen this several times, caused by mechanical issues when the USB
connector doesn’t seat well. This can be caused by low quality cables,
worn-out USB hubs, cable pulled at the wrong angle, etc.


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

> That’s fine. Is it a USB 1 device, or a USB 2 device?

my device is usb2.0 and I still can’t perfrorm my isoch transfers.

I build them with IoBuildDeviceIoControlRequest :

IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
pDeviceExtension->TopOfStackDeviceObject,
NULL,0,NULL,0,TRUE,&event,&ioStatus);

is it correct to do that for isoch transfers?

my code looks like this

static const int PACKET_COUNT = 32;
static const int URB_COUNT = 1;

KeInitializeEvent(&event,NotificationEvent,FALSE);
pOutIrp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
pDeviceExtension->TopOfStackDeviceObject,
NULL,0,NULL,0,TRUE,&event,&ioStatus);

pOutUrbs = ExAllocatePool(NonPagedPool,
GET_ISO_URB_SIZE(PACKET_COUNT)*URB_COUNT);
bufSize = URB_COUNT * PACKET_COUNT * pDeviceExtension->maxPacketSize;

Sorry I was misleadingly posted not completed reply.

so, rest of my code is.

FillIsoUrb(pOutUrbs,pDeviceExtension->maxPacketSize,pUrbBuffer,
pDeviceExtension->isocOutPipe.PipeHandle,
USBD_TRANSFER_DIRECTION_OUT);

//submit one for a test
pStack = IoGetNextIrpStackLocation(pOutIrp);
pStack->Parameters.Others.Argument1 = pOutUrbs;
pStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
pStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

IoSetCompletionRoutine(pOutIrp,IsoUsb_IsoOutComplete,pOutUrbs,
TRUE,
TRUE,
TRUE);

IoMarkIrpPending(pOutIrp);
pOutUrbs->UrbIsochronousTransfer.StartFrame =
IsoUsb_GetCurrentFrameNumber(pDeviceObject) + 16;

status = IoCallDriver(pDeviceExtension->TopOfStackDeviceObject,
pOutIrp);

and

void FillIsoUrb(PURB pUrb,ULONG packetSize,void * pBuf,USBD_PIPE_HANDLE pH,
int dir)
{
int i;
char *pCharBuf = pBuf;

sprintf(pBuf,“%s”,“First packet”);

RtlZeroMemory(pUrb,GET_ISO_URB_SIZE(PACKET_COUNT));

pUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT)
GET_ISO_URB_SIZE(PACKET_COUNT);

pUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
pUrb->UrbIsochronousTransfer.PipeHandle = pH;
pUrb->UrbIsochronousTransfer.TransferFlags = (ULONG)dir;
pUrb->UrbIsochronousTransfer.TransferFlags |=
USBD_START_ISO_TRANSFER_ASAP;
pUrb->UrbIsochronousTransfer.TransferBufferMDL = NULL;
pUrb->UrbIsochronousTransfer.TransferBuffer = pBuf;
pUrb->UrbIsochronousTransfer.TransferBufferLength =
packetSize*PACKET_COUNT;
pUrb->UrbIsochronousTransfer.NumberOfPackets = PACKET_COUNT;
pUrb->UrbIsochronousTransfer.UrbLink = NULL;

for(i = 0;i < PACKET_COUNT;++i){
pUrb->UrbIsochronousTransfer.IsoPacket[i].Offset = i*packetSize;
pUrb->UrbIsochronousTransfer.IsoPacket[i].Length = packetSize;
}
return;
}

xxxxx@yahoo.com wrote:

Sorry I was misleadingly posted not completed reply.

so, rest of my code is.

FillIsoUrb(pOutUrbs,pDeviceExtension->maxPacketSize,pUrbBuffer,
pDeviceExtension->isocOutPipe.PipeHandle,
USBD_TRANSFER_DIRECTION_OUT);

//submit one for a test
pStack = IoGetNextIrpStackLocation(pOutIrp);
pStack->Parameters.Others.Argument1 = pOutUrbs;
pStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
pStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

IoSetCompletionRoutine(pOutIrp,IsoUsb_IsoOutComplete,pOutUrbs,
TRUE,
TRUE,
TRUE);

IoMarkIrpPending(pOutIrp);
pOutUrbs->UrbIsochronousTransfer.StartFrame =
IsoUsb_GetCurrentFrameNumber(pDeviceObject) + 16;

status = IoCallDriver(pDeviceExtension->TopOfStackDeviceObject,
pOutIrp);

The IoMarkIrpPending call is a mistake. YOU do not get to decide
whether the IRP is pending. That decision will be made by the drivers
that handle the request.

The IoControlCode will already have been set by
IoBuildDeviceIoControlRequest.

The rest of this looks reasonable.


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

Not only is marking the request wrong from the perspective of who queues it, it will corrupt memory because it touches the current stack location and the current location is invalid

d

Sent using my smartphone, apologies forany typos

-----Original Message-----
From: “Tim Roberts”
To: “Windows System Software Devs Interest List”
Sent: 09/13/07 12:50 PM
Subject: Re: [ntdev] Problems with USB Isoc transfers.

xxxxx@yahoo.com wrote:
> Sorry I was misleadingly posted not completed reply.
>
> so, rest of my code is.
>
> FillIsoUrb(pOutUrbs,pDeviceExtension->maxPacketSize,pUrbBuffer,
> pDeviceExtension->isocOutPipe.PipeHandle,
> USBD_TRANSFER_DIRECTION_OUT);
>
> //submit one for a test
> pStack = IoGetNextIrpStackLocation(pOutIrp);
> pStack->Parameters.Others.Argument1 = pOutUrbs;
> pStack->Parameters.DeviceIoControl.IoControlCode =
> IOCTL_INTERNAL_USB_SUBMIT_URB;
> pStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
>
>
> IoSetCompletionRoutine(pOutIrp,IsoUsb_IsoOutComplete,pOutUrbs,
> TRUE,
> TRUE,
> TRUE);
>
> IoMarkIrpPending(pOutIrp);
> pOutUrbs->UrbIsochronousTransfer.StartFrame =
> IsoUsb_GetCurrentFrameNumber(pDeviceObject) + 16;
>
> status = IoCallDriver(pDeviceExtension->TopOfStackDeviceObject,
> pOutIrp);
>

The IoMarkIrpPending call is a mistake. YOU do not get to decide
whether the IRP is pending. That decision will be made by the drivers
that handle the request.

The IoControlCode will already have been set by
IoBuildDeviceIoControlRequest.

The rest of this looks reasonable.


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


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

Thanks.