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

📄 pwc-if.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
{	struct pwc_device *pdev = video_get_drvdata(vdev);	int rc;	rc = video_device_create_file(vdev, &dev_attr_button);	if (rc)		goto err;	if (pdev->features & FEATURE_MOTOR_PANTILT) {		rc = video_device_create_file(vdev, &dev_attr_pan_tilt);		if (rc) goto err_button;	}	return 0;err_button:	video_device_remove_file(vdev, &dev_attr_button);err:	return rc;}static void pwc_remove_sysfs_files(struct video_device *vdev){	struct pwc_device *pdev = video_get_drvdata(vdev);	if (pdev->features & FEATURE_MOTOR_PANTILT)		video_device_remove_file(vdev, &dev_attr_pan_tilt);	video_device_remove_file(vdev, &dev_attr_button);}#ifdef CONFIG_USB_PWC_DEBUGstatic const char *pwc_sensor_type_to_string(unsigned int sensor_type){	switch(sensor_type) {		case 0x00:			return "Hyundai CMOS sensor";		case 0x20:			return "Sony CCD sensor + TDA8787";		case 0x2E:			return "Sony CCD sensor + Exas 98L59";		case 0x2F:			return "Sony CCD sensor + ADI 9804";		case 0x30:			return "Sharp CCD sensor + TDA8787";		case 0x3E:			return "Sharp CCD sensor + Exas 98L59";		case 0x3F:			return "Sharp CCD sensor + ADI 9804";		case 0x40:			return "UPA 1021 sensor";		case 0x100:			return "VGA sensor";		case 0x101:			return "PAL MR sensor";		default:			return "unknown type of sensor";	}}#endif/***************************************************************************//* Video4Linux functions */static int pwc_video_open(struct inode *inode, struct file *file){	int i, ret;	struct video_device *vdev = video_devdata(file);	struct pwc_device *pdev;	PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);	pdev = (struct pwc_device *)vdev->priv;	BUG_ON(!pdev);	if (pdev->vopen) {		PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");		return -EBUSY;	}	mutex_lock(&pdev->modlock);	if (!pdev->usb_init) {		PWC_DEBUG_OPEN("Doing first time initialization.\n");		pdev->usb_init = 1;		/* Query sensor type */		ret = pwc_get_cmos_sensor(pdev, &i);		if (ret >= 0)		{			PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",					pdev->vdev->name,					pwc_sensor_type_to_string(i), i);		}	}	/* Turn on camera */	if (power_save) {		i = pwc_camera_power(pdev, 1);		if (i < 0)			PWC_DEBUG_OPEN("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)		PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");	pwc_construct(pdev); /* set min/max sizes correct */	/* So far, so good. Allocate memory. */	i = pwc_allocate_buffers(pdev);	if (i < 0) {		PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");		pwc_free_buffers(pdev);		mutex_unlock(&pdev->modlock);		return i;	}	/* Reset buffers & parameters */	pwc_reset_buffers(pdev);	for (i = 0; i < pwc_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;	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)	{		unsigned int default_resolution;		PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");		if (pdev->type>= 730)			default_resolution = PSZ_QSIF;		else			default_resolution = PSZ_QCIF;		i = pwc_set_video_mode(pdev,				       pwc_image_sizes[default_resolution].x,				       pwc_image_sizes[default_resolution].y,				       10,				       pdev->vcompression,				       0);	}	if (i) {		PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");		pwc_free_buffers(pdev);		mutex_unlock(&pdev->modlock);		return i;	}	i = pwc_isoc_init(pdev);	if (i) {		PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);		pwc_isoc_cleanup(pdev);		pwc_free_buffers(pdev);		mutex_unlock(&pdev->modlock);		return i;	}	/* Initialize the webcam to sane value */	pwc_set_brightness(pdev, 0x7fff);	pwc_set_agc(pdev, 1, 0);	pdev->vopen++;	file->private_data = vdev;	mutex_unlock(&pdev->modlock);	PWC_DEBUG_OPEN("<< video_open() returns 0.\n");	return 0;}static void pwc_cleanup(struct pwc_device *pdev){	pwc_remove_sysfs_files(pdev->vdev);	video_unregister_device(pdev->vdev);}/* 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, hint;	PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);	lock_kernel();	pdev = (struct pwc_device *)vdev->priv;	if (pdev->vopen == 0)		PWC_DEBUG_MODULE("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)		PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);	if (DEVICE_USE_CODEC1(pdev->type))	    pwc_dec1_exit();	else	    pwc_dec23_exit();	pwc_isoc_cleanup(pdev);	pwc_free_buffers(pdev);	/* Turn off LEDS and power down camera, but only when not unplugged */	if (!pdev->unplugged) {		/* Turn LEDs off */		if (pwc_set_leds(pdev, 0, 0) < 0)			PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");		if (power_save) {			i = pwc_camera_power(pdev, 0);			if (i < 0)				PWC_ERROR("Failed to power down camera (%d)\n", i);		}		pdev->vopen--;		PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);	} else {		pwc_cleanup(pdev);		/* Free memory (don't set pdev to 0 just yet) */		kfree(pdev);		/* search device_hint[] table if we occupy a slot, by any chance */		for (hint = 0; hint < MAX_DEV_HINTS; hint++)			if (device_hint[hint].pdev == pdev)				device_hint[hint].pdev = NULL;	}	unlock_kernel();	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 __user *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, rv = 0;	void *image_buffer_addr;	PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",			vdev, buf, count);	if (vdev == NULL)		return -EFAULT;	pdev = vdev->priv;	if (pdev == NULL)		return -EFAULT;	mutex_lock(&pdev->modlock);	if (pdev->error_status) {		rv = -pdev->error_status; /* Something happened, report what. */		goto err_out;	}	/* 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);				rv = -pdev->error_status ;				goto err_out;			}			if (noblock) {				remove_wait_queue(&pdev->frameq, &wait);				set_current_state(TASK_RUNNING);				rv = -EWOULDBLOCK;				goto err_out;			}			if (signal_pending(current)) {				remove_wait_queue(&pdev->frameq, &wait);				set_current_state(TASK_RUNNING);				rv = -ERESTARTSYS;				goto err_out;			}			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)) {			rv = -EFAULT;			goto err_out;		}	}	PWC_DEBUG_READ("Copying data to user space.\n");	if (pdev->vpalette == VIDEO_PALETTE_RAW)		bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);	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;	image_buffer_addr = pdev->image_data;	image_buffer_addr += pdev->images[pdev->fill_image].offset;	image_buffer_addr += pdev->image_read_pos;	if (copy_to_user(buf, image_buffer_addr, count)) {		rv = -EFAULT;		goto err_out;	}	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);	}	mutex_unlock(&pdev->modlock);	return count;err_out:	mutex_unlock(&pdev->modlock);	return rv;}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_ioctl(struct inode *inode, struct file *file,			   unsigned int cmd, unsigned long arg){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	int r = -ENODEV;	if (!vdev)		goto out;	pdev = vdev->priv;	mutex_lock(&pdev->modlock);	if (!pdev->unplugged)		r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);	mutex_unlock(&pdev->modlock);out:	return r;}static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma){	struct video_device *vdev = file->private_data;	struct pwc_device *pdev;	unsigned long start;	unsigned long size;	unsigned long page, pos = 0;	int index;	PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);	pdev = vdev->priv;	size = vma->vm_end - vma->vm_start;	start = vma->vm_start;	/* Find the idx buffer for this mapping */	for (index = 0; index < pwc_mbufs; index++) {		pos = pdev->images[index].offset;		if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)			break;	}	if (index == MAX_IMAGES)		return -EINVAL;	if (index == 0) {		/*		 * Special case for v4l1. In v4l1, we map only one big buffer,		 * but in v4l2 each buffer is mapped		 */		unsigned long total_size;		total_size = pwc_mbufs * pdev->len_per_image;		if (size != pdev->len_per_image && size != total_size) {			PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",				   size, pdev->len_per_image, total_size);			return -EINVAL;		}	} else if (size > pdev->len_per_image)		return -EINVAL;	vma->vm_flags |= VM_IO;	/* from 2.6.9-acX */	pos += (unsigned long)pdev->image_data;	while (size > 0) {		page = vmalloc_to_pfn((void *)pos);		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))			return -EAGAIN;		start += PAGE_SIZE;		pos += PAGE_SIZE;		if (size > PAGE_SIZE)			size -= PAGE_SIZE;		else			size = 0;	}	return 0;}/***************************************************************************//* USB functions *//* This function gets called when a new device is plugged in or the usb core * is loaded. */static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	struct pwc_device *pdev = NULL;	int vendor_id, product_id, type_id;	int i, hint, rc;	int features = 0;	int video_nr = -1; /* default: use next available device */	char serial_number[30], *name;	vendor_id = le16_to_cpu(udev->descriptor.idVendor);	product_id = le16_to_cpu(udev->descriptor.idProduct);	/* Check if we can handle this device */	PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",		vendor_id, product_id,		intf->altsetting->desc.bInterfaceNumber);	/* the interfaces are probed one by one. We are only interested in the	   video interface (0) now.	   Interface 1 is the Audio Control, and interface 2 Audio itself.	 */	if (intf->altsetting->desc.bInterfaceNumber > 0)		return -ENODEV;	if (vendor_id == 0x0471) {		switch (product_id) {		case 0x0302:			PWC_INFO("Philips PCA645VC USB webcam detected.\n");			name = "Philips 645 webcam";			type_id = 645;			break;		case 0x0303:			PWC_INFO("Philips PCA646VC USB webcam detected.\n");			name = "Philips 646 webcam";			type_id = 646;			break;		case 0x0304:			PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");			name = "Askey VC010 webcam";			type_id = 646;			break;		case 0x0307:			PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");			name = "Philips 675 webcam";			type_id = 675;			break;		case 0x0308:			PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");			name = "Philips 680 webcam";			type_id = 680;			break;		case 0x030C:			PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");			name = "Philips 690 webcam";			type_id = 690;			break;		case 0x0310:			PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");			name = "Philips 730 webcam";			type_id = 730;			break;		case 0x0311:			PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");			name = "Philips 740 webcam";			type_id = 740;			break;		case 0x0312:			PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");			name = "Philips 750 webcam";			type_id = 750;			break;		case 0x0313:			PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");			name = "Philips 720K/40 webcam";			type_id = 720;			break;		case 0x0329:			PWC_INFO("Philips SPC 900NC USB webcam detected.\n");			name = "Philips SPC 900NC webcam";			type_id = 740;			break;		default:			return -ENODEV;			break;		}

⌨️ 快捷键说明

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