I’m developing an AV/C tuner subunit driver, using the 1394dcam driver from
the Windows Server 2003 DDK (3790) as a basis. I’m able to send 1394 and
61883 commands to the device using IOCTL_1394_CLASS and IOCTL_61883_CLASS
respectively. However, when I try to send an AV/C command using
IOCTL_AVC_CLASS, I always get a response code of AVC_RESPONSE_NOTIMPL, even
with commands that I know work, having tested them using the Apple FireWire
SDK on a Mac running OS X.
Is there anyone out there who’s gotten AV/C commands to work, and if so,
what’s the secret?
Here’s the code I use to send the AV/C command:
NTSTATUS TunerIssueAVCCommandCR(IN PDEVICE_OBJECT DeviceObject, IN PIRP
pIrp, IN PVOID pCtx)
{
DbgMsg3((“'TunerIssueAVCCommandCR: pIrp->Pending = %u\r\n”,
pIrp->PendingReturned));
KeSetEvent((PKEVENT)pCtx, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS TunerGetAVCUnitInfo(PTUNER_EXTENSION pDevExt)
{
KEVENT Event;
NTSTATUS status;
PIO_STACK_LOCATION NextIrpStack;
BOOL bCanWait = KeGetCurrentIrql() < DISPATCH_LEVEL;
AVC_COMMAND_IRB irb;
PIRP pIrp;
pIrp = IoAllocateIrp(pDevExt->BusDeviceObject->StackSize, FALSE);
NextIrpStack = IoGetNextIrpStackLocation(pIrp);
NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_AVC_CLASS;
NextIrpStack->Parameters.Others.Argument1 = &irb;
RtlZeroMemory(&irb, sizeof(AVC_COMMAND_IRB));
irb.Function = AVC_FUNCTION_COMMAND;
irb.CommandType = (UCHAR)AVC_CTYPE_CONTROL;
irb.Opcode = (UCHAR)0x30; // AV/C Unit Info command
irb.OperandLength = 5;
irb.Operands[0] = 0xFF;
irb.Operands[1] = 0xFF;
irb.Operands[2] = 0xFF;
irb.Operands[3] = 0xFF;
irb.Operands[4] = 0xFF;
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
DbgMsg3((“GetAVCUnitInfo: before command, Rspcode = %02X, opcode = %02X,
oplength = %08X\r\n”,
irb.ResponseCode, irb.Opcode, irb.OperandLength));
IoSetCompletionRoutine(pIrp, TunerIssueAVCCommandCR, &Event, TRUE, TRUE,
TRUE);
status = IoCallDriver(pDevExt->BusDeviceObject, pIrp);
DbgMsg3((“'GetAVCUnitInfo: pIrp is pending(%s); will wait(%s)\r\n”,
status == STATUS_PENDING ? “Y”:“N”, bCanWait? “Y”:“N”));
if (STATUS_PENDING == status)
{
if (bCanWait)
{
//
// Still pending, wait for the IRP to complete
//
KeWaitForSingleObject( // Only in <= IRQL_DISPATCH_LEVEL; can
only in DISPATCH if Timeout is 0
&Event,
Executive,
KernelMode,
FALSE,
NULL
);
status = pIrp->IoStatus.Status;
DbgMsg3((“'GetAVCUnitInfo: Irp status = %08X, Rspcode = %02X,
opcode = %02X, oplength = %08X\r\n”,
pIrp->IoStatus.Status, irb.ResponseCode, irb.Opcode,
irb.OperandLength));
DbgMsg3((“'GetAVCUnitInfo: rsp = %02X %02X %02X %02X %02X\r\n”,
irb.Operands[0], irb.Operands[1], irb.Operands[2],
irb.Operands[3], irb.Operands[4]));
IoFreeIrp(pIrp);
return status;
}
else
{
IoFreeIrp(pIrp);
return STATUS_PENDING;
}
}
else
{
DbgMsg3((“'GetAVCUnitInfo: command finished immediately, status
%08X\r\n”, status));
if (STATUS_SUCCESS == status)
{
DbgMsg3((“'GetAVCUnitInfo: Irp status = %08X, Rspcode = %02X,
opcode = %02X, oplength = %08X\r\n”,
pIrp->IoStatus.Status, irb.ResponseCode, irb.Opcode,
irb.OperandLength));
DbgMsg3((“'GetAVCUnitInfo: rsp = %02X %02X %02X %02X %02X\r\n”,
irb.Operands[0], irb.Operands[1], irb.Operands[2],
irb.Operands[3], irb.Operands[4]));
}
IoFreeIrp(pIrp);
return status;
}
}