123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- #include "shared.h"
- #include "main.h"
- /****************************
- * UTILS *
- ****************************/
- static inline const struct r5u870_resolution* webcamGetFormatResolutionTable( struct driverInstance* this, __u32 format ){
-
- int i;
- for( i = 0; i < this->webcamFormatsCount; i++ ){
- if( this->webcamFormats[i].pixelformat == format ){
- return this->webcamFormats[i].resolutionTable;
- }
- }
- return NULL;
- }
- /****************************
- * videoDevice ioctl ops *
- ****************************/
- //These callbacks are protected by this->videoDevice.lock. Don't worry!
- static int vidioc_querycap_callback( struct file* file, void* fh, struct v4l2_capability* cap ){
-
- struct driverInstance* this = video_drvdata( file );
- const char busName[] = "USB";
-
- strlcpy( cap->driver, KBUILD_MODNAME, sizeof(cap->driver) );
- strlcpy( cap->card , this->webcamModel->modelName, sizeof(cap->card) );
- strlcpy( cap->bus_info, busName, sizeof(cap->bus_info) );
-
- cap->version = KERNEL_VERSION( 2, 0, 0 );
-
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-
- return 0;
- }
- static int vidioc_enum_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_fmtdesc* f ){
-
- struct driverInstance* this = video_drvdata( file );
- const struct r5u870_pixelformat* pixelformat;
-
- if( f->index >= this->webcamFormatsCount ) return -EINVAL;
-
- pixelformat = &this->webcamFormats[ f->index ];
- f->flags = pixelformat->flags;
- f->pixelformat = pixelformat->pixelformat;
- strlcpy( f->description, pixelformat->description, sizeof(f->description) );
-
- return 0;
- }
- static int vidioc_g_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f ){
- struct driverInstance* this = video_drvdata( file );
- f->fmt.pix = this->webcamCurrentPixelformat;
- return 0;
- }
- static int vidioc_s_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f ){
-
- struct driverInstance* this = video_drvdata( file );
- int res;
-
- if( atomic_read( &this->usbDeviceIsDisconnected ) ){
- printk( KERN_WARNING "[%s] VIDIOC_S_FMT: device disconnected\n", KBUILD_MODNAME );
- return -EIO;
- }
-
- if( !memcmp(&f->fmt.pix, &this->webcamCurrentPixelformat, sizeof(f->fmt.pix)) ){
- printk( KERN_NOTICE "[%s] VIDIOC_S_FMT: nothing to do\n", KBUILD_MODNAME );
- return 0;
- }
-
- if( atomic_read(&this->webcamIsCaptuing) ){
- printk( KERN_WARNING "[%s] VIDIOC_S_FMT: capture in progress\n", KBUILD_MODNAME );
- return -EBUSY;
- }
-
- res = webcamTryFormat( this, &f->fmt.pix, 1 );
- if( res )printk( KERN_ERR "[%s] VIDIOC_S_FMT: err: %i\n", KBUILD_MODNAME, res );
- return res;
- }
- static int vidioc_try_fmt_vid_cap_callback( struct file* file, void* fh, struct v4l2_format* f ){
- struct driverInstance* this = video_drvdata( file );
- if ( atomic_read( &this->usbDeviceIsDisconnected ) ) return -EIO;
- return webcamTryFormat( this, &f->fmt.pix, 0 );
- }
- static int vidioc_enum_input_callback( struct file* file, void* fh, struct v4l2_input* input ){
-
- const char camName[] = "Camera";
-
- if( input->index ) return -EINVAL;
-
- strlcpy( input->name, camName, sizeof(input->name) );
- input->type = V4L2_INPUT_TYPE_CAMERA;
-
- return 0;
- }
- static int vidioc_g_input_callback( struct file* file, void* fh, unsigned int* i ){
- *i = 0;
- return 0;
- }
- static int vidioc_s_input_callback( struct file* file, void* fh, unsigned int i ){
- return ( i ? -EINVAL : 0 );
- }
- /*
- TODO: Come up with something with standards.
- I don’t know what to specify as the standard, so I just write 0.
- Some programs, for example skype, do not work if these functions are not implemented.
- */
- static int vidioc_querystd_callback( struct file* file, void* fh, v4l2_std_id* argp ){
- printk( KERN_NOTICE "[%s] FIXME: %s is not implemented!\n", KBUILD_MODNAME, __FUNCTION__ );
- *argp = 0;
- return 0;
- }
- static int vidioc_g_std_callback( struct file* file, void* fh, v4l2_std_id* argp ){
- printk( KERN_NOTICE "[%s] FIXME: %s is not implemented!\n", KBUILD_MODNAME, __FUNCTION__ );
- *argp = 0;
- return 0;
- }
- static int vidioc_s_std_callback( struct file* file, void* fh, v4l2_std_id argp ){
- printk( KERN_NOTICE "[%s] FIXME: %s is not implemented!\n", KBUILD_MODNAME, __FUNCTION__ );
- return 0;
- }
- static int vidioc_enum_framesizes_callback( struct file* file, void* fh, struct v4l2_frmsizeenum* fsize ){
-
- struct driverInstance* this = video_drvdata( file );
- const struct r5u870_resolution* resolutionTable;
- int i;
-
- resolutionTable = webcamGetFormatResolutionTable( this, fsize->pixel_format );
- if( !resolutionTable ) return -EINVAL;
-
- for( i = 0; resolutionTable[i].width; i++ ){
- if( i == fsize->index ){
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = resolutionTable[i].width;
- fsize->discrete.height = resolutionTable[i].height;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int vidioc_enum_frameintervals_callback( struct file* file, void* fh, struct v4l2_frmivalenum* fival ){
-
- struct driverInstance* this = video_drvdata( file );
- const struct r5u870_resolution* resolutionTable;
- int i;
-
- if( fival->index ) return -EINVAL;
-
- resolutionTable = webcamGetFormatResolutionTable( this, fival->pixel_format );
- if( !resolutionTable ) return -EINVAL;
-
- for( i = 0; resolutionTable[i].width; i++ ){
- if( fival->width == resolutionTable[i].width && fival->height == resolutionTable[i].height ){
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete.numerator = resolutionTable[i].width * resolutionTable[i].height * 2;
- fival->discrete.denominator = resolutionTable[i].requiredBandwidth;
- return 0;
- }
- }
-
- return -EINVAL;
- }
- /****************************
- * videobuf2 ops *
- ****************************/
- //These callbacks are protected by this->videobuf2Queue.lock.
- static int queue_setup_callback( struct vb2_queue* videobufQueue, unsigned int* numBuffers, unsigned int* numPlanes, unsigned int sizes[], struct device* alloc_devs[] ){
-
- struct driverInstance* this = videobufQueue->drv_priv;
-
- if( *numBuffers < VIDEOBUF_QUEUE_MIN_BUF_NEED ) *numBuffers = VIDEOBUF_QUEUE_MIN_BUF_NEED;
- *numPlanes = 1;
- sizes[0] = this->webcamCurrentPixelformat.sizeimage;
-
- return 0;
- }
- //called every time the buffer is queued from userspace and from the VIDIOC_PREPARE_BUF ioctl
- static int buf_prepare_callback( struct vb2_buffer* videoBuffer ){
-
- struct driverInstance* this = vb2_get_drv_priv( videoBuffer->vb2_queue );
-
- if ( vb2_plane_size( videoBuffer, 0 ) < this->webcamCurrentPixelformat.sizeimage ) {
- printk( KERN_ERR "[%s] buffer too small (%lu < %u)\n", KBUILD_MODNAME, vb2_plane_size( videoBuffer, 0 ), this->webcamCurrentPixelformat.sizeimage );
- return -EINVAL;
- }
-
- vb2_set_plane_payload( videoBuffer, 0, this->webcamCurrentPixelformat.sizeimage );
- return 0;
- }
- //passes buffer to the driver; driver should give the buffer back by calling vb2_buffer_done() function
- static void buf_queue_callback( struct vb2_buffer* videoBuffer ){
-
- struct driverInstance* this = vb2_get_drv_priv( videoBuffer->vb2_queue );
- struct videobuffer_capsule* videobufCapsule = container_of( videoBuffer, struct videobuffer_capsule, videobuffer );
- unsigned long flags = 0;
-
- if( atomic_read( &this->buflistIsDisabled ) ){
- videoBuffer->timestamp = ktime_get_ns();
- vb2_buffer_done( videoBuffer, VB2_BUF_STATE_ERROR );
- }else{
- spin_lock_irqsave( &this->buflistSpinlock, flags );
- list_add_tail( &videobufCapsule->listItem, &this->buflist );
- spin_unlock_irqrestore( &this->buflistSpinlock, flags );
- }
- }
- static int start_streaming_callback( struct vb2_queue* videobufQueue, unsigned int count ){
- struct driverInstance* this = vb2_get_drv_priv( videobufQueue );
- return webcamCaptureStart( this );
- }
- static void stop_streaming_callback( struct vb2_queue* videobufQueue ){
- struct driverInstance* this = videobufQueue->drv_priv;
- webcamCaptureStop( this );
- atomic_set( &this->buflistIsDisabled, 0 );
- }
- /****************************
- * USB *
- ****************************/
- static int usbDeviceProbe_callback( struct usb_interface* usbInterface, const struct usb_device_id* usbDeviceId ){
-
- int err = 0;
-
- //void * devm_kzalloc(struct device * dev, size_t size, gfp_t gfp);
- struct driverInstance* this = devm_kzalloc( &usbInterface->dev, sizeof(struct driverInstance), GFP_KERNEL );
- if( !this ){
- printk( KERN_ERR "[%s] devm_kzalloc err\n", KBUILD_MODNAME );
- return -ENOMEM;
- }
-
- this->usbInterface = usb_get_intf( usbInterface );//NEED CLEAN
- this->usbDevice = usb_get_dev( interface_to_usbdev(usbInterface) );//NEED CLEAN
- this->usbDeviceDriver = to_usb_driver( usbInterface->dev.driver );
- this->dev = &usbInterface->dev;
-
- INIT_LIST_HEAD( &this->buflist );
- mutex_init( &this->lock );//Initialize the mutex to unlocked state.
- spin_lock_init( &this->buflistSpinlock );
- INIT_LIST_HEAD( &this->claimedInterfacesList );
-
- err = webcamInit( this, usbDeviceId );//NEED CLEAN
- if( err ){
- printk( KERN_ERR "[%s] WebcamInit failed: %i\n", KBUILD_MODNAME, err );
- goto l_put_interface_and_usb_device;
- }
-
- err = v4l2_device_register( this->dev, &this->v4l2Device );//NEED CLEAN
- if( err ){
- printk( KERN_ERR "[%s] v4l2_device_register result: %i\n", KBUILD_MODNAME, err );
- goto l_webcamRelease;
- }
-
- //videobuf2 queue init
- this->videobuf2Queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- this->videobuf2Queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
- this->videobuf2Queue.drv_priv = this;
- this->videobuf2Queue.buf_struct_size = sizeof( struct videobuffer_capsule );
- this->videobuf2Queue.ops = &videobuf2QueueOps;
- this->videobuf2Queue.mem_ops = &vb2_vmalloc_memops;//videobuf2MemOps
- this->videobuf2Queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- this->videobuf2Queue.min_buffers_needed = VIDEOBUF_QUEUE_MIN_BUF_NEED;
- this->videobuf2Queue.lock = &this->lock;
- this->videobuf2Queue.gfp_flags = GFP_KERNEL;//GFP_DMA32
- err = vb2_queue_init( &this->videobuf2Queue );
- if( err ){
- printk( KERN_ERR "[%s] vb2_queue_init err: %i\n", KBUILD_MODNAME, err );
- goto l_v4l2_device_unregister;
- }
-
- //videoDevice init
- strlcpy( this->videoDevice.name, KBUILD_MODNAME, sizeof(this->videoDevice.name) );
- this->videoDevice.release = video_device_release_empty;
- this->videoDevice.fops = &v4l2FileOperations;
- this->videoDevice.ioctl_ops = &videoDeviceIoctlOps;
- this->videoDevice.lock = &this->lock;//This lock will be automatically applied in ioctl_ops.
- this->videoDevice.queue = &this->videobuf2Queue;
- this->videoDevice.v4l2_dev = &this->v4l2Device;
- this->videoDevice.tvnorms = V4L2_STD_ALL;
- this->videoDevice.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- video_set_drvdata( &this->videoDevice, this );
- err = video_register_device( &this->videoDevice, VFL_TYPE_VIDEO, -1 );//NEED CLEAN
- if( err ){
- printk( KERN_ERR "[%s] video_register_device err: %i\n", KBUILD_MODNAME, err );
- goto l_v4l2_device_unregister;
- }
-
- this->urbstreamWorkqueue = create_singlethread_workqueue( KBUILD_MODNAME );//NEED CLEAN
-
- //static inline void usb_set_intfdata(struct usb_interface *intf, void *data);
- usb_set_intfdata( usbInterface, this );
- return err;
-
-
- l_v4l2_device_unregister:
- v4l2_device_unregister( &this->v4l2Device );
-
- l_webcamRelease:
- webcamRelease( this );
-
- l_put_interface_and_usb_device:
- usb_put_dev( this->usbDevice );
- usb_put_intf( this->usbInterface );
-
- return err;
- }
- //also called befoure module unloading
- static void usbDeviceDisconnect_callback( struct usb_interface* usbInterface ){
-
- //static inline void *usb_get_intfdata(struct usb_interface *intf);
- struct driverInstance* this = usb_get_intfdata( usbInterface );
-
- atomic_set( &this->usbDeviceIsDisconnected, 1 );
- webcamRelease( this );
-
- flush_workqueue( this->urbstreamWorkqueue );
- destroy_workqueue( this->urbstreamWorkqueue );
-
- video_unregister_device( &this->videoDevice );
- v4l2_device_unregister( &this->v4l2Device );
-
- usb_set_intfdata( usbInterface, NULL );
-
- usb_put_dev( this->usbDevice );
- usb_put_intf( this->usbInterface );
- }
- /****************************
- * module entry point *
- ****************************/
- static int onLoad( void ){
- printk( KERN_NOTICE "%s is here.\n", KBUILD_MODNAME );
- return usb_register( &usbDriver_s );
- }
- static void onUnload( void ){
- usb_deregister( &usbDriver_s );
- printk( KERN_NOTICE "%s has been unloaded.\n", KBUILD_MODNAME );
- }
- module_init( onLoad );
- module_exit( onUnload );
- MODULE_LICENSE( "GPL" );
|