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

📄 pwc-if.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Linux driver for Philips webcam    USB and Video4Linux interface part.   (C) 1999-2001 Nemosoft Unv.   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 device/product ID*/#include <linux/errno.h>#include <linux/init.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#include <asm/io.h>#include "pwc.h"#include "pwc-ioctl.h"#include "pwc-uncompress.h"#if !defined(MAP_NR)#define MAP_NR(a) virt_to_page(a)#endif/* Function prototypes and driver templates *//* hotplug device table support */static __devinitdata struct usb_device_id pwc_device_table [] = {	{ USB_DEVICE(0x0471, 0x0302) },	{ 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) },	{ USB_DEVICE(0x0471, 0x0312) },	{ USB_DEVICE(0x069A, 0x0001) },	{ USB_DEVICE(0x046D, 0x08b0) },	{ USB_DEVICE(0x055D, 0x9000) },	{ USB_DEVICE(0x055D, 0x9001) },	{ USB_DEVICE(0x041E, 0x400C) },	{ USB_DEVICE(0x04CC, 0x8116) },	{ }};MODULE_DEVICE_TABLE(usb, pwc_device_table);static void *usb_pwc_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id);static void usb_pwc_disconnect(struct usb_device *udev, void *ptr);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 10static int default_size = PSZ_QCIF;static int default_fps = 10;static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */static int default_fbufs = 3;   /* Default number of frame buffers */static int default_mbufs = 2;	/* Default number of mmap() buffers */       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;static int power_save = 0;static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */       int pwc_preferred_compression = 2; /* 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 struct semaphore mem_lock;static void *mem_leak = NULL; /* For delayed kfree()s. See below *//***/static int  pwc_video_open(struct video_device *vdev, int mode);static void pwc_video_close(struct video_device *vdev);static long pwc_video_read(struct video_device *vdev, char *buf, unsigned long count, int noblock);static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);static struct video_device pwc_template = {	owner:		THIS_MODULE,	name:		"Philips Webcam",	/* Filled in later */	type:		VID_TYPE_CAPTURE,	hardware:	VID_HARDWARE_PWC,	open:		pwc_video_open,	close:		pwc_video_close,	read:		pwc_video_read,	write:		pwc_video_write,	poll:		pwc_video_poll,	ioctl:		pwc_video_ioctl,	mmap:		pwc_video_mmap,	initialize:	NULL,			/* initialize */	minor:		0			/* minor */};/***************************************************************************//* 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 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 *//* Memory management functions, nicked from cpia.c, which nicked them from   bttv.c. So far, I've counted duplication of this code 6 times    (bttv, cpia, ibmcam, ov511, pwc, ieee1394). *//* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){        unsigned long ret = 0UL;	pmd_t *pmd;	pte_t *ptep, pte;  	if (!pgd_none(*pgd)) {                pmd = pmd_offset(pgd, adr);                if (!pmd_none(*pmd)) {                        ptep = pte_offset(pmd, adr);                        pte = *ptep;                        if(pte_present(pte)) {				ret  = (unsigned long) page_address(pte_page(pte));				ret |= (adr & (PAGE_SIZE - 1));							}                }        }	return ret;}/* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */static inline unsigned long kvirt_to_pa(unsigned long adr) {        unsigned long va, kva, ret;        va = VMALLOC_VMADDR(adr);        kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = __pa(kva);        return ret;}static void * rvmalloc(signed long size){	void * mem;	unsigned long adr, page;        /* Round it off to PAGE_SIZE */        size += (PAGE_SIZE - 1);        size &= ~(PAGE_SIZE - 1);	                mem=vmalloc_32(size);	if (mem) 	{		memset(mem, 0, size); /* Clear the ram out, no junk to the user */	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_pa(adr);			mem_map_reserve(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}	}	return mem;}static void rvfree(void * mem, signed long size){        unsigned long adr, page;                /* Round it off to PAGE_SIZE */        size += (PAGE_SIZE - 1);        size &= ~(PAGE_SIZE - 1);		if (mem) 	{	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_pa(adr);			mem_map_unreserve(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}		vfree(mem);	}}static int pwc_allocate_buffers(struct pwc_device *pdev){	int i;	void *kbuf;	Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev);	if (pdev == NULL)		return -ENXIO;		#ifdef PWC_MAGIC	if (pdev->magic != PWC_MAGIC) {		Err("allocate_buffers(): magic failed.\n");		return -ENXIO;	}#endif		/* Allocate Isochronuous pipe buffers */	for (i = 0; i < MAX_ISO_BUFS; i++) {		if (pdev->sbuf[i].data == NULL) {			kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);			if (kbuf == NULL) {				Err("Failed to allocate iso buffer %d.\n", i);				return -ENOMEM;			}			Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);			pdev->sbuf[i].data = kbuf;			memset(kbuf, 0, ISO_BUFFER_SIZE);		}	}	/* Allocate frame buffer structure */	if (pdev->fbuf == NULL) {		kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);		if (kbuf == NULL) {			Err("Failed to allocate frame buffer structure.\n");			return -ENOMEM;		}		Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);		pdev->fbuf = kbuf;		memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));	}	/* 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) {				Err("Failed to allocate frame buffer %d.\n", i);				return -ENOMEM;			}			Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);			pdev->fbuf[i].data = kbuf;			memset(kbuf, 128, PWC_FRAME_SIZE);		}	}		/* Allocate decompressor table space */	kbuf = NULL;	if (pdev->decompressor != NULL) {		kbuf = kmalloc(pdev->decompressor->table_size, GFP_KERNEL);		if (kbuf == NULL) {			Err("Failed to allocate decompress table.\n");			return -ENOMEM;		}		Trace(TRACE_MEMORY, "Allocated decompress table %p.\n", kbuf);	}	pdev->decompress_data = kbuf;		/* Allocate image buffer; double buffer for mmap() */	kbuf = rvmalloc(default_mbufs * pdev->len_per_image);	if (kbuf == NULL) {		Err("Failed to allocate image buffer(s).\n");		return -ENOMEM;	}	Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);	pdev->image_data = kbuf;	for (i = 0; i < default_mbufs; i++)		pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;	for (; i < MAX_IMAGES; i++)		pdev->image_ptr[i] = NULL;	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");	return 0;}static void pwc_free_buffers(struct pwc_device *pdev){	int i;	Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);	if (pdev == NULL)		return;#ifdef PWC_MAGIC	if (pdev->magic != PWC_MAGIC) {		Err("free_buffers(): magic failed.\n");		return;	}#endif		/* Release Iso-pipe buffers */	for (i = 0; i < MAX_ISO_BUFS; i++)		if (pdev->sbuf[i].data != NULL) {			Trace(TRACE_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) {				Trace(TRACE_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) {		Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);		kfree(pdev->decompress_data);		pdev->decompress_data = NULL;	}	pdev->decompressor = NULL;	/* Release image buffers */	if (pdev->image_data != NULL) {		Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);		rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);	}	pdev->image_data = NULL;	Trace(TRACE_MEMORY, "Leaving free_buffers().\n");}/* The frame & image buffer mess.    Yes, this is a mess. Well, it used to be simple, but alas...  In this   module, 3 buffers schemes are used to get the data from the USB bus to   the user program. The first scheme involves the ISO buffers (called thus   since they transport ISO data from the USB controller), and not really   interesting. Suffices to say the data from this buffer is quickly    gathered in an interrupt handler (pwc_isoc_handler) and placed into the    frame buffer.   

⌨️ 快捷键说明

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