⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwc-if.c

📁 webcam device driver
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Linux driver for Philips webcam   USB and Video4Linux interface part.   (C) 1999-2004 Nemosoft Unv.   (C) 2004-2006 Luc Saillard (luc@saillard.org)   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx   driver and thus may have bugs that are not present in the original version.   Please send bug reports and support requests to <luc@saillard.org>.   The decompression routines have been implemented by reverse-engineering the   Nemosoft binary pwcx module. Caveat emptor.   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*//*     This code forms the interface between the USB layers and the Philips   specific stuff. Some adanved stuff of the driver falls under an   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and   is thus not distributed in source form. The binary pwcx.o module    contains the code that falls under the NDA.      In case you're wondering: 'pwc' stands for "Philips WebCam", but    I really didn't want to type 'philips_web_cam' every time (I'm lazy as   any Linux kernel hacker, but I don't like uncomprehensible abbreviations   without explanation).      Oh yes, convention: to disctinguish between all the various pointers to   device-structures, I use these names for the pointer variables:   udev: struct usb_device *   vdev: struct video_device *   pdev: struct pwc_devive **//* Contributors:   - Alvarado: adding whitebalance code   - Alistar Moire: QuickCam 3000 Pro device/product ID   - Tony Hoyle: Creative Labs Webcam 5 device/product ID   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged   - Jk Fang: Sotec Afina Eye ID   - Xavier Roche: QuickCam Pro 4000 ID   - Jens Knudsen: QuickCam Zoom ID   - J. Debert: QuickCam for Notebooks ID*/#include <linux/errno.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/version.h>#include <asm/io.h>#include <linux/moduleparam.h>#include "pwc.h"#include "pwc-ioctl.h"#include "pwc-kiara.h"#include "pwc-timon.h"#include "pwc-dec23.h"#include "pwc-dec1.h"#include "pwc-uncompress.h"/* Function prototypes and driver templates *//* hotplug device table support */static const struct usb_device_id pwc_device_table [] = {	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */	{ USB_DEVICE(0x0471, 0x0303) },	{ USB_DEVICE(0x0471, 0x0304) },	{ USB_DEVICE(0x0471, 0x0307) },	{ USB_DEVICE(0x0471, 0x0308) },	{ USB_DEVICE(0x0471, 0x030C) },	{ USB_DEVICE(0x0471, 0x0310) },	{ USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */	{ USB_DEVICE(0x0471, 0x0312) },	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */	{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */	{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */	{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */	{ USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */	{ USB_DEVICE(0x055D, 0x9002) },	/* Samsung SNC-35E (Ver3.0) */	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */	{ USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */	{ USB_DEVICE(0x0d81, 0x1900) },	{ }};MODULE_DEVICE_TABLE(usb, pwc_device_table);static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);static void usb_pwc_disconnect(struct usb_interface *intf);static struct usb_driver pwc_driver = {	.name =			"Philips webcam",	/* name */	.id_table =		pwc_device_table,	.probe =		usb_pwc_probe,		/* probe() */	.disconnect =		usb_pwc_disconnect,	/* disconnect() */};#define MAX_DEV_HINTS	20#define MAX_ISOC_ERRORS	20static int default_size = PSZ_QCIF;static int default_fps = 10;static int default_fbufs = 3;   /* Default number of frame buffers */       int pwc_mbufs = 2;	/* Default number of mmap() buffers */#if CONFIG_PWC_DEBUG       int pwc_trace = PWC_DEBUG_LEVEL;#endifstatic int power_save = 0;static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */       int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */static struct {	int type;	char serial_number[30];	int device_node;	struct pwc_device *pdev;} device_hint[MAX_DEV_HINTS];/***/static int pwc_video_open(struct inode *inode, struct file *file);static int pwc_video_close(struct inode *inode, struct file *file);static ssize_t pwc_video_read(struct file *file, char __user *buf,			  size_t count, loff_t *ppos);static unsigned int pwc_video_poll(struct file *file, poll_table *wait);static int  pwc_video_ioctl(struct inode *inode, struct file *file,			    unsigned int ioctlnr, unsigned long arg);static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);static struct file_operations pwc_fops = {	.owner =	THIS_MODULE,	.open =		pwc_video_open,	.release =     	pwc_video_close,	.read =		pwc_video_read,	.poll =		pwc_video_poll,	.mmap =		pwc_video_mmap,	.ioctl =        pwc_video_ioctl,	.llseek =       no_llseek,};static struct video_device pwc_template = {	.owner =	THIS_MODULE,	.name =		"Philips Webcam",	/* Filled in later */	.type =		VID_TYPE_CAPTURE,	.hardware =	VID_HARDWARE_PWC,	.release =	video_device_release,	.fops =         &pwc_fops,	.minor =        -1,};/***************************************************************************//* Okay, this is some magic that I worked out and the reasoning behind it...   The biggest problem with any USB device is of course: "what to do    when the user unplugs the device while it is in use by an application?"   We have several options:   1) Curse them with the 7 plagues when they do (requires divine intervention)   2) Tell them not to (won't work: they'll do it anyway)   3) Oops the kernel (this will have a negative effect on a user's uptime)   4) Do something sensible.      Of course, we go for option 4.   It happens that this device will be linked to two times, once from   usb_device and once from the video_device in their respective 'private'   pointers. This is done when the device is probed() and all initialization   succeeded. The pwc_device struct links back to both structures.   When a device is unplugged while in use it will be removed from the    list of known USB devices; I also de-register it as a V4L device, but    unfortunately I can't free the memory since the struct is still in use   by the file descriptor. This free-ing is then deferend until the first   opportunity. Crude, but it works.      A small 'advantage' is that if a user unplugs the cam and plugs it back   in, it should get assigned the same video device minor, but unfortunately   it's non-trivial to re-link the cam back to the video device... (that    would surely be magic! :))*//***************************************************************************//* Private functions *//* Here we want the physical address of the memory. * This is used when initializing the contents of the area. */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)static unsigned long kvirt_to_pa(unsigned long adr) {        unsigned long kva, ret;	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1); /* restore the offset */	ret = __pa(kva);        return ret;}#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)/** * kzalloc - allocate memory. The memory is set to zero. * @size: how many bytes of memory are required. * @flags: the type of memory to allocate. */void *kzalloc(size_t size, int flags){        void *ret = kmalloc(size, flags);        if (ret)                memset(ret, 0, size);        return ret;}#endifstatic void *pwc_rvmalloc(unsigned long size){	void * mem;	unsigned long adr;        mem=vmalloc_32(size);	if (!mem)		return NULL;	memset(mem, 0, size); /* Clear the ram out, no junk to the user */	adr=(unsigned long) mem;	while (size > 0) 	 {	   SetPageReserved(vmalloc_to_page((void *)adr));	   adr  += PAGE_SIZE;	   size -= PAGE_SIZE;	 }	return mem;}static void pwc_rvfree(void * mem, unsigned long size){        unsigned long adr;	if (!mem) 	  	return;	adr=(unsigned long) mem;	while ((long) size > 0) 	 {	   ClearPageReserved(vmalloc_to_page((void *)adr));	   adr  += PAGE_SIZE;	   size -= PAGE_SIZE;	 }	vfree(mem);}static int pwc_allocate_buffers(struct pwc_device *pdev){	int i, err;	void *kbuf;	PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);	if (pdev == NULL)		return -ENXIO;			/* Allocate Isochronuous pipe buffers */	for (i = 0; i < MAX_ISO_BUFS; i++) {		if (pdev->sbuf[i].data == NULL) {			kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);			if (kbuf == NULL) {				PWC_ERROR("Failed to allocate iso buffer %d.\n", i);				return -ENOMEM;			}			PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);			pdev->sbuf[i].data = kbuf;		}	}	/* Allocate frame buffer structure */	if (pdev->fbuf == NULL) {		kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);		if (kbuf == NULL) {			PWC_ERROR("Failed to allocate frame buffer structure.\n");			return -ENOMEM;		}		PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);		pdev->fbuf = kbuf;	}	/* create frame buffers, and make circular ring */	for (i = 0; i < default_fbufs; i++) {		if (pdev->fbuf[i].data == NULL) {			kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */			if (kbuf == NULL) {				PWC_ERROR("Failed to allocate frame buffer %d.\n", i);				return -ENOMEM;			}			PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);			pdev->fbuf[i].data = kbuf;			memset(kbuf, 0, PWC_FRAME_SIZE);		}	}		/* Allocate decompressor table space */	if (DEVICE_USE_CODEC1(pdev->type))		err = pwc_dec1_alloc(pdev);	else		err = pwc_dec23_alloc(pdev);	if (err) {		PWC_ERROR("Failed to allocate decompress table.\n");		return err;	}	/* Allocate image buffer; double buffer for mmap() */	kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);	if (kbuf == NULL) {		PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",				pwc_mbufs * pdev->len_per_image);		return -ENOMEM;	}	PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);	pdev->image_data = kbuf;	for (i = 0; i < pwc_mbufs; i++) {		pdev->images[i].offset = i * pdev->len_per_image;		pdev->images[i].vma_use_count = 0;	}	for (; i < MAX_IMAGES; i++) {		pdev->images[i].offset = 0;	}	kbuf = NULL;	  	PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");	return 0;}static void pwc_free_buffers(struct pwc_device *pdev){	int i;	PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);	if (pdev == NULL)		return;	/* Release Iso-pipe buffers */	for (i = 0; i < MAX_ISO_BUFS; i++)		if (pdev->sbuf[i].data != NULL) {			PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);			kfree(pdev->sbuf[i].data);			pdev->sbuf[i].data = NULL;		}	/* The same for frame buffers */	if (pdev->fbuf != NULL) {		for (i = 0; i < default_fbufs; i++) {			if (pdev->fbuf[i].data != NULL) {				PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);				vfree(pdev->fbuf[i].data);				pdev->fbuf[i].data = NULL;			}		}		kfree(pdev->fbuf);		pdev->fbuf = NULL;	}	/* Intermediate decompression buffer & tables */	if (pdev->decompress_data != NULL) {		PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);		kfree(pdev->decompress_data);		pdev->decompress_data = NULL;	}	/* Release image buffers */	if (pdev->image_data != NULL) {		PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);		pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);	}	pdev->image_data = NULL;		PWC_DEBUG_MEMORY("Leaving free_buffers().\n");}/* The frame & image buffer mess. 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -