📄 em28xx-video.c
字号:
f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); list_del(dev->outqueue.next); spin_unlock_irqrestore(&dev->queue_lock, lock_flags); f->state = F_UNUSED; memcpy(b, &f->buf, sizeof(*b)); if (f->vma_use_count) b->flags |= V4L2_BUF_FLAG_MAPPED; return 0; } default: return em28xx_do_ioctl(inode, filp, dev, cmd, arg, em28xx_video_do_ioctl); } return 0;}/* * em28xx_v4l2_ioctl() * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl() */static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int ret = 0; struct em28xx *dev = filp->private_data; if (mutex_lock_interruptible(&dev->fileop_lock)) return -ERESTARTSYS; if (dev->state & DEV_DISCONNECTED) { em28xx_errdev("v4l2 ioctl: device not present\n"); mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_errdev ("v4l2 ioctl: device is misconfigured; close and open it again\n"); mutex_unlock(&dev->fileop_lock); return -EIO; } ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); mutex_unlock(&dev->fileop_lock); return ret;}static struct file_operations em28xx_v4l_fops = { .owner = THIS_MODULE, .open = em28xx_v4l2_open, .release = em28xx_v4l2_close, .ioctl = em28xx_v4l2_ioctl, .read = em28xx_v4l2_read, .poll = em28xx_v4l2_poll, .mmap = em28xx_v4l2_mmap, .llseek = no_llseek, .compat_ioctl = v4l_compat_ioctl32,};/******************************** usb interface *****************************************//* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, int minor, int model){ struct em28xx *dev = *devhandle; int retval = -ENOMEM; int errCode, i; unsigned int maxh, maxw; dev->udev = udev; dev->model = model; mutex_init(&dev->lock); init_waitqueue_head(&dev->open); dev->em28xx_write_regs = em28xx_write_regs; dev->em28xx_read_reg = em28xx_read_reg; dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->is_em2800 = em28xx_boards[model].is_em2800; dev->has_tuner = em28xx_boards[model].has_tuner; dev->has_msp34xx = em28xx_boards[model].has_msp34xx; dev->tda9887_conf = em28xx_boards[model].tda9887_conf; dev->decoder = em28xx_boards[model].decoder; if (tuner >= 0) dev->tuner_type = tuner; else dev->tuner_type = em28xx_boards[model].tuner_type; dev->video_inputs = em28xx_boards[model].vchannels; for (i = 0; i < TVNORMS; i++) if (em28xx_boards[model].norm == tvnorms[i].mode) break; if (i == TVNORMS) i = 0; dev->tvnorm = &tvnorms[i]; /* set default norm */ em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); maxw = norm_maxw(dev); maxh = norm_maxh(dev); /* set default image size */ dev->width = maxw; dev->height = maxh; dev->interlaced = EM28XX_INTERLACED_DEFAULT; dev->field_size = dev->width * dev->height; dev->frame_size = dev->interlaced ? dev->field_size << 1 : dev->field_size; dev->bytesperline = dev->width * 2; dev->hscale = 0; dev->vscale = 0; dev->ctl_input = 2; /* setup video picture settings for saa7113h */ memset(&dev->vpic, 0, sizeof(dev->vpic)); dev->vpic.colour = 128 << 8; dev->vpic.hue = 128 << 8; dev->vpic.brightness = 128 << 8; dev->vpic.contrast = 192 << 8; dev->vpic.whiteness = 128 << 8; /* This one isn't used */ dev->vpic.depth = 16; dev->vpic.palette = VIDEO_PALETTE_YUV422; em28xx_pre_card_setup(dev);#ifdef CONFIG_MODULES /* request some modules */ if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) request_module("saa7115"); if (dev->decoder == EM28XX_TVP5150) request_module("tvp5150"); if (dev->has_tuner) request_module("tuner"); if (dev->tda9887_conf) request_module("tda9887");#endif errCode = em28xx_config(dev); if (errCode) { em28xx_errdev("error configuring device\n"); em28xx_devused&=~(1<<dev->devno); kfree(dev); return -ENOMEM; } mutex_lock(&dev->lock); /* register i2c bus */ em28xx_i2c_register(dev); /* Do board specific init and eeprom reading */ em28xx_card_setup(dev); /* configure the device */ em28xx_config_i2c(dev); mutex_unlock(&dev->lock); errCode = em28xx_config(dev);#ifdef CONFIG_MODULES if (dev->has_msp34xx) request_module("msp3400");#endif /* allocate and fill v4l2 device struct */ dev->vdev = video_device_alloc(); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); em28xx_devused&=~(1<<dev->devno); kfree(dev); return -ENOMEM; } dev->vbi_dev = video_device_alloc(); if (NULL == dev->vbi_dev) { em28xx_errdev("cannot allocate video_device.\n"); kfree(dev->vdev); em28xx_devused&=~(1<<dev->devno); kfree(dev); return -ENOMEM; } /* Fills VBI device info */ dev->vbi_dev->type = VFL_TYPE_VBI; dev->vbi_dev->hardware = 0; dev->vbi_dev->fops = &em28xx_v4l_fops; dev->vbi_dev->minor = -1; dev->vbi_dev->dev = &dev->udev->dev; dev->vbi_dev->release = video_device_release; snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", "em28xx",dev->devno,"vbi"); /* Fills CAPTURE device info */ dev->vdev->type = VID_TYPE_CAPTURE; if (dev->has_tuner) dev->vdev->type |= VID_TYPE_TUNER; dev->vdev->hardware = 0; dev->vdev->fops = &em28xx_v4l_fops; dev->vdev->minor = -1; dev->vdev->dev = &dev->udev->dev; dev->vdev->release = video_device_release; snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", "em28xx",dev->devno,"video"); list_add_tail(&dev->devlist,&em28xx_devlist); /* register v4l2 device */ mutex_lock(&dev->lock); if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", retval); mutex_unlock(&dev->lock); list_del(&dev->devlist); video_device_release(dev->vdev); em28xx_devused&=~(1<<dev->devno); kfree(dev); return -ENODEV; } if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { printk("unable to register vbi device\n"); mutex_unlock(&dev->lock); list_del(&dev->devlist); video_device_release(dev->vbi_dev); video_device_release(dev->vdev); em28xx_devused&=~(1<<dev->devno); kfree(dev); return -ENODEV; } else { printk("registered VBI\n"); } if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); udelay(2500); em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); udelay(2500); } video_mux(dev, 0); mutex_unlock(&dev->lock); em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); return 0;}/* * em28xx_usb_probe() * checks for supported devices */static int em28xx_usb_probe(struct usb_interface *interface, const struct usb_device_id *id){ const struct usb_endpoint_descriptor *endpoint; struct usb_device *udev; struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; int model,i,nr,ifnum; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; /* Check to see next free device and mark as used */ nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS); em28xx_devused|=1<<nr; /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n", udev->descriptor.idVendor,udev->descriptor.idProduct, ifnum, interface->altsetting[0].desc.bInterfaceClass); em28xx_devused&=~(1<<nr); return -ENODEV; } em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", udev->descriptor.idVendor,udev->descriptor.idProduct, ifnum, interface->altsetting[0].desc.bInterfaceClass); endpoint = &interface->cur_altsetting->endpoint[1].desc; /* check if the the device has the iso in endpoint at the correct place */ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); em28xx_devused&=~(1<<nr); return -ENODEV; } if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); em28xx_devused&=~(1<<nr); return -ENODEV; } model=id->driver_info; if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<<nr); return -ENOMEM; } /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { em28xx_err(DRIVER_NAME ": out of memory!\n"); em28xx_devused&=~(1<<nr); return -ENOMEM; } snprintf(dev->name, 29, "em28xx #%d", nr); dev->devno=nr; /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; dev->num_alt=uif->num_altsetting; em28xx_info("Alternate settings: %i\n",dev->num_alt);// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* dev->alt_max_pkt_size = kmalloc(32* dev->num_alt,GFP_KERNEL); if (dev->alt_max_pkt_size == NULL) { em28xx_errdev("out of memory!\n"); em28xx_devused&=~(1<<nr); return -ENOMEM; } for (i = 0; i < dev->num_alt ; i++) { u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. wMaxPacketSize); dev->alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); em28xx_info("Alternate setting %i, max size= %i\n",i, dev->alt_max_pkt_size[i]); } if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) model=card[nr]; if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { em28xx_errdev( "Your board has no eeprom inside it and thus can't\n" "%s: be autodetected. Please pass card=<n> insmod option to\n" "%s: workaround that. Redirect complaints to the vendor of\n" "%s: the TV card. Generic type will be used." "%s: Best regards,\n" "%s: -- tux\n", dev->name,dev->name,dev->name,dev->name,dev->name); em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n", dev->name); for (i = 0; i < em28xx_bcount; i++) { em28xx_errdev(" card=%d -> %s\n", i, em28xx_boards[i].name); } } /* allocate device struct */ retval = em28xx_init_dev(&dev, udev, nr, model); if (retval) return retval; em28xx_info("Found %s\n", em28xx_boards[model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); return 0;}/* * em28xx_usb_disconnect() * called when the device gets diconencted * video device will be unregistered on v4l2_close in case it is still open */static void em28xx_usb_disconnect(struct usb_interface *interface){ struct em28xx *dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!dev) return; down_write(&em28xx_disconnect); mutex_lock(&dev->lock); em28xx_info("disconnecting %s\n", dev->vdev->name); wake_up_interruptible_all(&dev->open); if (dev->users) { em28xx_warn ("device /dev/video%d is open! Deregistration and memory " "deallocation are deferred on close.\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); dev->state |= DEV_MISCONFIGURED; em28xx_uninit_isoc(dev); dev->state |= DEV_DISCONNECTED; wake_up_interruptible(&dev->wait_frame); wake_up_interruptible(&dev->wait_stream); } else { dev->state |= DEV_DISCONNECTED; em28xx_release_resources(dev); } mutex_unlock(&dev->lock); if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); } up_write(&em28xx_disconnect);}static struct usb_driver em28xx_usb_driver = { .name = "em28xx", .probe = em28xx_usb_probe, .disconnect = em28xx_usb_disconnect, .id_table = em28xx_id_table,};static int __init em28xx_module_init(void){ int result; printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n", (EM28XX_VERSION_CODE >> 16) & 0xff, (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);#ifdef SNAPSHOT printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n", SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);#endif /* register this driver with the USB subsystem */ result = usb_register(&em28xx_usb_driver); if (result) em28xx_err(DRIVER_NAME " usb_register failed. Error number %d.\n", result); return result;}static void __exit em28xx_module_exit(void){ /* deregister this driver with the USB subsystem */ usb_deregister(&em28xx_usb_driver);}module_init(em28xx_module_init);module_exit(em28xx_module_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -