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

📄 pwc-if.c

📁 Linux support for Philips USB webcams halted Latest version: pwc-9.0.2.tar.gz (including documents
💻 C
📖 第 1 页 / 共 5 页
字号:
	        urb->transfer_buffer_length = ISO_BUFFER_SIZE;	        urb->complete = pwc_isoc_handler;	        urb->context = pdev;		urb->start_frame = 0;		urb->number_of_packets = ISO_FRAMES_PER_DESC;		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;		}	}	/* link */	for (i = 0; i < MAX_ISO_BUFS; i++) {		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);		if (ret)			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);		else			Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);	}	/* All is done... */	pdev->iso_init = 1;	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");	return 0;}static void pwc_isoc_cleanup(struct pwc_device *pdev){	int i;	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");	if (pdev == NULL)		return;	/* Unlinking ISOC buffers one by one */	for (i = 0; i < MAX_ISO_BUFS; i++) {		struct urb *urb;		urb = pdev->sbuf[i].urb;		if (urb != 0) {			if (pdev->iso_init) {				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);				usb_unlink_urb(urb);			}			Trace(TRACE_MEMORY, "Freeing URB\n");			usb_free_urb(urb);			pdev->sbuf[i].urb = NULL;		}	}	/* Stop camera, but only if we are sure the camera is still there (unplug	   is signalled by EPIPE) 	 */	if (pdev->error_status && pdev->error_status != EPIPE) {		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");		usb_set_interface(pdev->udev, 0, 0);	}	pdev->iso_init = 0;	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");}int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot){	int ret, start;	/* Stop isoc stuff */	pwc_isoc_cleanup(pdev);	/* Reset parameters */	pwc_reset_buffers(pdev);	/* Try to set video mode... */	start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);	if (ret) { 	        Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");		/* That failed... restore old mode (we know that worked) */		start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);		if (start) {		        Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");		}	}	if (start == 0)	{		if (pwc_isoc_init(pdev) < 0)		{			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");			ret = -EAGAIN; /* let's try again, who knows if it works a second time */		}	}	pdev->drop_frames++; /* try to avoid garbage during switch */	return ret; /* Return original error code */}/***************************************************************************//* Video4Linux functions */static int pwc_video_open(struct inode *inode, struct file *file){	int i;	struct video_device *vdev = video_devdata(file);	struct pwc_device *pdev;	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);		pdev = (struct pwc_device *)vdev->priv;	if (pdev == NULL)		BUG();	if (pdev->vopen)		return -EBUSY;		down(&pdev->modlock);	if (!pdev->usb_init) {		Trace(TRACE_OPEN, "Doing first time initialization.\n");		pdev->usb_init = 1;				if (pwc_trace & TRACE_OPEN)		{			/* Query sensor type */			const char *sensor_type = NULL;			int ret;			ret = pwc_get_cmos_sensor(pdev, &i);			if (ret >= 0)			{				switch(i) {				case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;				case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;				case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;				case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;				case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;				case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;				case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;				case 0x40:  sensor_type = "UPA 1021 sensor"; break;				case 0x100: sensor_type = "VGA sensor"; break;				case 0x101: sensor_type = "PAL MR sensor"; break;				default:    sensor_type = "unknown type of sensor"; break;				}			}			if (sensor_type != NULL)				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);		}	}	/* Turn on camera */	if (power_save) {		i = pwc_camera_power(pdev, 1);		if (i < 0)			Info("Failed to restore power to the camera! (%d)\n", i);	}	/* Set LED on/off time */	if (pwc_set_leds(pdev, led_on, led_off) < 0)		Info("Failed to set LED on/off time.\n");	/* Find our decompressor, if any */	pdev->decompressor = pwc_find_decompressor(pdev->type);#if PWC_DEBUG		Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor);#endif	pwc_construct(pdev); /* set min/max sizes correct */	/* So far, so good. Allocate memory. */	i = pwc_allocate_buffers(pdev);	if (i < 0) {		Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");		up(&pdev->modlock);		return i;	}		/* Reset buffers & parameters */	pwc_reset_buffers(pdev);	for (i = 0; i < default_mbufs; i++)		pdev->image_used[i] = 0;	pdev->vframe_count = 0;	pdev->vframes_dumped = 0;	pdev->vframes_error = 0;	pdev->visoc_errors = 0;	pdev->error_status = 0;#if PWC_DEBUG	pdev->sequence = 0;#endif	pwc_construct(pdev); /* set min/max sizes correct */	/* Set some defaults */	pdev->vsnapshot = 0;	/* Start iso pipe for video; first try the last used video size	   (or the default one); if that fails try QCIF/10 or QSIF/10;	   it that fails too, give up.	 */	i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);	if (i)	{		Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");		if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);		else			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);	}	if (i) {		Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");		up(&pdev->modlock);		return i;	}		i = pwc_isoc_init(pdev);	if (i) {		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);		up(&pdev->modlock);		return i;	}	pdev->vopen++;	file->private_data = vdev;	/* lock decompressor; this has a small race condition, since we 	   could in theory unload pwcx.o between pwc_find_decompressor()	   above and this call. I doubt it's ever going to be a problem.	 */	if (pdev->decompressor != NULL)		pdev->decompressor->lock();	up(&pdev->modlock);	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");	return 0;}/* Note that all cleanup is done in the reverse order as in _open */static int pwc_video_close(struct inode *inode, struct file *file){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	int i;	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);	pdev = (struct pwc_device *)vdev->priv;	if (pdev->vopen == 0)		Info("video_close() called on closed device?\n");	/* Dump statistics, but only if a reasonable amount of frames were	   processed (to prevent endless log-entries in case of snap-shot	   programs)	 */	if (pdev->vframe_count > 20)		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);	if (pdev->decompressor != NULL) {		pdev->decompressor->exit();		pdev->decompressor->unlock();		pdev->decompressor = NULL;	}	pwc_isoc_cleanup(pdev);	pwc_free_buffers(pdev);	/* Turn off LEDS and power down camera, but only when not unplugged */	if (pdev->error_status != EPIPE) {		/* Turn LEDs off */		if (pwc_set_leds(pdev, 0, 0) < 0)			Info("Failed to set LED on/off time.\n");		if (power_save) {			i = pwc_camera_power(pdev, 0);			if (i < 0)				Err("Failed to power down camera (%d)\n", i);		}	}	pdev->vopen = 0;	Trace(TRACE_OPEN, "<< video_close()\n");	return 0;}/* *	FIXME: what about two parallel reads ???? *      ANSWER: Not supported. You can't open the device more than once,                despite what the V4L1 interface says. First, I don't see                the need, second there's no mechanism of alerting the                2nd/3rd/... process of events like changing image size.                And I don't see the point of blocking that for the                2nd/3rd/... process.                In multi-threaded environments reading parallel from any                device is tricky anyhow. */static ssize_t pwc_video_read(struct file *file, char *buf,			  size_t count, loff_t *ppos){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	int noblock = file->f_flags & O_NONBLOCK;	DECLARE_WAITQUEUE(wait, current);        int bytes_to_read;	Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count);	if (vdev == NULL)		return -EFAULT;	pdev = vdev->priv;	if (pdev == NULL)		return -EFAULT;	if (pdev->error_status)		return -pdev->error_status; /* Something happened, report what. */	/* In case we're doing partial reads, we don't have to wait for a frame */	if (pdev->image_read_pos == 0) {		/* Do wait queueing according to the (doc)book */		add_wait_queue(&pdev->frameq, &wait);		while (pdev->full_frames == NULL) {			/* Check for unplugged/etc. here */			if (pdev->error_status) {				remove_wait_queue(&pdev->frameq, &wait);				set_current_state(TASK_RUNNING);				return -pdev->error_status ;			}	                if (noblock) {	                	remove_wait_queue(&pdev->frameq, &wait);	                	set_current_state(TASK_RUNNING);	                	return -EWOULDBLOCK;	                }	                if (signal_pending(current)) {	                	remove_wait_queue(&pdev->frameq, &wait);	                	set_current_state(TASK_RUNNING);	                	return -ERESTARTSYS;	                }	                schedule();	               	set_current_state(TASK_INTERRUPTIBLE);		}		remove_wait_queue(&pdev->frameq, &wait);		set_current_state(TASK_RUNNING);                                                                                                                                                                                		/* Decompress and release frame */		if (pwc_handle_frame(pdev))			return -EFAULT;	}	Trace(TRACE_READ, "Copying data to user space.\n");	if (pdev->vpalette == VIDEO_PALETTE_RAW)		bytes_to_read = pdev->frame_size;	else 		bytes_to_read = pdev->view.size;	/* copy bytes to user space; we allow for partial reads */	if (count + pdev->image_read_pos > bytes_to_read)		count = bytes_to_read - pdev->image_read_pos;	if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))		return -EFAULT;	pdev->image_read_pos += count;	if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */		pdev->image_read_pos = 0;		pwc_next_image(pdev);	}	return count;}static unsigned int pwc_video_poll(struct file *file, poll_table *wait){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	if (vdev == NULL)		return -EFAULT;	pdev = vdev->priv;	if (pdev == NULL)		return -EFAULT;	poll_wait(file, &pdev->frameq, wait);	if (pdev->error_status)		return POLLERR;	if (pdev->full_frames != NULL) /* we have frames waiting */		return (POLLIN | POLLRDNORM);	return 0;}static int pwc_video_do_ioctl(struct inode *inode, struct file *file,			      unsigned int cmd, void *arg){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	DECLARE_WAITQUEUE(wait, current);	if (vdev == NULL)		return -EFAULT;	pdev = vdev->priv;	if (pdev == NULL)		return -EFAULT;	switch (cmd) {		/* Query cabapilities */		case VIDIOCGCAP:		{			struct video_capability *caps = arg;			strcpy(caps->name, vdev->name);			caps->type = VID_TYPE_CAPTURE;			caps->channels = 1;			caps->audios = 1;			caps->minwidth  = pdev->view_min.x;			caps->minheight = pdev->view_min.y;			caps->maxwidth  = pdev->view_max.x;			caps->maxheight = pdev->view_max.y;			break;		}		/* Channel functions (simulate 1 channel) */		case VIDIOCGCHAN:		{			struct video_channel *v = arg;			if (v->channel != 0)				return -EINVAL;			v->flags = 0;			v->tuners = 0;			v->type = VIDEO_TYPE_CAMERA;			strcpy(v->name, "Webcam");			return 0;		}		case VIDIOCSCHAN:		{			/* The spec says the argument is an integer, but			   the bttv driver uses a video_channel arg, which			   makes sense becasue it also has the norm flag.			 */			struct video_channel *v = arg;			if (v->channel != 0)				return -EINVAL;			return 0;		}		/* Picture functions; contrast etc. */		case VIDIOCGPICT:		{			struct video_picture *p = arg;			int val;			val = pwc_get_brightness(pdev);			if (val >= 0)

⌨️ 快捷键说明

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