Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/uvc.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include <drivers/usb/usb.h>
0019 #include <drivers/usb/uhci.h>
0020 #include <drivers/usb/uvc.h>
0021 #include <arch/i386.h>
0022 #include <util/printf.h>
0023 #include <kernel.h>
0024 #include <sched/sched.h>
0025 
0026 #define DEBUG_UVC
0027 
0028 #ifdef DEBUG_UVC
0029 
0030 #define DLOG(fmt,...) DLOG_PREFIX("uvc",fmt,##__VA_ARGS__)
0031 
0032 #define printf com1_printf
0033 #define print com1_puts
0034 #define putx  com1_putx
0035 #define putchar com1_putc
0036 
0037 #else
0038 
0039 #define DLOG(fmt,...) ;
0040 #endif
0041 
0042 #define BUF_SIZE        38400
0043 #define PACKET_SIZE     944
0044 
0045 struct iso_data_source
0046 {
0047   uint8_t endp;
0048   uint16_t max_packet;
0049   uint32_t sample_size;
0050 };
0051 
0052 typedef struct iso_data_source ISO_DATA_SRC;
0053 
0054 static ISO_DATA_SRC iso_src;
0055 static uint8_t frame_buf[BUF_SIZE];
0056 static uint8_t jpeg_frame[BUF_SIZE];
0057 //static uint32_t uvc_test_stack[1024];
0058 
0059 bool usb_uvc_driver_init (void);
0060 static bool uvc_probe (USB_DEVICE_INFO *, USB_CFG_DESC *, USB_IF_DESC *);
0061 static bool uvc_init(USB_DEVICE_INFO *, USB_CFG_DESC *);
0062 static int video_probe_controls (USB_DEVICE_INFO *, uint8_t, uint8_t,
0063     UVC_VS_CTL_PAR_BLOCK *);
0064 static int video_commit_controls (USB_DEVICE_INFO *, uint8_t, uint8_t,
0065     UVC_VS_CTL_PAR_BLOCK *);
0066 static int video_ctl_error_code (USB_DEVICE_INFO *, uint8_t, uint8_t);
0067 static void para_block_dump (UVC_VS_CTL_PAR_BLOCK *);
0068 int uvc_get_frame (USB_DEVICE_INFO *, ISO_DATA_SRC *, uint8_t *,
0069     uint32_t, uint8_t *, uint32_t *);
0070 static void uvc_test (void);
0071 static int uvc_device_cfg (USB_DEVICE_INFO *, USB_CFG_DESC *,
0072     ISO_DATA_SRC *);
0073 
0074 static USB_DEVICE_INFO gdev; // --??-- Remove after test
0075 
0076 static void
0077 uvc_test (void)
0078 {
0079   DLOG("UVC Test starts!");
0080   uint32_t frm_len;
0081   int i = 0;
0082   uint32_t *dump = (uint32_t*)jpeg_frame;
0083 
0084   memset(frame_buf, 0, BUF_SIZE);
0085   memset(jpeg_frame, 0, BUF_SIZE);
0086   uvc_get_frame (&gdev, &iso_src, frame_buf, PACKET_SIZE, jpeg_frame, &frm_len);
0087   DLOG("Getting the first frame : %d bytes", frm_len);
0088   
0089   memset(frame_buf, 0, BUF_SIZE);
0090   memset(jpeg_frame, 0, BUF_SIZE);
0091   uvc_get_frame (&gdev, &iso_src, frame_buf, PACKET_SIZE, jpeg_frame, &frm_len);
0092   DLOG("Getting the second frame : %d bytes", frm_len);
0093 
0094   memset(frame_buf, 0, BUF_SIZE);
0095   memset(jpeg_frame, 0, BUF_SIZE);
0096   uvc_get_frame (&gdev, &iso_src, frame_buf, PACKET_SIZE, jpeg_frame, &frm_len);
0097   DLOG("Getting the third frame : %d bytes", frm_len);
0098 
0099   DLOG("Dumping the frame:");
0100 
0101   for(i = 1; i <= (frm_len / 4 + 1); i++) {
0102     putx(*dump);
0103     dump++;
0104     if ((i % 6) == 0) putchar('\n');
0105     if ((i % 96) == 0) putchar('\n');
0106   }
0107 
0108   for (;;)
0109     delay (1000);
0110 }
0111 
0112 int
0113 uvc_get_frame (
0114     USB_DEVICE_INFO * dev,
0115     ISO_DATA_SRC * iso_src,
0116     uint8_t * buf,
0117     uint32_t transfer_len,
0118     uint8_t * frame,
0119     uint32_t * frm_len)
0120 {
0121   int status = 0, i = 0, j = 0, act_len = 0;
0122   uint8_t * index;
0123   int counter = 0, header_len = 0;
0124 
0125   //DLOG("In uvc_get_frame!");
0126   *frm_len = 0;
0127 
0128   for (i = 0; i < 1024; i++) {
0129     index = buf + i * transfer_len;
0130 
0131     status += uhci_isochronous_transfer (dev->address, iso_src->endp,
0132         (addr_t) index, transfer_len, &act_len, i, DIR_IN, 0);
0133 
0134     header_len = *(index);
0135     *frm_len += (act_len - header_len);
0136 
0137 #if 0
0138     DLOG("Actual length received : %d, header : %d, frame : %d",
0139         act_len, header_len, *frm_len);
0140 #endif
0141 
0142     for (j = 0; j < (act_len - header_len); j++) {
0143       *(frame + counter) = *(index + header_len + j);
0144       counter ++;
0145     }
0146 
0147     /* Now, we only retreive one frame. Check EOF in the header */
0148     if ((*(index + 1)) & 0x02) {
0149       //DLOG("End of frame reached!");
0150       break;
0151     }
0152   }
0153 
0154   DLOG("%d TDs used for one frame", i + 1);
0155 
0156   return status;
0157 }
0158 
0159 static bool
0160 uvc_init (USB_DEVICE_INFO * dev, USB_CFG_DESC * cfg)
0161 {
0162   USB_SPD_CFG_DESC *scfgd;
0163   UVC_VS_CTL_PAR_BLOCK par;
0164   uint8_t tmp[1300];
0165 
0166   DLOG("Configuring UVC device ...");
0167 
0168   gdev = *dev; // --??-- Remove after test
0169 
0170   if (uvc_device_cfg(dev, cfg, &iso_src) == -1) {
0171     DLOG("Device Configuration Failed!");
0172     return FALSE;
0173   }
0174 
0175   /* Set data source info manually for now */
0176   iso_src.endp = 1;
0177   iso_src.max_packet = PACKET_SIZE;
0178   iso_src.sample_size = 0;
0179 
0180   memset(tmp, 0, 1300);
0181   memset(&par, 0, sizeof(UVC_VS_CTL_PAR_BLOCK));
0182 
0183   DLOG("Now, getting other speed configuration.");
0184   if (usb_get_descriptor(dev, USB_TYPE_SPD_CFG_DESC, 0, 0, 9, (addr_t)tmp)) {
0185     DLOG("Other Speed Configuration is not presented.");
0186   } else {
0187     scfgd = (USB_SPD_CFG_DESC *)tmp;
0188     DLOG("Other Speed Configuration:");
0189     DLOG("  bLength : 0x%x  bDescriptorType : 0x%x  wTotalLength : 0x%x",
0190         scfgd->bLength, scfgd->bDescriptorType, scfgd->wTotalLength);
0191     DLOG("  bNumInterfaces : 0x%x  bConfigurationValue : 0x%x",
0192         scfgd->bNumInterfaces, scfgd->bConfigurationValue);
0193   }
0194 
0195   /* There is only one configuration in Logitech Webcam Pro 9000 */
0196   DLOG("Set configuration to %d.", cfg->bConfigurationValue);
0197   usb_set_configuration(dev, cfg->bConfigurationValue);
0198 
0199   /* Now, negotiate with VS interface for streaming parameters */
0200 
0201   /* Manually set parameters */
0202   par.bmHint = 1; // Frame Interval Fixed
0203   par.bFormatIndex = 2;
0204   par.bFrameIndex = 4;
0205   //par.dwFrameInterval = 0x61A80; // 25FPS
0206   par.dwFrameInterval = 0xF4240; // 10FPS
0207   //par.wCompQuality = 5000; // 1 - 10000, with 1 the lowest
0208   //par.dwMaxPayloadTransferSize = 512;
0209 
0210   if (video_probe_controls (dev, SET_CUR, 1, &par)) {
0211     DLOG("Initial negotiation failed during probe");
0212   }
0213 
0214   memset(&par, 0, sizeof(UVC_VS_CTL_PAR_BLOCK));
0215 
0216   if (video_probe_controls (dev, GET_CUR, 1, &par)) {
0217     DLOG("Getting current state during probe failed");
0218   }
0219   para_block_dump (&par);
0220 
0221   if (video_commit_controls (dev, SET_CUR, 1, &par)) {
0222     DLOG("Setting device state during probe failed");
0223   }
0224   memset(&par, 0, sizeof(UVC_VS_CTL_PAR_BLOCK));
0225 
0226   if (video_commit_controls (dev, GET_CUR, 1, &par)) {
0227     DLOG("Setting device state during probe failed");
0228   }
0229   para_block_dump (&par);
0230 
0231   /* Select Alternate Setting 2 for interface 1 (Std VS interface) */
0232   /* This is for an isochronous endpoint with MaxPacketSize 384 */
0233   DLOG("Select Alternate Setting 2 for VS interface");
0234   if (usb_set_interface(dev, 6, 1)) {
0235     DLOG("Cannot configure interface setting for Std VS interface");
0236     return FALSE;
0237   }
0238 
0239   delay(1000);
0240   delay(1000);
0241   delay(1000);
0242   delay(1000);
0243   delay(1000);
0244   delay(1000);
0245 
0246   return TRUE;
0247 }
0248 
0249 static bool
0250 uvc_probe (USB_DEVICE_INFO *dev, USB_CFG_DESC *cfg, USB_IF_DESC *ifd)
0251 {
0252   /* Avoid multi-entrance in uhci_enumerate(), should be removed soon */
0253   static int entrance = 0;
0254   if (entrance) return FALSE;
0255 
0256   /* For now, we only support device with multi video interface
0257    * collections. This is ugly. But let's make Logitech Webcam Pro
0258    * 9000 work first.
0259    */
0260   if(!(dev->devd.bDeviceClass == 0xEF) ||
0261      !(dev->devd.bDeviceSubClass == 0x02) ||
0262      !(dev->devd.bDeviceProtocol == 0x01)) {
0263     return FALSE;
0264   }
0265 
0266 #if 0
0267   /* Dumping UVC device descriptors */
0268   desc_dump (dev, cfg);
0269 #endif
0270 
0271   if (uvc_init(dev, cfg) == FALSE) {
0272     DLOG("Device configuration failed!");
0273     return FALSE;
0274   }
0275 
0276   //start_kernel_thread((uint)uvc_test, (uint)&uvc_test_stack[1023]);
0277   uvc_test ();
0278 
0279 #if 0
0280   int i = 0;
0281   uint32_t *dump = (uint32_t*)frame_buf;
0282   memset(frame_buf, 0, 38400);
0283 
0284   uvc_get_frame (dev, &iso_src, (addr_t) frame_buf, 384);
0285 
0286   for(i = 1; i <= 9600; i++) {
0287     putx(*dump);
0288     dump++;
0289     if ((i % 6) == 0) putchar('\n');
0290     if ((i % 96) == 0) putchar('\n');
0291   }
0292 #endif
0293 
0294   /* Avoid multi-entrance in uhci_enumerate(), should be removed soon */
0295   entrance++;
0296 
0297   return TRUE;
0298 }
0299 
0300 static int
0301 video_ctl_error_code (
0302     USB_DEVICE_INFO * dev,
0303     uint8_t request,
0304     uint8_t interface)
0305 {
0306   USB_DEV_REQ setup_req;
0307   uint8_t code, status;
0308 
0309   setup_req.bmRequestType = 0xA1;
0310   setup_req.bRequest = request;
0311   setup_req.wValue = VC_REQUEST_ERROR_CODE_CONTROL << 8;
0312   setup_req.wIndex = interface;
0313   setup_req.wLength = 1;
0314 
0315   status = usb_control_transfer (dev, (addr_t) & setup_req,
0316       sizeof (USB_DEV_REQ), (addr_t) & code, 1);
0317 
0318   if (status) {DLOG("Getting error code failed!"); return 0xFF;}
0319 
0320   return code;
0321 }
0322 
0323 static int
0324 video_probe_controls (
0325     USB_DEVICE_INFO * dev,
0326     uint8_t request,
0327     uint8_t interface,
0328     UVC_VS_CTL_PAR_BLOCK * par)
0329 {
0330   USB_DEV_REQ setup_req;
0331   if (request == SET_CUR)
0332     setup_req.bmRequestType = 0x21;
0333   else
0334     setup_req.bmRequestType = 0xA1;
0335   setup_req.bRequest = request;
0336   setup_req.wValue = VS_PROBE_CONTROL << 8;
0337   setup_req.wIndex = interface;
0338   //setup_req.wLength = sizeof(UVC_VS_CTL_PAR_BLOCK);
0339   setup_req.wLength = 26; // Why? It should be 34! Odd...
0340 
0341   return usb_control_transfer (dev, (addr_t) & setup_req,
0342       sizeof (USB_DEV_REQ), (addr_t) par, setup_req.wLength);
0343 }
0344 
0345 static int
0346 video_commit_controls (
0347     USB_DEVICE_INFO * dev,
0348     uint8_t request,
0349     uint8_t interface,
0350     UVC_VS_CTL_PAR_BLOCK * par)
0351 {
0352   USB_DEV_REQ setup_req;
0353   if (request == SET_CUR)
0354     setup_req.bmRequestType = 0x21;
0355   else
0356     setup_req.bmRequestType = 0xA1;
0357   setup_req.bRequest = request;
0358   setup_req.wValue = VS_COMMIT_CONTROL << 8;
0359   setup_req.wIndex = interface;
0360   //setup_req.wLength = sizeof(UVC_VS_CTL_PAR_BLOCK);
0361   setup_req.wLength = 26; // Why? It should be 34! Odd...
0362 
0363   return usb_control_transfer (dev, (addr_t) & setup_req,
0364       sizeof (USB_DEV_REQ), (addr_t) par, setup_req.wLength);
0365 }
0366 
0367 static USB_DRIVER uvc_driver = {
0368   .probe = uvc_probe
0369 };
0370 
0371 bool
0372 usb_uvc_driver_init (void)
0373 {
0374   return usb_register_driver (&uvc_driver);
0375 }
0376 
0377 static void
0378 para_block_dump (UVC_VS_CTL_PAR_BLOCK * par)
0379 {
0380   DLOG ("Parameter Block Dump: ");
0381   DLOG ("  bmHint : 0x%x", par->bmHint);
0382   DLOG ("  bFormatIndex : 0x%x", par->bFormatIndex);
0383   DLOG ("  bFrameIndex : 0x%x", par->bFrameIndex);
0384   DLOG ("  dwFrameInterval : 0x%x", par->dwFrameInterval);
0385   DLOG ("  wKeyFrameRate : 0x%x", par->wKeyFrameRate);
0386   DLOG ("  wPFrameRate : 0x%x", par->wPFrameRate);
0387   DLOG ("  wCompQuality : 0x%x", par->wCompQuality);
0388   DLOG ("  wCompWindowSize : 0x%x", par->wCompWindowSize);
0389   DLOG ("  wDelay : 0x%x", par->wDelay);
0390   DLOG ("  dwMaxVideoFrameSize : 0x%x", par->dwMaxVideoFrameSize);
0391   DLOG ("  dwMaxPayloadTransferSize : 0x%x", par->dwMaxPayloadTransferSize);
0392   DLOG ("  dwClockFrequency : 0x%x", par->dwClockFrequency);
0393   DLOG ("  bmFramingInfo : 0x%x", par->bmFramingInfo);
0394   DLOG ("  bPreferedVersion : 0x%x", par->bPreferedVersion);
0395   DLOG ("  bMinVersion : 0x%x", par->bMinVersion);
0396   DLOG ("  bMaxVersion : 0x%x", par->bMaxVersion);
0397 }
0398 
0399 static int
0400 uvc_device_cfg (
0401     USB_DEVICE_INFO *dev,
0402     USB_CFG_DESC *cfg,
0403     ISO_DATA_SRC * src)
0404 {
0405   /* Dump all the descriptors retreived from UVC device */
0406   uint8_t conf[1300];
0407   int index = 0, tmp_index = 0;
0408 
0409   USB_DEV_DESC *desc;
0410   UVC_IA_DESC *iad;
0411   USB_IF_DESC *vcifd, *vsifd;
0412   UVC_CSVC_IF_HDR_DESC *csvcifd;
0413   UVC_CSVS_IF_HDR_DESC *csvsifd;
0414   UVC_IN_TERM_DESC *intd;
0415   UVC_OUT_TERM_DESC *outd;
0416   UVC_MJPEG_FORMAT_DESC *jpegfd;
0417   UVC_MJPEG_FRAME_DESC *jpegrd;
0418   USB_EPT_DESC *videoept;
0419 
0420   typedef struct uvc_desc_idx {
0421     uint8_t bLength;
0422     uint8_t bDescriptorType;
0423     uint8_t bDescriptorSubType;
0424   } UVC_DESC_IDX;
0425 
0426   UVC_DESC_IDX * desc_idx;
0427 
0428   desc = &(dev->devd);
0429   usb_get_descriptor(dev, USB_TYPE_CFG_DESC, 0, 0, cfg->wTotalLength, (addr_t)conf);
0430 
0431   /* Parsing all UVC specific descriptors */
0432   /* Get the first IAD */
0433   DLOG("Getting IAD ...");
0434   index += cfg->bLength;
0435   iad = (UVC_IA_DESC*)(&conf[index]);
0436 
0437   if ((iad->bDescriptorType != USB_TYPE_IA_DESC) ||
0438       (iad->bFunctionClass != CC_VIDEO) ||
0439       (iad->bFunctionSubClass != SC_VIDEO_INTERFACE_COLLECTION)) {
0440     DLOG("IAD not found after configuration descriptor.");
0441     return -1;
0442   } else {
0443     DLOG("Found Video Interface Collection");
0444     DLOG("  bFirstInterface : 0x%x", iad->bFirstInterface);
0445     DLOG("  bInterfaceCount : 0x%x", iad->bInterfaceCount);
0446   }
0447 
0448   /* Get First VC Interface Descriptor */
0449   DLOG("Getting VC Interface Descriptor ...");
0450   while (index < cfg->wTotalLength) {
0451     desc_idx = (UVC_DESC_IDX *)(&conf[index]);
0452     if (desc_idx->bDescriptorType != USB_TYPE_IF_DESC)
0453       index += desc_idx->bLength;
0454     else
0455       break;
0456   }
0457 
0458   if (index >= cfg->wTotalLength) {
0459     DLOG("Descriptor parsing error!");
0460     return -1;
0461   }
0462 
0463   vcifd = (USB_IF_DESC *)(&conf[index]);
0464 
0465   if ((vcifd->bDescriptorType != USB_TYPE_IF_DESC) ||
0466       (vcifd->bInterfaceClass != CC_VIDEO) ||
0467       (vcifd->bInterfaceSubClass != SC_VIDEOCONTROL)) {
0468     DLOG("Standard VC Interface Descriptor cannot be found");
0469     return -1;
0470   } else {
0471     DLOG("Found Standard VC Interface");
0472     DLOG("  bInterfaceNumber : 0x%x", vcifd->bInterfaceNumber);
0473     DLOG("  bAlternateSetting : 0x%x", vcifd->bAlternateSetting);
0474     if (vcifd->bNumEndpoints)
0475       DLOG("  Status interrupt endpoint is present");
0476     else
0477       DLOG("  Status interrupt endpoint is not present");
0478   }
0479 
0480   /* Get Class-specific VC Interface header descriptor */
0481   DLOG("Getting Class-specific VC Interface Descriptor ...");
0482   while (index < cfg->wTotalLength) {
0483     desc_idx = (UVC_DESC_IDX *)(&conf[index]);
0484     if ((desc_idx->bDescriptorType != CS_INTERFACE) ||
0485         (desc_idx->bDescriptorSubType != VC_HEADER))
0486       index += desc_idx->bLength;
0487     else
0488       break;
0489   }
0490 
0491   if (index >= cfg->wTotalLength) {
0492     DLOG("Descriptor parsing error!");
0493     return -1;
0494   }
0495 
0496   csvcifd = (UVC_CSVC_IF_HDR_DESC *)(&conf[index]);
0497 
0498   DLOG("Found Class-specific VC Interface Header");
0499   DLOG("  wTotalLength : 0x%x", csvcifd->wTotalLength);
0500   DLOG("  bInCollection : 0x%x", csvcifd->bInCollection);
0501 
0502   /* Get Input and Output Terminals */
0503   DLOG("Getting Input and Output Terminals ...");
0504   tmp_index = index;
0505   index += csvcifd->wTotalLength;
0506   while (tmp_index < index) {
0507     desc_idx = (UVC_DESC_IDX *)(&conf[tmp_index]);
0508 
0509     if ((desc_idx->bDescriptorType == CS_INTERFACE) &&
0510         (desc_idx->bDescriptorSubType == VC_INPUT_TERMINAL)) {
0511       intd = (UVC_IN_TERM_DESC *)(&conf[tmp_index]);
0512       DLOG("Found Input Terminal");
0513       DLOG("  bTerminalID : 0x%x", intd->bTerminalID);
0514       DLOG("  wTerminalType : 0x%x", intd->wTerminalType);
0515       DLOG("  bAssocTerminal : 0x%x", intd->bAssocTerminal);
0516     }
0517 
0518     if ((desc_idx->bDescriptorType == CS_INTERFACE) &&
0519         (desc_idx->bDescriptorSubType == VC_OUTPUT_TERMINAL)) {
0520       outd = (UVC_OUT_TERM_DESC *)(&conf[tmp_index]);
0521       DLOG("Found Output Terminal");
0522       DLOG("  bTerminalID : 0x%x", outd->bTerminalID);
0523       DLOG("  wTerminalType : 0x%x", outd->wTerminalType);
0524       DLOG("  bAssocTerminal : 0x%x", outd->bAssocTerminal);
0525       DLOG("  bSourceID : 0x%x", outd->bSourceID);
0526     }
0527 
0528     /* Multiple Processing or Extension Units may exist here */
0529 
0530     tmp_index += desc_idx->bLength;
0531   }
0532 
0533   /* We may have Standard and Class-specific Interrupt Endpoint
0534    * Descriptors after the Class-specific VC Interface Descriptor.
0535    * Just ignore them for now!
0536    */
0537 
0538   /* Get Standard VS Interface */
0539   DLOG("Getting Standard VS Interface ...");
0540   while (index < cfg->wTotalLength) {
0541     desc_idx = (UVC_DESC_IDX *)(&conf[index]);
0542     if (desc_idx->bDescriptorType != USB_TYPE_IF_DESC)
0543       index += desc_idx->bLength;
0544     else
0545       break;
0546   }
0547 
0548   if (index >= cfg->wTotalLength) {
0549     DLOG("Descriptor parsing error!");
0550     return -1;
0551   }
0552 
0553   vsifd = (USB_IF_DESC *)(&conf[index]);
0554 
0555   if ((vsifd->bDescriptorType != USB_TYPE_IF_DESC) ||
0556       (vsifd->bInterfaceClass != CC_VIDEO) ||
0557       (vsifd->bInterfaceSubClass != SC_VIDEOSTREAMING)) {
0558     DLOG("Standard VS Interface Descriptor cannot be found");
0559     return -1;
0560   } else {
0561     DLOG("Found Standard VS Interface");
0562     DLOG("  bInterfaceNumber : 0x%x", vsifd->bInterfaceNumber);
0563     DLOG("  bAlternateSetting : 0x%x", vsifd->bAlternateSetting);
0564     DLOG("  bNumEndpoints : 0x%x", vsifd->bNumEndpoints);
0565   }
0566 
0567   /* Get Class-Specific VS Interface Input Header Descriptor */
0568   DLOG("Getting Class-Specific VS Interface Input Header ...");
0569   while (index < cfg->wTotalLength) {
0570     desc_idx = (UVC_DESC_IDX *)(&conf[index]);
0571     if ((desc_idx->bDescriptorType != CS_INTERFACE) ||
0572         (desc_idx->bDescriptorSubType != VS_INPUT_HEADER))
0573       index += desc_idx->bLength;
0574     else
0575       break;
0576   }
0577 
0578   if (index >= cfg->wTotalLength) {
0579     DLOG("Descriptor parsing error!");
0580     return -1;
0581   }
0582 
0583   csvsifd = (UVC_CSVS_IF_HDR_DESC *)(&conf[index]);
0584 
0585   DLOG("Found Class-specific VS Interface Input Header");
0586   DLOG("  bNumFormats : 0x%x", csvsifd->bNumFormats);
0587   DLOG("  wTotalLength : 0x%x", csvsifd->wTotalLength);
0588   DLOG("  bEndpointAddress : 0x%x", csvsifd->bEndpointAddress);
0589   DLOG("  bTerminalLink : 0x%x", csvsifd->bTerminalLink);
0590 
0591   /* Try to get MJPEG format and frame info */
0592   DLOG("Getting MJPEG Format and Frame Info ...");
0593   tmp_index = index;
0594   index += csvsifd->wTotalLength;
0595 
0596   while (tmp_index < index) {
0597     desc_idx = (UVC_DESC_IDX *)(&conf[tmp_index]);
0598     if ((desc_idx->bDescriptorType != CS_INTERFACE) ||
0599         (desc_idx->bDescriptorSubType != VS_FORMAT_MJPEG)) {
0600       tmp_index += desc_idx->bLength;
0601     } else break;
0602   }
0603 
0604   jpegfd = (UVC_MJPEG_FORMAT_DESC *)(&conf[tmp_index]);
0605 
0606   if (tmp_index >= index) {
0607     DLOG("Motion-JPEG format is not supported");
0608     return -1;
0609   } else {
0610     DLOG("Motion-JPEG format is supported");
0611     DLOG("  bFormatIndex : 0x%x", jpegfd->bFormatIndex);
0612     DLOG("  bNumFrameDescriptors : 0x%x", jpegfd->bNumFrameDescriptors);
0613     DLOG("  bDefaultFrameIndex : 0x%x", jpegfd->bDefaultFrameIndex);
0614     DLOG("  bCopyProtect : 0x%x", jpegfd->bCopyProtect);
0615   }
0616 
0617   tmp_index += jpegfd->bLength;
0618 
0619   /* Get all the frame descriptors pertaining to the format */
0620   while (tmp_index < index) {
0621     desc_idx = (UVC_DESC_IDX *)(&conf[tmp_index]);
0622     if ((desc_idx->bDescriptorType == CS_INTERFACE) &&
0623         (desc_idx->bDescriptorSubType == VS_FRAME_MJPEG)) {
0624       jpegrd = (UVC_MJPEG_FRAME_DESC *)(&conf[tmp_index]);
0625 
0626       DLOG("Found Motion-JPEG Frame Descriptor");
0627       DLOG("  bFrameIndex : 0x%x", jpegrd->bFrameIndex);
0628       DLOG("  The Minimum Bit Rate : %d", jpegrd->dwMinBitRate);
0629       DLOG("  The Maximum Bit Rate : %d", jpegrd->dwMaxBitRate);
0630       DLOG("  Maximum Frame Buffer : %d bytes",
0631           jpegrd->dwMaxVideoFrameBufferSize);
0632       DLOG("  The default interval : %d ns",
0633           jpegrd->dwDefaultFrameInterval * 100);
0634       DLOG("  The supported resolution : %d x %d",
0635           jpegrd->wWidth, jpegrd->wHeight);
0636     }
0637 
0638     tmp_index += desc_idx->bLength;
0639   }
0640 
0641   /* We could have parsed the Still Image Frame descriptor
0642    * and Color Matching Descriptor here. But for simplicity,
0643    * just skip them.
0644    */
0645 
0646   /* Get all the alternate settings for the VS interface above */
0647   DLOG("Getting possible alternate settings for VS interface ...");
0648   while (index < cfg->wTotalLength) {
0649     desc_idx = (UVC_DESC_IDX *)(&conf[index]);
0650 
0651     if (desc_idx->bDescriptorType == USB_TYPE_IA_DESC) {
0652       DLOG("Reach the end of the current VS interface");
0653       break;
0654     }
0655 
0656     if (desc_idx->bDescriptorType == USB_TYPE_IF_DESC) {
0657       vsifd = (USB_IF_DESC *)(&conf[index]);
0658 
0659       DLOG("Found Standard VS Interface");
0660       DLOG("  bInterfaceNumber : 0x%x", vsifd->bInterfaceNumber);
0661       DLOG("  bAlternateSetting : 0x%x", vsifd->bAlternateSetting);
0662       DLOG("  bNumEndpoints : 0x%x", vsifd->bNumEndpoints);
0663     }
0664 
0665     if (desc_idx->bDescriptorType == USB_TYPE_EPT_DESC) {
0666       videoept = (USB_EPT_DESC *)(&conf[index]);
0667 
0668       DLOG("Found Video Data Endpoint");
0669       DLOG("  bEndpointAddress : 0x%x", videoept->bEndpointAddress);
0670       DLOG("  bmAttributes : 0x%x", videoept->bmAttributes);
0671       if ((videoept->bmAttributes & 0xFC) == 1)
0672         DLOG("  This is an isochronous end point"); 
0673       if ((videoept->bmAttributes & 0xFC) == 2)
0674         DLOG("  This is a bulk end point"); 
0675       DLOG("  The max packet size is : %d bytes",
0676           videoept->wMaxPacketSize);
0677       DLOG("  bInterval : 0x%x", videoept->bInterval);
0678     }
0679 
0680     index += desc_idx->bLength;
0681   }
0682 
0683   DLOG("UVC device configuration finished");
0684 
0685   return 0;
0686 }
0687 
0688 #include "module/header.h"
0689 
0690 static const struct module_ops mod_ops = {
0691   .init = usb_uvc_driver_init
0692 };
0693 
0694 DEF_MODULE (usb___uvc, "USB video driver", &mod_ops, {"usb"});
0695 
0696 /*
0697  * Local Variables:
0698  * indent-tabs-mode: nil
0699  * mode: C
0700  * c-file-style: "gnu"
0701  * c-basic-offset: 2
0702  * End:
0703  */
0704 
0705 /* vi: set et sw=2 sts=2: */