📄 pwc-if.c
字号:
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); 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->error_status != EPIPE) { /* 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); 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; 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; 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; } 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)) 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_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);}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) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) page = kvirt_to_pa(pos); if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN;#else page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN;#endif 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; int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) vendor_id = udev->descriptor.idVendor; product_id = udev->descriptor.idProduct;#else vendor_id = le16_to_cpu(udev->descriptor.idVendor); product_id = le16_to_cpu(udev->descriptor.idProduct);#endif /* 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 = 720; break; default: return -ENODEV; break; } } else if (vendor_id == 0x069A) { switch(product_id) { case 0x0001: PWC_INFO("Askey VC010 type 1 USB webcam detected.\n"); name = "Askey VC010 webcam"; type_id = 645; break; default: return -ENODEV; break; } } else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n"); name = "Logitech QuickCam Pro 3000"; type_id = 740; /* CCD sensor */ break; case 0x08b1: PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n"); name = "Logitech QuickCam Notebook Pro"; type_id = 740; /* CCD sensor */ break; case 0x08b2: PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); name = "Logitech QuickCam Pro 4000"; type_id = 740; /* CCD sensor */ break; case 0x08b3: PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); name = "Logitech QuickCam Zoom"; type_id = 740; /* CCD sensor */ break; case 0x08B4: PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); name = "Logitech QuickCam Zoom"; type_id = 740; /* CCD sensor */ power_save = 1; break; case 0x08b5: PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); name = "Logitech QuickCam Orbit"; type_id = 740; /* CCD sensor */ features |= FEATURE_MOTOR_PANTILT; break; case 0x08b6: case 0x08b7: case 0x08b8: PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); name = "Logitech QuickCam (res.)"; type_id = 730; /* Assuming CMOS */ break; default: return -ENODEV; break; } } else if (vendor_id == 0x055d) { /* I don't know the difference between the C10 and the C30; I suppose the difference is the sensor, but both cameras work equally well with a type_id of 675 */ switch(product_id) { case 0x9000: PWC_INFO("Samsung MPC-C10 USB webcam detected.\n"); name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: PWC_INFO("Samsung MPC-C30 USB webcam detected.\n"); name = "Samsung MPC-C30"; type_id = 675; break; case 0x9002: PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n"); name = "Samsung MPC-C30"; type_id = 740; break; default: return -ENODEV; break; } } else if (vendor_id == 0x041e) { switch(product_id) { case 0x400c: PWC_INFO("Creative Labs Webcam 5 detected.\n"); name = "Creative Labs Webcam 5"; type_id = 730; break; case 0x4011: PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); name = "Creative Labs Webcam Pro Ex"; type_id = 740; break; default: return -ENODEV; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -