Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Oct 2012 21:54:34 +0900 (JST)
From:      SAITOU Toshihide <toshi@ruby.ocn.ne.jp>
To:        freebsd-usb@freebsd.org
Subject:   isochronous transfer for UVC camera
Message-ID:  <20121029.215434.122618874.toshi@ruby.ocn.ne.jp>

next in thread | raw e-mail | index | archive | help
I'm trying to get the streaming data from the UVC camera, but isochronous transfer callback isn't invoked. Is this lack of parameters to be set or wrong coding for my isochronous transfer?

$ uname -a
FreeBSD Kingyo.ens.tut.ac.jp 9.1-RC2 FreeBSD 9.1-RC2 #0 r241106: Mon Oct  1 18:26:44 UTC 2012     root@farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

------------------------------------------------------------
/*
 *   $ cc -o ex10 ex10.c -lusb
 *   $ ./ex10 
 *
 * [UVC1.5] Universal Serial Bus Device Class Definition for Video Devices,
 *          (UVC 1.5 Class specification.pdf),
 *          <http://www.usb.org/developers/devclass_docs>.
 *
 * [USB2.0] USB 2.0 Specification Universal Serial Bus Revision 2.0 specification,
 *          (usb_20.pdf), <http://www.USB.org/developers/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <libusb.h>
 
#define VID     0x0458
#define PID     0x7081
#define TIMEOUT 500             // 500 ms
     
#define ConfNum    1            // Configuration Number
#define IfNum      1            // Interface Number
#define AltIfNum   1            // Alternate Interface Number


static void cb(struct libusb_transfer *transfer)
{
        printf("\nReceived.\n");
        libusb_submit_transfer(transfer); // repeat
}


int main( int argc, char **argv)
{
        struct libusb_device_descriptor desc;
    	libusb_context *ctx = NULL;
    	libusb_device **deviceLst;
    	ssize_t deviceCnt = 0;
    	libusb_device *camdev = NULL;
        libusb_device_handle *handle;	
    	int attached = 0;

        uint8_t buf[256];
    	int i;
    	int rcv;


        // populate list with the list of usb devices available.
    	libusb_init(&ctx);
    	if ((deviceCnt = libusb_get_device_list(ctx, &deviceLst)) < 0) {
    		fprintf(stderr, "no usb devices found\n");
    		return;
    	}

        libusb_set_debug(ctx, 99);

    	// find device
    	for (i = 0; i < deviceCnt; i++) {
                libusb_get_device_descriptor(deviceLst[i], &desc);
                if (desc.idVendor == VID && desc.idProduct == PID) {
                        camdev = (libusb_device *)deviceLst[i];
                        break;
                }
    	}

    	if (!camdev)
        {
                fprintf(stderr, "device not found.");
                return;
        }


        // open device
        if (libusb_open(camdev, &handle) != 0)
        {
                fprintf(stderr, "Unable to open usb device\n");
                return;
        }
     
        // if kernel driver is active, detach a kernel driver.
        if (libusb_kernel_driver_active(handle, 0) == 1)
        {
                printf("Detaching kernel driver.\n");
                libusb_detach_kernel_driver(handle, 0);
                attached = 1;
        }

        // set the active configuration
        if (libusb_set_configuration(handle, ConfNum) != 0)
        {
                fprintf(stderr, "Set configuration failed.");
        }


        // ------------------------------------------------------------
        // negotiate the streaming parameters

        // Device State Transition [UVC1.5, p. 107]
        // Video Probe and Commit Controls [UVC1.5, p. 134]

        // set some parameters described to set by the host. [UVC1.5, p. 134]
        for (i=0; i<48; i++) {
                buf[i] = 0x00;
        }
        buf[0] = 0x01;          // what fields shall be kept fixed (0x01: dwFrameInterval)
        buf[1] = 0x00;          // 
        buf[2] = 0x01;          // video format index
        buf[3] = 0x01;          // video frame index
        buf[4] = 0x40;          // interval
        buf[5] = 0x4b;          //   propose:   0x4c4b40 (500 ms)
        buf[6] = 0x4c;          //   agreement: 0x1312d0 (125 ms)
        buf[7] = 0x00;          // 

        // VS_PROBE_CONTROL(0x01) [UVC1.5, p. 161], SET_CUR(0x87) [UVC1.5, p.158]
        libusb_control_transfer(handle, 0x21, 0x01, 0x0100, 0x0001, buf, 48, TIMEOUT);
        for (i=0; i<48; i++) { printf("%x ", buf[i]); } printf("\n");

        // VS_PROBE_CONTROL(0x01) [UVC1.5, p. 161], GET_CUR(0x81) [UVC1.5, p.158]
        libusb_control_transfer(handle, 0xa1, 0x81, 0x0100, 0x0001, buf, 48, TIMEOUT);
        for (i=0; i<48; i++) { printf("%x ", buf[i]); } printf("\n");

        // VS_COMMIT_CONTROL(0x02) [UVC1.5, p. 161], SET_CUR(0x01) [UVC1.5, p.158]
        libusb_control_transfer(handle, 0x21, 0x01, 0x0200, 0x0001, buf, 48, TIMEOUT);
        for (i=0; i<48; i++) { printf("%x ", buf[i]); } printf("\n");

        // VS_COMMIT_CONTROL(0x02) [UVC1.5, p. 161], GET_CUR(0x81) [UVC1.5, p.158]
        //libusb_control_transfer(handle, 0xa1, 0x81, 0x0200, 0x0001, buf, 48, TIMEOUT);
        //for (i=0; i<48; i++) { printf("%x ", buf[i]); } printf("\n");


        // set interface, set alt interface [USB2.0, p. 250]
        // are available through synchronous, blocking function
        // in the libusb, so can not use libusb_control_transfer.

        // claim an interface in a given libusb_handle.
        if (libusb_claim_interface(handle, IfNum) != 0)
        {
                fprintf(stderr, "Claim interface failed.");
        }

        // activate an alternate setting for an interface.
        if (libusb_set_interface_alt_setting(handle, IfNum, AltIfNum) != 0)
        {
                fprintf(stderr, "Activate an alternate setting failed.");
        }

        // cam LED is lit here. it looks like ready to send the data.
        //while (1) {}


        // ------------------------------------------------------------
        // do an isochronous transfer

        /* High-speed
         * 1024 bytes data payloads
         * 1 microframe takes 125 us (8 times per frame).
         * upto 3 transfer per microframe.
         * 8 3 1024 1000 ~ 
         */

#define PKT_LEN        0x1400
#define PKTS_PER_XFER  8

        struct libusb_transfer *xfer;

        xfer = libusb_alloc_transfer(PKTS_PER_XFER);
        uint8_t *data = malloc(PKT_LEN*PKTS_PER_XFER);

        libusb_fill_iso_transfer(
                xfer, handle, 0x82, // Interface 1 Alt 1 Endpoint 0 Address 0x82
                data, PKT_LEN*PKTS_PER_XFER, PKTS_PER_XFER,
                cb, NULL, TIMEOUT);
            
        if ( (rcv = libusb_submit_transfer(xfer)) != 0)
        {
                fprintf(stderr, "failed to submit transfer: %d\n", rcv);
        }

        sleep(30);

        // if we detached kernel driver, reattach.
        if (attached == 1) {
                libusb_attach_kernel_driver(handle, 0);
        }

        libusb_close(handle);

    	libusb_free_device_list(deviceLst, 1);
    	libusb_exit(ctx);
}


------------------------------------------------------------
Interface 1
  ...
  bDescriptorSubType = 0x01 <VS_INPUT_HEADER>
  ...
  bDescriptorSubType = 0x04 <VS_FORMAT_UNCOMPRESSED>. (bFormatIndex: 0x01)
  ...
  bDescriptorSubType = 0x05 <VS_FRAME_UNCOMPRESSED>. (bFrameIndex: 0x01)
  ...

Interface 1 Alt 1
  bLength = 0x0009 
  bDescriptorType = 0x0004 
  bInterfaceNumber = 0x0001 
  bAlternateSetting = 0x0001 
  bNumEndpoints = 0x0001 
  bInterfaceClass = 0x000e <CC_VIDEO> [UVC1.5, p. 156]
  bInterfaceSubClass = 0x0002 <SC_VIDEOSTREAMING> [UVC1.5, p. 156]
  bInterfaceProtocol = 0x0000 <PC_PROTOCOL_UNDEFINED> [UVC1.5, p. 156]
  iInterface = 0x0004  <PC Camera> (read from index of string descriptor 4)

  Endpoint 0
     bLength = 0x0007 
     bDescriptorType = 0x0005 <ENDPOINT> [USB2.0, p. 251, 269-270]
     bEndpointAddress = 0x0082  <IN>
     bmAttributes = 0x0005  <ASYNC-ISOCHRONOUS>
     wMaxPacketSize = 0x1400 
     bInterval = 0x0001 
     bRefresh = 0x0000 
     bSynchAddress = 0x0000 


------------------------------------------------------------
$ sysctl hw.usb.debug=1
$ ./ex10
1 0 1 1 40 4b 4c 0 30 0 62 40 0 0 0 0 1 0 0 0 0 0 0 0 0 c8 61 40 0 0 0 0 90 6c a3 40 0 0 0 0 90 d2 ff ff ff 7f 0 0 
1 0 1 1 d0 12 13 0 0 0 0 0 0 0 0 0 0 0 0 60 9 0 0 c 0 0 61 40 0 0 0 0 90 6c a3 40 0 0 0 0 90 d2 ff ff ff 7f 0 0 
1 0 1 1 d0 12 13 0 0 0 0 0 0 0 0 0 0 0 0 60 9 0 0 c 0 0 61 40 0 0 0 0 90 6c a3 40 0 0 0 0 90 d2 ff ff ff 7f 0 0 
$ sysctl hw.usb.debug=0
$ fgrep 'bEndpointAddress=0x82' /var/log/messages


------------------------------------------------------------
kernel: usb_dump_endpoint: endpoint=0xfffffe00781f7a50 edesc=0xfffffe0007cd3704 isoc_next=112 toggle_next=0 bEndpointAddress=0x82
kernel: usb_dump_queue: endpoint=0xfffffe00781f7a50 xfer: 
kernel: usbd_transfer_submit: open
kernel: usbd_pipe_enter: enter
kernel: usbd_pipe_start: start
kernel: usbd_transfer_done: err=USB_ERR_NORMAL_COMPLETION
kernel: usbd_callback_wrapper_sub: xfer=0xffffff8002e28148 endpoint=0xfffffe00781f7a50 sts=0 alen=0, slen=0, afrm=8, nfrm=8
kernel: usbd_transfer_done: err=USB_ERR_NORMAL_COMPLETION
kernel: usbd_callback_wrapper_sub: xfer=0xfffffe00077f6948 endpoint=0xfffffe0007920a80 sts=0 alen=4, slen=4, afrm=1, nfrm=1
kernel: usbd_transfer_submit: xfer=0xfffffe00077f6948, endpoint=0xfffffe0007920a80, nframes=1, dir=read
kernel: usb_dump_endpoint: endpoint=0xfffffe0007920a80 edesc=0xfffffe000792951b isoc_next=0 toggle_next=0 bEndpointAddress=0x81
kernel: usb_dump_queue: endpoint=0xfffffe0007920a80 xfer: 
kernel: usbd_pipe_enter: enter
kernel: usbd_pipe_start: start
...
kernel: usbd_pipe_enter: enter
kernel: usbd_pipe_start: start
kernel: usbd_do_request_flags: Handle Request function is set
last message repeated 9 times

---
SAITOU Toshihide



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121029.215434.122618874.toshi>