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

📄 tm6000-video.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (!dev)		return;	spin_lock_irqsave(&dev->slock, flags);	get_next_buf(dma_q, &buf);	if (buf)		 tm6000_isoc_copy(urb, &buf);	spin_unlock_irqrestore(&dev->slock, flags);#if 0	/* Reset urb buffers */	for (i = 0; i < urb->number_of_packets; i++) {		urb->iso_frame_desc[i].status = 0;		urb->iso_frame_desc[i].actual_length = 0;	}#endif	urb->status = usb_submit_urb(urb, GFP_ATOMIC);	if (urb->status)		tm6000_err("urb resubmit failed (error=%i)\n",			urb->status);}/* * Stop and Deallocate URBs */static void tm6000_uninit_isoc(struct tm6000_core *dev){	struct urb *urb;	int i;	dev->isoc_ctl.nfields = -1;	dev->isoc_ctl.buf = NULL;	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {		urb=dev->isoc_ctl.urb[i];		if (urb) {			usb_kill_urb(urb);			usb_unlink_urb(urb);			if (dev->isoc_ctl.transfer_buffer[i]) {				usb_buffer_free(dev->udev,						urb->transfer_buffer_length,						dev->isoc_ctl.transfer_buffer[i],						urb->transfer_dma);			}			usb_free_urb(urb);			dev->isoc_ctl.urb[i] = NULL;		}		dev->isoc_ctl.transfer_buffer[i] = NULL;	}	kfree (dev->isoc_ctl.urb);	kfree (dev->isoc_ctl.transfer_buffer);	dev->isoc_ctl.urb=NULL;	dev->isoc_ctl.transfer_buffer=NULL;	dev->isoc_ctl.num_bufs = 0;	dev->isoc_ctl.num_bufs=0;}/* * Allocate URBs and start IRQ */static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize){	struct tm6000_dmaqueue *dma_q = &dev->vidq;	int i, j, sb_size, pipe, size, max_packets, num_bufs = 5;	struct urb *urb;	/* De-allocates all pending stuff */	tm6000_uninit_isoc(dev);	pipe = usb_rcvisocpipe(dev->udev,			       dev->isoc_in->desc.bEndpointAddress &			       USB_ENDPOINT_NUMBER_MASK);	size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));	if (size > dev->max_isoc_in)		size = dev->max_isoc_in;	dev->isoc_ctl.max_pkt_size = size;	max_packets = ( framesize + size - 1) / size;	if (max_packets > TM6000_MAX_ISO_PACKETS)		max_packets = TM6000_MAX_ISO_PACKETS;	sb_size = max_packets * size;	dev->isoc_ctl.num_bufs = num_bufs;	dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);	if (!dev->isoc_ctl.urb) {		tm6000_err("cannot alloc memory for usb buffers\n");		return -ENOMEM;	}	dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,				   GFP_KERNEL);	if (!dev->isoc_ctl.urb) {		tm6000_err("cannot allocate memory for usbtransfer\n");		kfree(dev->isoc_ctl.urb);		return -ENOMEM;	}	dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"		    " (%d bytes) of %d bytes each to handle %u size\n",		    max_packets, num_bufs, sb_size,		    dev->max_isoc_in, size);#if 0	/* reset streaming vars */	dev->isoc_ctl.frame_current = NULL;	dev->isoc_ctl.frame_count = 0;#endif	/* allocate urbs and transfer buffers */	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {		urb = usb_alloc_urb(max_packets, GFP_KERNEL);		if (!urb) {			tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);			tm6000_uninit_isoc(dev);			usb_free_urb(urb);			return -ENOMEM;		}		dev->isoc_ctl.urb[i] = urb;		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,			sb_size, GFP_KERNEL, &urb->transfer_dma);		if (!dev->isoc_ctl.transfer_buffer[i]) {			tm6000_err ("unable to allocate %i bytes for transfer"					" buffer %i%s\n",					sb_size, i,					in_interrupt()?" while in int":"");			tm6000_uninit_isoc(dev);			return -ENOMEM;		}		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);		usb_fill_bulk_urb(urb, dev->udev, pipe,				  dev->isoc_ctl.transfer_buffer[i], sb_size,				  tm6000_irq_callback, dma_q);		urb->interval = dev->isoc_in->desc.bInterval;		urb->number_of_packets = max_packets;		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;		for (j = 0; j < max_packets; j++) {			urb->iso_frame_desc[j].offset = size * j;			urb->iso_frame_desc[j].length = size;		}	}	return 0;}static int tm6000_start_thread( struct tm6000_core *dev){	struct tm6000_dmaqueue *dma_q = &dev->vidq;	int i;	dma_q->frame=0;	dma_q->ini_jiffies=jiffies;	init_waitqueue_head(&dma_q->wq);	/* submit urbs and enables IRQ */	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {		int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);		if (rc) {			tm6000_err("submit of urb %i failed (error=%i)\n", i,				   rc);			tm6000_uninit_isoc(dev);			return rc;		}	}	return 0;}/* ------------------------------------------------------------------	Videobuf operations   ------------------------------------------------------------------*/static intbuffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size){	struct tm6000_fh *fh = vq->priv_data;	*size = fh->fmt->depth * fh->width * fh->height >> 3;	if (0 == *count)		*count = TM6000_DEF_BUF;	if (*count < TM6000_MIN_BUF) {		*count=TM6000_MIN_BUF;	}	while (*size * *count > vid_limit * 1024 * 1024)		(*count)--;	return 0;}static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf){	struct tm6000_fh *fh = vq->priv_data;	struct tm6000_core   *dev = fh->dev;	unsigned long flags;	if (in_interrupt())		BUG();	/* We used to wait for the buffer to finish here, but this didn't work	   because, as we were keeping the state as VIDEOBUF_QUEUED,	   videobuf_queue_cancel marked it as finished for us.	   (Also, it could wedge forever if the hardware was misconfigured.)	   This should be safe; by the time we get here, the buffer isn't	   queued anymore. If we ever start marking the buffers as	   VIDEOBUF_ACTIVE, it won't be, though.	*/	spin_lock_irqsave(&dev->slock, flags);	if (dev->isoc_ctl.buf == buf)		dev->isoc_ctl.buf = NULL;	spin_unlock_irqrestore(&dev->slock, flags);	videobuf_vmalloc_free(&buf->vb);	buf->vb.state = VIDEOBUF_NEEDS_INIT;}static intbuffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,						enum v4l2_field field){	struct tm6000_fh     *fh  = vq->priv_data;	struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);	struct tm6000_core   *dev = fh->dev;	int rc = 0, urb_init = 0;	BUG_ON(NULL == fh->fmt);#if 0	if (fh->width  < norm_minw(core) || fh->width  > norm_maxw(core) ||	    fh->height < norm_minh(core) || fh->height > norm_maxh(core)) {		dprintk(dev, V4L2_DEBUG_QUEUE, "Window size (%dx%d) is out of "				"supported range\n", fh->width, fh->height);		dprintk(dev, V4L2_DEBUG_QUEUE, "Valid range is from (%dx%d) to "				"(%dx%d)\n", norm_minw(core), norm_minh(core),				norm_maxw(core),norm_maxh(core));		return -EINVAL;	}#endif	/* FIXME: It assumes depth=2 */	/* The only currently supported format is 16 bits/pixel */	buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)		return -EINVAL;	if (buf->fmt       != fh->fmt    ||	    buf->vb.width  != fh->width  ||	    buf->vb.height != fh->height ||	    buf->vb.field  != field) {		buf->fmt       = fh->fmt;		buf->vb.width  = fh->width;		buf->vb.height = fh->height;		buf->vb.field  = field;		buf->vb.state = VIDEOBUF_NEEDS_INIT;	}	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {		if (0 != (rc = videobuf_iolock(vq, &buf->vb, NULL)))			goto fail;		urb_init = 1;	}	if (!dev->isoc_ctl.num_bufs)		urb_init = 1;	if (urb_init) {		rc = tm6000_prepare_isoc(dev, buf->vb.size);		if (rc < 0)			goto fail;		rc = tm6000_start_thread(dev);		if (rc < 0)			goto fail;	}	buf->vb.state = VIDEOBUF_PREPARED;	return 0;fail:	free_buffer(vq, buf);	return rc;}static voidbuffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){	struct tm6000_buffer    *buf     = container_of(vb,struct tm6000_buffer,vb);	struct tm6000_fh        *fh      = vq->priv_data;	struct tm6000_core      *dev     = fh->dev;	struct tm6000_dmaqueue  *vidq    = &dev->vidq;	buf->vb.state = VIDEOBUF_QUEUED;	list_add_tail(&buf->vb.queue, &vidq->active);}static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb){	struct tm6000_buffer   *buf  = container_of(vb,struct tm6000_buffer,vb);	free_buffer(vq,buf);}static struct videobuf_queue_ops tm6000_video_qops = {	.buf_setup      = buffer_setup,	.buf_prepare    = buffer_prepare,	.buf_queue      = buffer_queue,	.buf_release    = buffer_release,};/* ------------------------------------------------------------------	IOCTL handling   ------------------------------------------------------------------*/static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh){	/* is it free? */	mutex_lock(&dev->lock);	if (dev->resources) {		/* no, someone else uses it */		mutex_unlock(&dev->lock);		return 0;	}	/* it's free, grab it */	dev->resources =1;	dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");	mutex_unlock(&dev->lock);	return 1;}static int res_locked(struct tm6000_core *dev){	return (dev->resources);}static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh){	mutex_lock(&dev->lock);	dev->resources = 0;	dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");	mutex_unlock(&dev->lock);}/* ------------------------------------------------------------------	IOCTL vidioc handling   ------------------------------------------------------------------*/static int vidioc_querycap (struct file *file, void  *priv,					struct v4l2_capability *cap){	//	struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;	strlcpy(cap->driver, "tm6000", sizeof(cap->driver));	strlcpy(cap->card,"Trident TVMaster TM5600/6000", sizeof(cap->card));	//	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));	cap->version = TM6000_VERSION;	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |				V4L2_CAP_STREAMING     |				V4L2_CAP_TUNER	       |				V4L2_CAP_READWRITE;	return 0;}static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,					struct v4l2_fmtdesc *f){	if (unlikely(f->index >= ARRAY_SIZE(format)))		return -EINVAL;	strlcpy(f->description,format[f->index].name,sizeof(f->description));	f->pixelformat = format[f->index].fourcc;	return 0;}static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,					struct v4l2_format *f){	struct tm6000_fh  *fh=priv;	f->fmt.pix.width        = fh->width;	f->fmt.pix.height       = fh->height;	f->fmt.pix.field        = fh->vb_vidq.field;	f->fmt.pix.pixelformat  = fh->fmt->fourcc;	f->fmt.pix.bytesperline =		(f->fmt.pix.width * fh->fmt->depth) >> 3;	f->fmt.pix.sizeimage =		f->fmt.pix.height * f->fmt.pix.bytesperline;	return (0);}static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc){	unsigned int i;	for (i = 0; i < ARRAY_SIZE(format); i++)		if (format[i].fourcc == fourcc)			return format+i;	return NULL;}static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,			struct v4l2_format *f){	struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;	struct tm6000_fmt *fmt;	enum v4l2_field field;	fmt = format_by_fourcc(f->fmt.pix.pixelformat);	if (NULL == fmt) {		dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"				" invalid.\n", f->fmt.pix.pixelformat);		return -EINVAL;	}	field = f->fmt.pix.field;	if (field == V4L2_FIELD_ANY) {//		field=V4L2_FIELD_INTERLACED;		field=V4L2_FIELD_SEQ_TB;	} else if (V4L2_FIELD_INTERLACED != field) {		dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");		return -EINVAL;	}#if 1	tm6000_get_std_res (dev);	f->fmt.pix.width  = dev->width;	f->fmt.pix.height = dev->height;#else	/* Scaling is not yet supported */	if (f->fmt.pix.width  < norm_minw(core))		f->fmt.pix.width = norm_minw(core);	if (f->fmt.pix.width  > norm_maxw(core))		f->fmt.pix.width = norm_maxw(core);	if (f->fmt.pix.height < norm_minh(core))		f->fmt.pix.height = norm_minh(core);	if (f->fmt.pix.height > norm_maxh(core))		f->fmt.pix.height = norm_maxh(core);#endif	f->fmt.pix.width &= ~0x01;	f->fmt.pix.field = field;	f->fmt.pix.bytesperline =		(f->fmt.pix.width * fmt->depth) >> 3;	f->fmt.pix.sizeimage =		f->fmt.pix.height * f->fmt.pix.bytesperline;	return 0;}/*FIXME: This seems to be generic enough to be at videodev2 */static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,					struct v4l2_format *f){	struct tm6000_fh  *fh=priv;	struct tm6000_core *dev = fh->dev;	int ret = vidioc_try_fmt_vid_cap(file,fh,f);	if (ret < 0)		return (ret);	fh->fmt           = format_by_fourcc(f->fmt.pix.pixelformat);	fh->width         = f->fmt.pix.width;	fh->height        = f->fmt.pix.height;	fh->vb_vidq.field = f->fmt.pix.field;	fh->type          = f->type;	dev->fourcc       = f->fmt.pix.pixelformat;	tm6000_set_fourcc_format(dev);	return (0);}static int vidioc_reqbufs (struct file *file, void *priv,			   struct v4l2_requestbuffers *p){	struct tm6000_fh  *fh=priv;	return (videobuf_reqbufs(&fh->vb_vidq, p));}static int vidioc_querybuf (struct file *file, void *priv,			    struct v4l2_buffer *p){	struct tm6000_fh  *fh=priv;	return (videobuf_querybuf(&fh->vb_vidq, p));}static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p){	struct tm6000_fh  *fh=priv;	return (videobuf_qbuf(&fh->vb_vidq, p));}static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p){	struct tm6000_fh  *fh=priv;	return (videobuf_dqbuf(&fh->vb_vidq, p,				file->f_flags & O_NONBLOCK));}#ifdef CONFIG_VIDEO_V4L1_COMPATstatic int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf){	struct tm6000_fh  *fh=priv;	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);}#endifstatic int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){	struct tm6000_fh  *fh=priv;	struct tm6000_core *dev    = fh->dev;	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (i != fh->type)		return -EINVAL;	if (!res_get(dev,fh))		return -EBUSY;	return (videobuf_streamon(&fh->vb_vidq));

⌨️ 快捷键说明

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