📄 zc030x_isochron.c
字号:
{ PDEBUG(2, "data error: [%d] len=%d, status=%d", i, datalength, st); } /* Skip any zero length block or non selected frame buffer */ /* TODO I think this is a bug so I need to check this */ if (datalength <= 0 || dev->curframe < 0) continue; /* ...else packet data available -> cdata points to packet data! */ cData = ((unsigned char *) urb->transfer_buffer) + urb->iso_frame_desc[i].offset; /* Save the previous pointer */ if (urb->transfer_buffer == NULL || urb->iso_frame_desc[i].offset >= ISO_BUFFER_SIZE) { PDEBUG(2, "URB error: [%d] len=%d, status=%d", i, urb->iso_frame_desc[i].offset, st); continue; } /* Now, we can check if we have had a frame to decode */ /* TODO: frame dropping, frame error handling */ /* Andrew got an idea about this... (interrupt messages?) */ /* Check if we find a SOI marker... */ if( ((*((int *)cData)) & 0xFFFF) == 0xD8FF ) { /* We might be on a next frame */ /* If the frame we've received is filled, it's the case */ /* Lock it before accessing it */ if(down_trylock(&frame->Lock)) { return -ENOBUFS; } if (frame->SeqNumber > 1 && frame->GrabState != FRAME_ERROR) { /* Found so debug it */ PDEBUG(5,"frame compressed size: %d %p",frame->CompLen, frame->CompData); /* Schedule tasklet to decode this frame */ /* Launch the tasklet to decode it */ tasklet_init(&decodetasklet, decode_tasklet, (unsigned long)frame); up(&frame->Lock); tasklet_schedule(&decodetasklet); PDEBUG(5, "Scheduled the decode tasklet"); // If someone decided to wait for ANY frame - wake him up if (waitqueue_active(&dev->wq)) wake_up_interruptible(&dev->wq); PDEBUG(5, "Now changing the frame"); /* Get a new frame now */ /* Get the frame */ frame = zc030x_get_free_frame_tmp(dev); /* And check it */ if(frame == NULL) { PDEBUG(2, "Error while locking the buffer or frame %p", frame); return -ENOBUFS; } PDEBUG(5, "DUMPIN Frame changed to %d", dev->curframe); if(down_trylock(&frame->Lock)) { return -ENOBUFS; } } /* Read pseudo header data */ /* TODO: For PPC should make endianness independant code */ frame->SeqNumber = ((int)cData[8]<<8) | (int)cData[9]; frame->Width = ((int)cData[12]<<8) | (int)cData[13]; frame->Height = ((int)cData[14]<<8) | (int)cData[15]; frame->HeaderWidth = frame->Width; frame->HeaderHeight = frame->Height; frame->Format = dev->VideoFormat; frame->Depth = zc030x_v4l_getdepth(dev->VideoFormat); /* Unlock it */ up(&frame->Lock); /* Debug the result */ PDEBUG(5,"***SOI FOUND, seqno:%d, width:%d, height:%d", frame->SeqNumber, frame->Width, frame->Height); } /* And copy the buffer */ /* Lock it before accessing it */ if(down_trylock(&frame->Lock)) { return -ENOBUFS; } /* Check the copy first */ if (frame->CompData == NULL || (frame->CompLen + datalength) >= MAX_VIDEODATA_SIZE / 4) { /* Buffer too small, maybe it could be good to increase their size */ PDEBUG(2, "Error : Frame buffers too small, %d needed (%d available)", (frame->CompLen + datalength), MAX_VIDEODATA_SIZE / 4); PDEBUG(2, "Error : Frame will be erroneous"); frame->GrabState = FRAME_ERROR; } else { /* Copy the urb data into the frame */ memcpy(frame->CompData + frame->CompLen, cData, datalength); /* Advance pointers */ frame->CompLen += datalength; } /* Unlock it */ up(&frame->Lock); /* Increase the total length */ totlen += datalength; } /* UnLock the buffers */ return(totlen);}/* Isochronous transfers callback */#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)void zc030x_isoc_handler (struct urb *urb)#elsevoid zc030x_isoc_handler (struct urb *urb, struct pt_regs *prgx)#endif{ /* Get the device pointer */ struct usb_zc030x *dev = (struct usb_zc030x *)urb->context; /* Check input */ if (!dev) { PDEBUG (4, "isoc handler: no context!\n"); return; } /* Check if isochronous transfers have started */ if (!dev->streaming) { PDEBUG(4, "isoc handler: not streaming, but got interrupt"); return; } /* copy received data to a frame buffer */ zc030x_move_data(dev, urb); /* Set the current buffer to the next one */ dev->cursbuf = (dev->cursbuf + 1) % MAX_ISO_BUFS; // IS THIS NEEDED? SOME CODE I FOUND DO THAT // // urb->dev = dev->udev; // for (i = 0; i < ISO_FRAMES_PER_DESC; i++) { // urb->iso_frame_desc[i].status = 0; // } // urb->context = dev; // urb->status = 0; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) // wtf does this? { /* Declare iterator */ int i = 0; /* Submit ack to the transfers ? */ urb->dev = dev->udev; if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { PDEBUG(4, "Err usb_submit_urb ret %d\n", i); } }#endif}/* Start the isochronous transfers */int zc030x_isoc_start (struct usb_zc030x *dev){ /* Iterators */ int i, j; /* Return value */ int ret = 0; /* Urb to submit */ struct urb *urb = NULL; /* Get the usb device pointer */ struct usb_device *udev; /* Check arguments */ if (dev == NULL) { PDEBUG(1,"Error no dev!!"); return -ENODEV; } udev = dev->udev; if (udev == NULL) { PDEBUG(1,"Error no udev!!!"); return -ENODEV; } /* Check for available isochronous buffers */ if (dev->sbuf == NULL) { PDEBUG(1,"Error no dev->sbuf!!!"); return -ENODEV; } /* Debug this */ PDEBUG (3, ">> [ZCISO] Starting !"); /* Look for a free urb */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (dev->sbuf[i].urb == NULL) { PDEBUG(1,"Error no dev->sbuf[%d].urb, allocate them now!!!",i); if (zc030x_allocate_urbs(dev) < 0) return -ENODEV; } } /* Set streaming variables */ down(&dev->buf_lock); dev->cursbuf = 0; dev->curframe = 0; dev->streaming = 0; /* Send the gamma matrix */ zc030x_send_gamma(dev->udev, dev->Brightness, dev->Contrast, dev->Gamma); /* Init URB structure */ for (i = 0; i < MAX_ISO_BUFS; i++) { urb = dev->sbuf[i].urb; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) urb->next = dev->sbuf[(i + 1) % MAX_ISO_BUFS].urb; #endif urb->dev = udev; urb->pipe = usb_rcvisocpipe (udev, dev->isocend); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->sbuf[i].data; urb->transfer_buffer_length = ISO_BUFFER_SIZE; urb->complete = zc030x_isoc_handler; urb->context = dev; urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; urb->interval = 1; /* Get an offset */ for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; } } /* All is done... */ dev->streaming = 1; /* Set the first frame state, application will use more buffer if it wants to */ dev->frame[0].GrabState = FRAME_GRABBING; dev->frame[1].GrabState = FRAME_READY; dev->frame[2].GrabState = FRAME_UNUSED; dev->frame[3].GrabState = FRAME_UNUSED; /* link iso buffers*/ for (i = 0; i < MAX_ISO_BUFS; i++) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ret = usb_submit_urb (dev->sbuf[i].urb); #else ret = usb_submit_urb (dev->sbuf[i].urb, GFP_ATOMIC); #endif if (ret) { PDEBUG (5, "Submit_urb %d failed with error %d\n", i, ret); } else { PDEBUG (5, "URB 0x%p submitted.\n", dev->sbuf[i].urb); } } up(&dev->buf_lock); PDEBUG (3, "<< [ZCISO] Started!"); return 0;}/* Stop the isochronous transfers */int zc030x_isoc_stop (struct usb_zc030x *dev){ /* URB object */ struct urb *urb; /* Iterator */ int i; /* Debug this functions */ PDEBUG(3,">> [ZCISO] Stopping!"); /* Loop through iso buffers */ for (i = MAX_ISO_BUFS -1; i >= 0; i--) { urb = dev->sbuf[i].urb; if (urb != 0) { /* TODO If streaming unlink the urb before freeing it */ if (dev->streaming) { PDEBUG (5, "Unlinking URB %p\n", urb); usb_unlink_urb (urb); } PDEBUG (5, "Freeing URB\n"); usb_free_urb (urb); dev->sbuf[i].urb = NULL; } } dev->streaming = 0; /* Okay, return */ PDEBUG(3,"<< [ZCISO] Stopped!"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -