isochronous transfer for UVC camera
SAITOU Toshihide
toshi at ruby.ocn.ne.jp
Mon Oct 29 13:18:13 UTC 2012
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 at 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
More information about the freebsd-usb
mailing list