📄 pwc-if.c
字号:
p->brightness = val; else p->brightness = 0xffff; val = pwc_get_contrast(pdev); if (val >= 0) p->contrast = val; else p->contrast = 0xffff; /* Gamma, Whiteness, what's the difference? :) */ val = pwc_get_gamma(pdev); if (val >= 0) p->whiteness = val; else p->whiteness = 0xffff; val = pwc_get_saturation(pdev); if (val >= 0) p->colour = val; else p->colour = 0xffff; p->depth = 24; p->palette = pdev->vpalette; p->hue = 0xFFFF; /* N/A */ break; } case VIDIOCSPICT: { struct video_picture *p = arg; /* * FIXME: Suppose we are mid read ANSWER: No problem: the firmware of the camera can handle brightness/contrast/etc changes at _any_ time, and the palette is used exactly once in the uncompress routine. */ pwc_set_brightness(pdev, p->brightness); pwc_set_contrast(pdev, p->contrast); pwc_set_gamma(pdev, p->whiteness); pwc_set_saturation(pdev, p->colour); if (p->palette && p->palette != pdev->vpalette) { switch (p->palette) { case VIDEO_PALETTE_YUV420P: case VIDEO_PALETTE_RAW: pdev->vpalette = p->palette; return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); break; default: return -EINVAL; break; } } break; } /* Window/size parameters */ case VIDIOCGWIN: { struct video_window *vw = arg; vw->x = 0; vw->y = 0; vw->width = pdev->view.x; vw->height = pdev->view.y; vw->chromakey = 0; vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); break; } case VIDIOCSWIN: { struct video_window *vw = arg; int fps, snapshot, ret; fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; snapshot = vw->flags & PWC_FPS_SNAPSHOT; if (fps == 0) fps = pdev->vframes; if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) return 0; ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); if (ret) return ret; break; } /* We don't have overlay support (yet) */ case VIDIOCGFBUF: { struct video_buffer *vb = arg; memset(vb,0,sizeof(*vb)); break; } /* mmap() functions */ case VIDIOCGMBUF: { /* Tell the user program how much memory is needed for a mmap() */ struct video_mbuf *vm = arg; int i; memset(vm, 0, sizeof(*vm)); vm->size = default_mbufs * pdev->len_per_image; vm->frames = default_mbufs; /* double buffering should be enough for most applications */ for (i = 0; i < default_mbufs; i++) vm->offsets[i] = i * pdev->len_per_image; break; } case VIDIOCMCAPTURE: { /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ struct video_mmap *vm = arg; Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); if (vm->frame < 0 || vm->frame >= default_mbufs) return -EINVAL; /* xawtv is nasty. It probes the available palettes by setting a very small image size and trying various palettes... The driver doesn't support such small images, so I'm working around it. */ if (vm->format) { switch (vm->format) { case VIDEO_PALETTE_YUV420P: case VIDEO_PALETTE_RAW: break; default: return -EINVAL; break; } } if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { int ret; Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); if (ret) return ret; } /* ... size mismatch */ /* FIXME: should we lock here? */ if (pdev->image_used[vm->frame]) return -EBUSY; /* buffer wasn't available. Bummer */ pdev->image_used[vm->frame] = 1; /* Okay, we're done here. In the SYNC call we wait until a frame comes available, then expand image into the given buffer. In contrast to the CPiA cam the Philips cams deliver a constant stream, almost like a grabber card. Also, we have separate buffers for the rawdata and the image, meaning we can nearly always expand into the requested buffer. */ Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); break; } case VIDIOCSYNC: { /* The doc says: "Whenever a buffer is used it should call VIDIOCSYNC to free this frame up and continue." The only odd thing about this whole procedure is that MCAPTURE flags the buffer as "in use", and SYNC immediately unmarks it, while it isn't after SYNC that you know that the buffer actually got filled! So you better not start a CAPTURE in the same frame immediately (use double buffering). This is not a problem for this cam, since it has extra intermediate buffers, but a hardware grabber card will then overwrite the buffer you're working on. */ int *mbuf = arg; int ret; Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); /* bounds check */ if (*mbuf < 0 || *mbuf >= default_mbufs) return -EINVAL; /* check if this buffer was requested anyway */ if (pdev->image_used[*mbuf] == 0) return -EINVAL; /* Add ourselves to the frame wait-queue. FIXME: needs auditing for safety. QUESTION: In what respect? I think that using the frameq is safe now. */ add_wait_queue(&pdev->frameq, &wait); while (pdev->full_frames == NULL) { if (pdev->error_status) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); return -pdev->error_status; } 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); /* The frame is ready. Expand in the image buffer requested by the user. I don't care if you mmap() 5 buffers and request data in this order: buffer 4 2 3 0 1 2 3 0 4 3 1 . . . Grabber hardware may not be so forgiving. */ Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ /* Decompress, etc */ ret = pwc_handle_frame(pdev); pdev->image_used[*mbuf] = 0; if (ret) return -EFAULT; break; } case VIDIOCGAUDIO: { struct video_audio *v = arg; strcpy(v->name, "Microphone"); v->audio = -1; /* unknown audio minor */ v->flags = 0; v->mode = VIDEO_SOUND_MONO; v->volume = 0; v->bass = 0; v->treble = 0; v->balance = 0x8000; v->step = 1; break; } case VIDIOCSAUDIO: { /* Dummy: nothing can be set */ break; } case VIDIOCGUNIT: { struct video_unit *vu = arg; vu->video = pdev->vdev->minor & 0x3F; vu->audio = -1; /* not known yet */ vu->vbi = -1; vu->radio = -1; vu->teletext = -1; break; } default: return pwc_ioctl(pdev, cmd, arg); } /* ..switch */ 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 = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); pdev = vdev->priv; pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_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; int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; /* Check if we can handle this device */ Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", udev->descriptor.idVendor, udev->descriptor.idProduct, 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; vendor_id = udev->descriptor.idVendor; product_id = udev->descriptor.idProduct; if (vendor_id == 0x0471) { switch (product_id) { case 0x0302: Info("Philips PCA645VC USB webcam detected.\n"); name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: Info("Philips PCA646VC USB webcam detected.\n"); name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: Info("Askey VC010 type 2 USB webcam detected.\n"); name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); name = "Philips 750 webcam"; type_id = 750; break; case 0x0313: Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); name = "Philips 720K/40 webcam"; type_id = 720; break; default: return -ENODEV; break; } } else if (vendor_id == 0x069A) { switch(product_id) { case 0x0001: 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: Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); name = "Logitech QuickCam Pro 3000"; type_id = 740; /* CCD sensor */ break; case 0x08b1: Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); name = "Logitech QuickCam Notebook Pro"; type_id = 740; /* CCD sensor */ break; case 0x08b2: Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); name = "Logitech QuickCam Pro 4000"; type_id = 740; /* CCD sensor */ break; case 0x08b3: Info("Logitech QuickCam Zoom USB webcam detected.\n"); name = "Logitech QuickCam Zoom"; type_id = 740; /* CCD sensor */ break; case 0x08B4: Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); name = "Logitech QuickCam Zoom";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -