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

📄 vicam.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- linux-c -*- * USB ViCAM driver * * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE * *      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 driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB * * Thanks to Greg Kroah-Hartman for the USB Skeleton driver * * TODO: *	- find out the ids for the Vista Imaging ViCAM * * History: * * 2001_07_07 - 0.1 - christopher: first version * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try  			while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done		      yep, moving pictures. * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, 			get gqcam-0.9, compile it and run. Better than dd ;-). * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) 			kill update_params if it does not seem to work for you. * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk * * FIXME: It crashes on rmmod with camera plugged. */#define DEBUG 1#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include <asm/io.h>#include <linux/wrapper.h>#include <linux/vmalloc.h>#include <linux/videodev.h>#include "vicam.h"#include "vicamurbs.h"/* Version Information */#define DRIVER_VERSION "v0"#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"#define DRIVER_DESC "USB ViCAM Driver"/* Define these values to match your device */#define USB_VICAM_VENDOR_ID	0x04C1#define USB_VICAM_PRODUCT_ID	0x009D/* table of devices that work with this driver */static struct usb_device_id vicam_table [] = {	{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },	{ }					/* Terminating entry */};MODULE_DEVICE_TABLE (usb, vicam_table);static int video_nr = -1; 		/* next avail video device */static struct usb_driver vicam_driver;static char *buf, *buf2;static int change_pending = 0; static int vicam_parameters(struct usb_vicam *vicam);/****************************************************************************** * *  Memory management functions * *  Taken from bttv-drivers.c 2.4.7-pre3 * ******************************************************************************//* [DaveM] I've recoded most of this so that: * 1) It's easier to tell what is happening * 2) It's more portable, especially for translating things *    out of vmalloc mapped areas in the kernel. * 3) Less unnecessary translations happen. * * The code used to assume that the kernel vmalloc mappings * existed in the page tables of every process, this is simply * not guarenteed.  We now use pgd_offset_k which is the * defined way to get at the kernel page tables. *//* 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;}static inline unsigned long uvirt_to_bus(unsigned long adr){	unsigned long kva, ret;	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);	ret = virt_to_bus((void *)kva);	return ret;}static inline unsigned long kvirt_to_bus(unsigned long adr){	unsigned long va, kva, ret;	va = VMALLOC_VMADDR(adr);	kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = virt_to_bus((void *)kva);	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;	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;	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);	}}/****************************************************************************** * *  Foo Bar * ******************************************************************************//** *	usb_vicam_debug_data */static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data){	int i;	if (!debug)		return;	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",		function, size);	for (i = 0; i < size; ++i) {		printk ("%.2x ", data[i]);	}	printk ("\n");}/***************************************************************************** * *  Send command to vicam * *****************************************************************************/static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,	unsigned short value, unsigned char *cp, int size){	int ret;	unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);	/* Needs to return data I think, works for sending though */	memcpy(transfer_buffer, cp, size);		ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);	kfree(transfer_buffer);	if (ret)		printk("vicam: error: %d\n", ret);	mdelay(100);	return ret;}/***************************************************************************** * *  Video4Linux Helpers *  *****************************************************************************/static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b){	dbg("vicam_get_capability");	strcpy(b->name, vicam->camera_name);	b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;	b->channels = 1;	b->audios = 0;	b->maxwidth = vicam->width[vicam->sizes-1];	b->maxheight = vicam->height[vicam->sizes-1];	b->minwidth = vicam->width[0];	b->minheight = vicam->height[0];	return 0;}		static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v){	dbg("vicam_get_channel");	if (v->channel != 0)		return -EINVAL; 	v->flags = 0;	v->tuners = 0;	v->type = VIDEO_TYPE_CAMERA;	strcpy(v->name, "Camera");	return 0;} 		static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v){	dbg("vicam_set_channel");	if (v->channel != 0)		return -EINVAL;		return 0;}		static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm){	int i;	dbg("vicam_get_mmapbuffer");	memset(vm, 0, sizeof(vm));	vm->size = VICAM_NUMFRAMES * vicam->maxframesize;	vm->frames = VICAM_NUMFRAMES;	for (i=0; i<VICAM_NUMFRAMES; i++)		vm->offsets[i] = vicam->maxframesize * i;	return 0;}static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p){	dbg("vicam_get_picture");	/* This is probably where that weird 0x56 call goes */	p->brightness = vicam->win.brightness;	p->hue = vicam->win.hue;	p->colour = vicam->win.colour;	p->contrast = vicam->win.contrast;	p->whiteness = vicam->win.whiteness;	p->depth = vicam->win.depth;	p->palette = vicam->win.palette;	return 0;}static void synchronize(struct usb_vicam *vicam){	change_pending = 1;	interruptible_sleep_on(&vicam->wait);	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);	mdelay(10);	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);	mdelay(10);}static void params_changed(struct usb_vicam *vicam){#if 1	synchronize(vicam);	mdelay(10);	vicam_parameters(vicam);	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));#endif}static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p){	int changed = 0;	info("vicam_set_picture (%d)", p->brightness);#define SET(x) \	if (vicam->win.x != p->x) \		vicam->win.x = p->x, changed = 1;	SET(brightness);	SET(hue);	SET(colour);	SET(contrast);	SET(whiteness);	SET(depth);	SET(palette);	if (changed)		params_changed(vicam);	return 0;	/* Investigate what should be done maybe 0x56 type call */	if (p->depth != 8) return 1;	if (p->palette != VIDEO_PALETTE_GREY) return 1;	return 0;}/* FIXME - vicam_sync_frame - important */static int vicam_sync_frame(struct usb_vicam *vicam, int frame){	dbg("vicam_sync_frame");	if(frame <0 || frame >= VICAM_NUMFRAMES)		return -EINVAL;	/* Probably need to handle various cases *//*	ret=vicam_newframe(vicam, frame);	vicam->frame[frame].grabstate=FRAME_UNUSED;*/	return 0;}	static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw){	dbg("vicam_get_window");	vw->x = 0;	vw->y = 0;	vw->chromakey = 0;	vw->flags = 0;	vw->clipcount = 0;	vw->width = vicam->win.width;	vw->height = vicam->win.height;	return 0;}static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw){	info("vicam_set_window");			if (vw->flags)		return -EINVAL;	if (vw->clipcount)		return -EINVAL;	if (vicam->win.width == vw->width && vicam->win.height == vw->height)		return 0;	/* Pick largest mode that is smaller than specified res */	/* If specified res is too small reject                 */	/* Add urb send to device... */	vicam->win.width = vw->width;	vicam->win.height = vw->height;	params_changed(vicam);	return 0;}/* FIXME - vicam_mmap_capture - important */static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm){	dbg("vicam_mmap_capture");	/* usbvideo.c looks good for using here */	/* 	if (vm->frame >= VICAM_NUMFRAMES)		return -EINVAL;	if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)		return -EBUSY;	vicam->frame[vm->frame].grabstate=FRAME_READY;	*/	/* No need to vicam_set_window here according to Alan */	/*	if (!vicam->streaming)		vicam_start_stream(vicam);	*/	/* set frame as ready */	return 0;}/***************************************************************************** * *  Video4Linux *  *****************************************************************************/static int vicam_v4l_open(struct video_device *vdev, int flags){	struct usb_vicam *vicam = (struct usb_vicam *)vdev;	int err = 0;		dbg("vicam_v4l_open");	MOD_INC_USE_COUNT; 	down(&vicam->sem);	if (vicam->open_count)		/* Maybe not needed? */		err = -EBUSY;	else {		vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);		if (!vicam->fbuf)			err=-ENOMEM;		else {			vicam->open_count = 1;		}#ifdef BLINKING		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);		info ("led on");		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);#endif	}	up(&vicam->sem);	if (err)		MOD_DEC_USE_COUNT;	return err;

⌨️ 快捷键说明

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