123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- #include "shared.h"
- #include "urb.h"
- /****************************
- * ALTSETTING *
- ****************************/
- //Traverse the alternate setting list and find one that provides
- //the least bandwidth that satisfies the minimum requirement.
- int usbcam_choose_altsetting( struct driverInstance* this ){
-
- struct usb_interface *intf;
- const struct usb_host_interface *aintf;
- const struct usb_endpoint_descriptor* endpointDescriptor = NULL;
- int i, j;
-
- int endpointMaxPacketSize;
- int bandwidth;
- int best_alt = -1, best_alt_bw = 0;
-
- int interfaceNumber = this->urbstreamInterfaceNumber;
- int pipe = usb_rcvisocpipe( this->usbDevice, this->urbstreamEndpoint );
-
-
- if( atomic_read(&this->usbDeviceIsDisconnected) ){
- printk( KERN_WARNING "[%s] %s: device is disconnected\n", KBUILD_MODNAME, __FUNCTION__ );
- return -ENODEV;
- }
-
- if( interfaceNumber < 0 ) interfaceNumber = this->usbInterface->cur_altsetting->desc.bInterfaceNumber;
-
- intf = usb_ifnum_to_if( this->usbDevice, interfaceNumber );
- if( !intf ) {
- printk( KERN_WARNING "[%s] %s: interface %d does not exist\n", KBUILD_MODNAME, __FUNCTION__, interfaceNumber );
- return -ENODEV;
- }
-
- for (i = 0; i < intf->num_altsetting; i++) {
-
- aintf = &intf->altsetting[i];
- for (j = 0; j < aintf->desc.bNumEndpoints; j++) {
- endpointDescriptor = &aintf->endpoint[j].desc;
- if( (endpointDescriptor->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == usb_pipeendpoint(pipe) )break;
- }
-
- if ( j == aintf->desc.bNumEndpoints ) {
- //Desired endpoint not present in this descriptor
- printk( KERN_NOTICE "[%s] altsetting %d has no EP%d\n", KBUILD_MODNAME, i, usb_pipeendpoint(pipe) );
- continue;
- }
-
- if ( !usb_endpoint_xfer_isoc(endpointDescriptor) || !usb_endpoint_dir_in(endpointDescriptor) ){
- //Something is horribly wrong
- printk( KERN_NOTICE "[%s] altsetting %d has unexpected EP%d\n", KBUILD_MODNAME, i, usb_pipeendpoint(pipe) );
- continue;
- }
-
- bandwidth = 0;
- endpointMaxPacketSize = le16_to_cpu( endpointDescriptor->wMaxPacketSize );
-
- if( this->usbDevice->speed == USB_SPEED_HIGH ){
- //8 uframes per regular frame
- bandwidth = 8000;
-
- //high bandwidth endpoint?
- endpointMaxPacketSize = (endpointMaxPacketSize & 0x7ff) * (((endpointMaxPacketSize >> 11) & 0x3) + 1);
- }else{
- bandwidth = 1000;
- endpointMaxPacketSize &= 0x7ff;
- }
-
- bandwidth *= endpointMaxPacketSize;
-
- //Divide by interval / frame skippage
- bandwidth = bandwidth / (1 << (endpointDescriptor->bInterval - 1));
-
- printk( KERN_NOTICE "[%s] altsetting %d provides %d B/s bandwidth\n", KBUILD_MODNAME, i, bandwidth );
-
- //Check the bandwidth
- if( bandwidth < this->webcamCurrentResolution->requiredBandwidth ) continue;
-
- //Check the packet size
- if( (this->urbstreamMinPacketSize >= 0) && (endpointMaxPacketSize < this->urbstreamMinPacketSize) ) continue;
-
- if( (best_alt < 0) || (bandwidth < best_alt_bw) ){
- best_alt = i;
- best_alt_bw = bandwidth;
- }
- }
-
- if (best_alt == -1) return -ENODEV;
-
- this->usbCurrentAltsetting = best_alt;
- return 0;
- }
- /****************************
- * CLEANUP *
- ****************************/
- static void usbcam_urb_free( struct urb* urbp ){
- usb_free_coherent( urbp->dev, urbp->transfer_buffer_length, urbp->transfer_buffer, urbp->transfer_dma );
- //usb_buffer_free( urbp->dev, urbp->transfer_buffer_length, urbp->transfer_buffer, urbp->transfer_dma );
- usb_free_urb( urbp );
- }
- void usbcam_urbstream_cleanup( struct driverInstance* this ){
- int i;
- for( i = 0; i < URBSTREAM_URB_COUNT; i++ ) if( this->urbstreamUrbs[i].urbp ){
- usbcam_urb_free( this->urbstreamUrbs[i].urbp );
- this->urbstreamUrbs[i].urbp = NULL;
- }
- }
- /****************************
- * WORK PROCESS *
- ****************************/
- //NEVER SLEEP IN A COMPLETION HANDLER.
- //These are often called in atomic context.
- static void urbCompleteHandler( struct urb* urb ){
- struct urb_capsule* urbCapsule = urb->context;
- struct driverInstance* this = urbCapsule->driverInstanceThis;
- if( urb->status == -ECONNRESET || urb->status == -ENOENT ) return;//usb_kill_urb() or usb_unlink_urb()
- if( !queue_work( this->urbstreamWorkqueue, &urbCapsule->workitem ) ) printk( KERN_ERR "[%s] %s: queue_work err\n", KBUILD_MODNAME, __FUNCTION__ );
- }
- static void usbcam_urbstream_iso_process( struct work_struct* work ){
-
- struct urb_capsule* urbCapsule = container_of( work, struct urb_capsule, workitem );
- struct driverInstance* this = urbCapsule->driverInstanceThis;
- struct urb* urbp = urbCapsule->urbp;
-
- int i = 0;
- int res = 0;
-
- char* buf;
- int len;
- int status;
-
- if( !atomic_read( &this->urbstreamIsStreaming ) ) return;
-
- //printk( KERN_NOTICE "[%s] urbstream[%d] processing %p\n", KBUILD_MODNAME, this->us_endpoint, ibp );
-
- for( i = 0; i < urbp->number_of_packets; i++ ){
-
- buf = (((char *) urbp->transfer_buffer) + urbp->iso_frame_desc[i].offset);
- len = urbp->iso_frame_desc[i].actual_length;
- status = urbp->iso_frame_desc[i].status;
-
- urbp->iso_frame_desc[i].actual_length = 0;
- urbp->iso_frame_desc[i].status = 0;
-
- //void r5u870_iso_packet_done( struct driverInstance* this, const uint8_t *pktdata, int pktlen, int pktstatus )
- r5u870_iso_packet_done( this, buf, len, status );
- }
-
- if( atomic_read( &this->urbstreamIsStreaming ) ){
- res = usb_submit_urb( urbp, GFP_ATOMIC );
- if( res == -EL2NSYNC ) res = usb_submit_urb( urbp, GFP_ATOMIC );
-
- if( res ){
- printk( KERN_NOTICE "[%s] urbstream[%d] resubmit %p failed: %d\n", KBUILD_MODNAME, this->urbstreamEndpoint, urbCapsule, res );
- webcamCaptureStop( this );
- }
- }
- }
- /****************************
- * STOP START *
- ****************************/
- void usbcam_urbstream_stop( struct driverInstance* this ){
-
- int i = 0;
- atomic_set( &this->urbstreamIsStreaming, 0 );
- for( i = 0; i < URBSTREAM_URB_COUNT; i++ ) usb_kill_urb( this->urbstreamUrbs[i].urbp );
- }
- int usbcam_urbstream_start( struct driverInstance* this ){
-
- int res = 0;
- int i = 0;
-
- if( atomic_read( &this->urbstreamIsStreaming ) ){
- printk( KERN_WARNING "[%s] %s: urbstream[%d] already streaming\n", KBUILD_MODNAME, __FUNCTION__, this->urbstreamEndpoint );
- return -EEXIST;
- }
-
- atomic_set( &this->urbstreamIsStreaming, 1 );
-
- for( i = 0; i < URBSTREAM_URB_COUNT; i++ ){
-
- res = usb_submit_urb( this->urbstreamUrbs[i].urbp, GFP_KERNEL );
- if( res == -EL2NSYNC ) res = usb_submit_urb( this->urbstreamUrbs[i].urbp, GFP_KERNEL );
- if( res ){
- printk( KERN_ERR "[%s] %s: URB submit failed: %d\n", KBUILD_MODNAME, __FUNCTION__, res );
- printk( KERN_ERR "[%s] urbstream[%d] start failed: %i\n", KBUILD_MODNAME, this->urbstreamEndpoint, res );
- usbcam_urbstream_stop( this );
- break;
- }
- }
-
- return res;
- }
- /****************************
- * PREPARE *
- ****************************/
- struct urb* usbcam_urb_alloc( struct driverInstance* this, int packetSize ){
-
- struct urb* urbp;
- int totalBytesCount;
- int i;
-
- urbp = usb_alloc_urb( URBSTREAM_URB_PACKETS_COUNT, GFP_KERNEL );
- if( !urbp ) return NULL;
-
- urbp->dev = this->usbDevice;
- urbp->pipe = usb_rcvisocpipe( this->usbDevice, this->urbstreamEndpoint );
- urbp->number_of_packets = URBSTREAM_URB_PACKETS_COUNT;
- urbp->transfer_buffer = NULL;
- urbp->transfer_buffer_length = 0;
-
- totalBytesCount = packetSize * URBSTREAM_URB_PACKETS_COUNT;
-
- urbp->transfer_buffer = usb_alloc_coherent( urbp->dev, totalBytesCount, GFP_KERNEL, &urbp->transfer_dma );
- //urbp->transfer_buffer = usb_buffer_alloc( urbp->dev, totalBytesCount, GFP_KERNEL, &urbp->transfer_dma );
-
- if( !urbp->transfer_buffer ){
- usb_free_urb( urbp );
- return NULL;
- }
-
- urbp->transfer_buffer_length = totalBytesCount;
- urbp->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- urbp->transfer_flags |= URB_ISO_ASAP;
-
- for(i = 0; i < URBSTREAM_URB_PACKETS_COUNT; i++){
- urbp->iso_frame_desc[i].offset = (i * packetSize);
- urbp->iso_frame_desc[i].length = packetSize;
- urbp->iso_frame_desc[i].actual_length = 0;
- urbp->iso_frame_desc[i].status = 0;
- }
-
- urbp->complete = urbCompleteHandler;
- urbp->interval = 1;//FIXME: find the appropriate interval for the endpoint
-
- return urbp;
- }
- int usbcam_urbstream_config_iso( struct driverInstance* this ){
-
- struct usb_host_endpoint* endpoint;
-
- int err = 0;
- int packetSize = 0;
- int i;
-
-
- endpoint = this->usbDevice->ep_in[this->urbstreamEndpoint];
- if( !endpoint ){
- printk( KERN_ERR "[%s] Endpoint %d is not exist\n", KBUILD_MODNAME, this->urbstreamEndpoint );
- return -EINVAL;
- }
-
- packetSize = __le16_to_cpu( endpoint->desc.wMaxPacketSize );
- if ( !packetSize ) {
- printk( KERN_ERR "[%s] urbstream[%d]: current endpoint has maxpacket=0\n", KBUILD_MODNAME, this->urbstreamEndpoint );
- return -EINVAL;
- }
-
- if ( this->usbDevice->speed == USB_SPEED_HIGH ) packetSize = (packetSize & 0x7ff) * (((packetSize >> 11) & 0x3) + 1);
- else packetSize &= 0x7ff;
-
- printk( KERN_NOTICE "[%s] urbstream[%d] using packetSize %d\n", KBUILD_MODNAME, this->urbstreamEndpoint, packetSize );
-
- for( i = 0; i < URBSTREAM_URB_COUNT; i++ ){
-
- this->urbstreamUrbs[i].urbp = usbcam_urb_alloc( this, packetSize );
- if( !this->urbstreamUrbs[i].urbp ){
- usbcam_urbstream_cleanup( this );
- err = -ENOMEM;
- break;
- }
-
- this->urbstreamUrbs[i].urbp->context = &this->urbstreamUrbs[i];
- this->urbstreamUrbs[i].driverInstanceThis = this;
- INIT_WORK( &this->urbstreamUrbs[i].workitem, usbcam_urbstream_iso_process );
- }
-
- return err;
- }
|