📄 stv680.c
字号:
bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; stv680->scratch_use++; if (stv680->scratch_use >= STV680_NUMSCRATCH) stv680->scratch_use = 0; if (errors > STV680_MAX_ERRORS) { errors = 0; PDEBUG (2, "STV(i): too many errors, restarting capture"); stv680_stop_stream (stv680); stv680_start_stream (stv680); } } /* else */ } /* while */ return 0;}/********************************************************************* * Video4Linux *********************************************************************/static int stv_open (struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); struct usb_stv *stv680 = video_get_drvdata(dev); int err = 0; /* we are called with the BKL held */ stv680->user = 1; err = stv_init (stv680); /* main initialization routine for camera */ if (err >= 0) { stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); if (!stv680->fbuf) { PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); err = -ENOMEM; } file->private_data = dev; } if (err) stv680->user = 0; return err;}static int stv_close (struct inode *inode, struct file *file){ struct video_device *dev = file->private_data; struct usb_stv *stv680 = video_get_drvdata(dev); int i; for (i = 0; i < STV680_NUMFRAMES; i++) stv680->frame[i].grabstate = FRAME_UNUSED; if (stv680->streaming) stv680_stop_stream (stv680); if ((i = stv_stop_video (stv680)) < 0) PDEBUG (1, "STV(e): stop_video failed in stv_close"); rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); stv680->user = 0; if (stv680->removed) { kfree (stv680); stv680 = NULL; PDEBUG (0, "STV(i): device unregistered"); } file->private_data = NULL; return 0;}static int stv680_do_ioctl (struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct video_device *vdev = file->private_data; struct usb_stv *stv680 = video_get_drvdata(vdev); if (!stv680->udev) return -EIO; switch (cmd) { case VIDIOCGCAP:{ struct video_capability *b = arg; strcpy (b->name, stv680->camera_name); b->type = VID_TYPE_CAPTURE; b->channels = 1; b->audios = 0; b->maxwidth = stv680->maxwidth; b->maxheight = stv680->maxheight; b->minwidth = stv680->maxwidth / 2; b->minheight = stv680->maxheight / 2; return 0; } 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, "STV Camera"); return 0; } case VIDIOCSCHAN:{ struct video_channel *v = arg; if (v->channel != 0) return -EINVAL; return 0; } case VIDIOCGPICT:{ struct video_picture *p = arg; stv680_get_pict (stv680, p); return 0; } case VIDIOCSPICT:{ struct video_picture *p = arg; if (stv680_set_pict (stv680, p)) return -EINVAL; return 0; } case VIDIOCSWIN:{ struct video_window *vw = arg; if (vw->flags) return -EINVAL; if (vw->clipcount) return -EINVAL; if (vw->width != stv680->vwidth) { if (stv680_set_size (stv680, vw->width, vw->height)) { PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); return -EINVAL; } } return 0; } case VIDIOCGWIN:{ struct video_window *vw = arg; vw->x = 0; /* FIXME */ vw->y = 0; vw->chromakey = 0; vw->flags = 0; vw->clipcount = 0; vw->width = stv680->vwidth; vw->height = stv680->vheight; return 0; } case VIDIOCGMBUF:{ struct video_mbuf *vm = arg; int i; memset (vm, 0, sizeof (*vm)); vm->size = STV680_NUMFRAMES * stv680->maxframesize; vm->frames = STV680_NUMFRAMES; for (i = 0; i < STV680_NUMFRAMES; i++) vm->offsets[i] = stv680->maxframesize * i; return 0; } case VIDIOCMCAPTURE:{ struct video_mmap *vm = arg; if (vm->format != STV_VIDEO_PALETTE) { PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", vm->format, STV_VIDEO_PALETTE); if ((vm->format == 3) && (swapRGB_on == 0)) { PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); /* this may fix those apps (e.g., xawtv) that want BGR */ swapRGB = 1; } return -EINVAL; } if (vm->frame >= STV680_NUMFRAMES) { PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); return -EINVAL; } if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR) || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) { PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", stv680->frame[vm->frame].grabstate); return -EBUSY; } /* Is this according to the v4l spec??? */ if (stv680->vwidth != vm->width) { if (stv680_set_size (stv680, vm->width, vm->height)) { PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); return -EINVAL; } } stv680->frame[vm->frame].grabstate = FRAME_READY; if (!stv680->streaming) stv680_start_stream (stv680); return 0; } case VIDIOCSYNC:{ int *frame = arg; int ret = 0; if (*frame < 0 || *frame >= STV680_NUMFRAMES) { PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); return -EINVAL; } ret = stv680_newframe (stv680, *frame); stv680->frame[*frame].grabstate = FRAME_UNUSED; return ret; } case VIDIOCGFBUF:{ struct video_buffer *vb = arg; memset (vb, 0, sizeof (*vb)); return 0; } case VIDIOCKEY: return 0; case VIDIOCCAPTURE: { PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); return -EINVAL; } case VIDIOCSFBUF: case VIDIOCGTUNER: case VIDIOCSTUNER: case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGAUDIO: case VIDIOCSAUDIO: return -EINVAL; default: return -ENOIOCTLCMD; } /* end switch */ return 0;}static int stv680_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);}static int stv680_mmap (struct file *file, struct vm_area_struct *vma){ struct video_device *dev = file->private_data; struct usb_stv *stv680 = video_get_drvdata(dev); unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; down (&stv680->lock); if (stv680->udev == NULL) { up (&stv680->lock); return -EIO; } if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { up (&stv680->lock); return -EINVAL; } pos = (unsigned long) stv680->fbuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { up (&stv680->lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } up (&stv680->lock); return 0;}static ssize_t stv680_read (struct file *file, char __user *buf, size_t count, loff_t *ppos){ struct video_device *dev = file->private_data; unsigned long int realcount = count; int ret = 0; struct usb_stv *stv680 = video_get_drvdata(dev); unsigned long int i; if (STV680_NUMFRAMES != 2) { PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); return -1; } if (stv680->udev == NULL) return -EIO; if (realcount > (stv680->vwidth * stv680->vheight * 3)) realcount = stv680->vwidth * stv680->vheight * 3; /* Shouldn't happen: */ if (stv680->frame[0].grabstate == FRAME_GRABBING) { PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); return -EBUSY; } stv680->frame[0].grabstate = FRAME_READY; stv680->frame[1].grabstate = FRAME_UNUSED; stv680->curframe = 0; if (!stv680->streaming) stv680_start_stream (stv680); if (!stv680->streaming) { ret = stv680_newframe (stv680, 0); /* ret should = 0 */ } ret = stv680_newframe (stv680, 0); if (!ret) { if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); return -EFAULT; } } else { realcount = ret; } stv680->frame[0].grabstate = FRAME_UNUSED; return realcount;} /* stv680_read */static struct file_operations stv680_fops = { .owner = THIS_MODULE, .open = stv_open, .release = stv_close, .read = stv680_read, .mmap = stv680_mmap, .ioctl = stv680_ioctl, .llseek = no_llseek,};static struct video_device stv680_template = { .owner = THIS_MODULE, .name = "STV0680 USB camera", .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_SE401, .fops = &stv680_fops, .release = video_device_release, .minor = -1,};static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_stv *stv680 = NULL; char *camera_name = NULL; int retval = 0; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) { PDEBUG (0, "STV(e): Number of Configurations != 1"); return -ENODEV; } interface = &intf->altsetting[0]; /* Is it a STV680? */ if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { camera_name = "STV0680"; PDEBUG (0, "STV(i): STV0680 camera found."); } else { PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values."); PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer."); retval = -ENODEV; goto error; } /* We found one */ if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); retval = -ENOMEM; goto error; } memset (stv680, 0, sizeof (*stv680)); stv680->udev = dev; stv680->camera_name = camera_name; stv680->vdev = video_device_alloc(); if (!stv680->vdev) { retval = -ENOMEM; goto error; } memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); stv680->vdev->dev = &intf->dev; video_set_drvdata(stv680->vdev, stv680); memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); init_waitqueue_head (&stv680->wq); init_MUTEX (&stv680->lock); wmb (); if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { PDEBUG (0, "STV(e): video_register_device failed"); retval = -EIO; goto error_vdev; } PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); usb_set_intfdata (intf, stv680); stv680_create_sysfs_files(stv680->vdev); return 0;error_vdev: video_device_release(stv680->vdev);error: kfree(stv680); return retval;}static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680){ int i; stv680->udev = NULL; stv680->frame[0].grabstate = FRAME_ERROR; stv680->frame[1].grabstate = FRAME_ERROR; stv680->streaming = 0; wake_up_interruptible (&stv680->wq); for (i = 0; i < STV680_NUMSBUF; i++) if (stv680->urb[i]) { usb_kill_urb (stv680->urb[i]); usb_free_urb (stv680->urb[i]); stv680->urb[i] = NULL; kfree (stv680->sbuf[i].data); } for (i = 0; i < STV680_NUMSCRATCH; i++) kfree (stv680->scratch[i].data); PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); /* Free the memory */ kfree (stv680);}static void stv680_disconnect (struct usb_interface *intf){ struct usb_stv *stv680 = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); if (stv680) { /* We don't want people trying to open up the device */ if (stv680->vdev) { stv680_remove_sysfs_files(stv680->vdev); video_unregister_device(stv680->vdev); stv680->vdev = NULL; } if (!stv680->user) { usb_stv680_remove_disconnected (stv680); } else { stv680->removed = 1; } }}static struct usb_driver stv680_driver = { .owner = THIS_MODULE, .name = "stv680", .probe = stv680_probe, .disconnect = stv680_disconnect, .id_table = device_table};/******************************************************************** * Module routines ********************************************************************/static int __init usb_stv680_init (void){ if (usb_register (&stv680_driver) < 0) { PDEBUG (0, "STV(e): Could not setup STV0680 driver"); return -1; } PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION); return 0;}static void __exit usb_stv680_exit (void){ usb_deregister (&stv680_driver); PDEBUG (0, "STV(i): driver deregistered");}module_init (usb_stv680_init);module_exit (usb_stv680_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -