zhonghong200
驱动牛犊
驱动牛犊
  • 注册日期2009-12-03
  • 最后登录2012-04-24
  • 粉丝0
  • 关注0
  • 积分26分
  • 威望311点
  • 贡献值2点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1236回复:0

USB 摄像机驱动开发瓶颈问题请教大家

楼主#
更多 发布于:2009-12-29 15:35
瓶颈问题:重要!需求:
我现在做的是摄像机的驱动程序,现在我的驱动程序设置了2个函数,一个用于传输控制命令(对应于端点0),一个用于从端点6读取数据:相机USB有2个端点,端点0和端点6,端点0用于传输命令,端点6用来传输数据,端点0的缓冲区大小为64个字节,端点6的缓冲区的大小为2k,当应用程序向相机发送F1 xx xx xx xx xx xx xx 命令,命令为8个字节,xx表示为任意值,应用程序发送F1后,相机通过端点6给应用程序发送数据,但是每次只发512个字节,所以需要开辟一个线程不断的监听端点6,然后不断的把数据取走,摄像机会不断的往端点6发送数据,当取出的数据的大小为一幅图像的大小时(1.4M)就将图像显示在界面上,然后继续监听端点6,重新开始读数据。
    
问题(1) 怎么使用线程去监听端点6,有没有读取端点6的API,以流的形式读(StreamRead)
我是这样考虑的,可以用2种方法去读数据,第一种方法是驱动程序分配一个缓冲区,大小为一幅图像的大小,然后不断的从端点6读取数据,一次读512个字节,然后移动缓冲区的指针,接着读,直到缓冲区满,说明一幅图像已经读出来了,显示在界面上,清空缓冲区,然后继续读端点6.
第2种方法是采用Stream的方式读,不知道有这样的API吗,(win driver )里面就有这样的API,我现在不知道driver studio 或windows 提供这样的API吗?

问题(2):我在应用程序中想用这个函数传输控制命令,
DeviceIoControl(m_hDevice,
        Camera_IOCTL_Control,
        bufInput,
        IOCTL_INBUF_SIZE,
        bufOutput,
        IOCTL_OUTBUF_SIZE,
        &nOutput,
        NULL)
        )
BufInput 是不是传输的就是我们的令牌还是我们的控制命令,我的令牌为0x40 0xF1 0x00 0x00 0x00 0x00 0x08 0x00,而我的控制命令是0xF10x00 0x00 0x00 0x00 0x00 0x08 0x00,我现在搞不懂了到底命令怎么传输。我将bufInput 初始化为 0xF10x00 0x00 0x00 0x00 0x00 0x08 0x00,使用bus hound 抓图如下:没有弄明白,我没有发送令牌,CTL 0x40 0xF1 0x00 0x00 0x00 0x00 0x08 0x00 是怎么加上去的
 

问题(3):
我想用NTSTATUS CameraDevice::Camera_IOCTL_Read_Handler(KIrp I)函数去读取端点6中的数据,这个里面调用了2个函数EndPoint6In.BuildBulkTransfer和EndPoint6In.SubmitUrb:
PURB pUrb=EndPoint6In.BuildBulkTransfer((unsigned char *)I.IoctlBuffer(), //接收数据的缓冲区
    dwTotalSize, //读数据的数据字节数
    TRUE,  //TURE表示读数据
    NULL,  //连接下一个传输的URB,这里没有,置为NULL
    TRUE,  //TRUE表示设备传输的字节数可以少于指定的字节数
    NULL);  //指向一个已经存在的URB。置为NULL,分配一个新的URB

但是我没有弄明白:BuildBulkTransfer函数中,I.IoctlBuffer()就是我的相机传输的512字节吗,那么在调用Camera_IOCTL_Read_Handler(KIrp I)的应用程序DeviceIoControl中,bufInput=512吗,还有bufOutput的大小就是我分配的一幅图片的缓冲区的大小吗?
那么我怎么在Camera_IOCTL_Read_Handler(KIrp I)中不断的读数据呢?
DeviceIoControl(m_hDevice,
        Camera_IOCTL_Control,
        bufInput,
        IOCTL_INBUF_SIZE,
        bufOutput,
        IOCTL_OUTBUF_SIZE,
        &nOutput,
        NULL)
        )


问题(4)我不知道怎么去开辟一个线程去监听端口,我那个应用程序和驱动程序中的读数据函数还没有完全写好,大家提供能提供一点方法吗?我的读图像的理路如下:
 

驱动程序和应用程序如下:

NTSTATUS CameraDevice::DeviceControl(KIrp I)
{
    T.Trace(TraceInfo, __FUNCTION__"++.  IRP %p\n", I);
    NTSTATUS status = STATUS_SUCCESS;
    switch (I.IoctlCode())
    {
    case Camera_IOCTL_Control:
        status = Camera_IOCTL_Control_Handler(I);//设置控制参数;
        break;
    case Camera_IOCTL_Read:
        status = Camera_IOCTL_Read_Handler(I);//读端口6中的数据;
        break;
    case Camera_IOCTL_Write:
        status = Camera_IOCTL_Write_Handler(I);
        break;
    default:
        status = STATUS_INVALID_DEVICE_REQUEST;
        break;
    }
    if (status != STATUS_PENDING)
    {
        I.PnpComplete(this, status);
    }
    T.Trace(TraceInfo, __FUNCTION__"--.  IRP %p, STATUS %x\n", I, status);
    return status;
}

//下面是接收端点0控制命令的函数
NTSTATUS CameraDevice::Camera_IOCTL_Control_Handler(KIrp I)//发送控制命令的脚本
{
    T.Trace(TraceInfo, __FUNCTION__"++.  IRP %p\n", I);

    NTSTATUS status = STATUS_SUCCESS;

    //ULONG inputSize = I.IoctlInputBufferSize();
    //ULONG outputSize = I.IoctlOutputBufferSize();
           //PVOID inputBuffer = I.IoctlBuffer();
   // PVOID outputBuffer = I.IoctlBuffer();
    if(FALSE)
    {
        status=STATUS_INVALID_PARAMETER;
        I.Information()=0;
    }
    else
    {
            PURB pUrb=m_Lower.BuildVendorRequest(
            (unsigned char *)I.IoctlBuffer(),//transfer buffer 为驱动程序传输数据的内存区
            I.IoctlInputBufferSize(),//transfer buffer size 为传输的字节数
            0, //request reserved bits
            0xF1,//具体请求的数值,可以为F1 F2 F4 F5 F6
            0,       //value
            FALSE,   //FALSE 表示输出,数据从主机到设备
            TRUE,    //        
            NULL,    //Link
            0        //Index
            );
        if ( pUrb == NULL )
            {
                status = STATUS_INSUFFICIENT_RESOURCES;
            }
        else
            {
                // submit the URB to USBD
status = m_Lower.SubmitUrb(pUrb);//SubmitUrb(pUrb,NULL,NULL,1500L);
            if(NT_SUCCESS(status))
            {
I.Information() = pUrb->UrbControlVendorClassRequest.TransferBufferLength;
            }
              delete pUrb;//删除分配的Urb
            }
          }//end else
    I.Status() = status;
    T.Trace(NT_SUCCESS(status)?TraceInfo:TraceWarning, __FUNCTION__"--.  IRP %p, STATUS %x\n", I, status);
    return status;
}

NTSTATUS CameraDevice::Camera_IOCTL_Read_Handler(KIrp I)//这里是往端点6读数据的程序
{
    T.Trace(TraceInfo, __FUNCTION__"++.  IRP %p\n", I);
    NTSTATUS status = STATUS_SUCCESS;
      //    ULONG inputSize = I.IoctlInputBufferSize();
      //    ULONG outputSize = I.IoctlOutputBufferSize();
      // Buffered ioctl - using the same buffer so read the buffer before writing the buffer
      // PVOID inputBuffer = I.IoctlBuffer();
      // PVOID outputBuffer = I.IoctlBuffer();
      // TODO: Validate the parameters of the IRP.  Replace "FALSE"
      //in the following line with error checking code that
      //evaulates to TRUE if the request is not valid.
    if(FALSE)//如果缓冲区为无效地址
    {
        status = STATUS_INVALID_PARAMETER;
        I.Information() = 0;
    }
    else
    {
        if(I.IoctlOutputBufferSize()==0) //如果读数据长度为0,则不用传输数据
        {
            I.Information() = 0;
            return I.PnpComplete(this,STATUS_SUCCESS);
        }
        else //长度不为0
        {
                ULONG dwTotalSize=I.IoctlOutputBufferSize(CURRENT);//
                ULONG dwMaxSize=EndPoint6In.MaximumTransferSize();
                if(dwTotalSize>dwMaxSize)
                {
                ASSERT(dwMaxSize);
                dwTotalSize=dwMaxSize;
                }
                 //创建一个批量传输的URB,用来从端点6读取数据
PURB pUrb=EndPoint6In.BuildBulkTransfer((unsigned char *)I.IoctlBuffer(), //接收数据的缓冲区
                dwTotalSize, //读数据的数据字节数
                TRUE,  //TURE表示读数据
                NULL,  //连接下一个传输的URB,这里没有,置为NULL
                TRUE,  //TRUE表示设备传输的字节数可以少于指定的字节数
                NULL);  //指向一个已经存在的URB。置为NULL,分配一个新的URB
            if(pUrb==NULL)  //如果分配失败
            {
                status=STATUS_INSUFFICIENT_RESOURCES;  //设置状态为资源不足
                I.Information()=0; //数据传输为0
            }
            else
            {
                //提交URB,并设置等待3秒后就超时
                status=EndPoint6In.SubmitUrb(pUrb,NULL,NULL,3000);//
                //获取实际读到的数据字节数
                if(NT_SUCCESS(status))
                {
                I.Information()=pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
                }
                delete pUrb; //删除刚刚分配的URB
            }
        }
    }
    T.Trace(NT_SUCCESS(status)?TraceInfo:TraceWarning, __FUNCTION__"--.  IRP %p, STATUS %x\n", I, status);
    return status;
}

对应的测试应用程序如下:
void CTest_CameraDlg::OnOK()
{
    // TODO: Add extra validation here
    TestControlParam();//传输控制命令
    TestReadParam();//从端点6读取数据
}

     void CTest_CameraDlg::TestControlParam()
{
    UCHAR bufInput[IOCTL_INBUF_SIZE]={0xF1,0x00,0x00,0x00,0x00,0x00,0x08,0x00};// //Input to device
    UCHAR bufOutput[IOCTL_OUTBUF_SIZE];    // Output from device
    ULONG nOutput;                    // Count written to bufOutput
    if (!DeviceIoControl(m_hDevice,
        Camera_IOCTL_Control,
        bufInput,
        IOCTL_INBUF_SIZE,
        bufOutput,
        IOCTL_OUTBUF_SIZE,
        &nOutput,
        NULL)
        )
    {
        MessageBox("Camera_IOCTL_Control", "错误", MB_OK | MB_ICONHAND);
    }
}

#define IOCTL_INBUF_SIZE1 512
#define  IOCTL_OUTBUF_SIZE1 512

void CTest_CameraDlg::TestReadParam()
{
    UCHAR   bufInput[IOCTL_INBUF_SIZE1];
    UCHAR    bufOutput[IOCTL_OUTBUF_SIZE1];
    ULONG   nOutput;//
    if (!DeviceIoControl(m_hDevice,
        Camera_IOCTL_Read,
        bufInput,
        IOCTL_INBUF_SIZE,
        bufOutput,
        IOCTL_OUTBUF_SIZE,
        &nOutput,
        NULL)
        )
    {
        MessageBox("Camera_IOCTL_Read", "错误", MB_OK | MB_ICONHAND);
    }
    else
    {
        CString str;
        str.Format("0x%x",bufOutput);
        SetDlgItemText(IDC_OutputEndpoint,str);
    }
}
游客

返回顶部