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

📄 gspca.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (gspca_dev->alt != 0) {		/* isoc */		/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));		npkt = ISO_MAX_SIZE / psize;		if (npkt > ISO_MAX_PKT)			npkt = ISO_MAX_PKT;		bsize = psize * npkt;		PDEBUG(D_STREAM,			"isoc %d pkts size %d = bsize:%d",			npkt, psize, bsize);		nurbs = DEF_NURBS;	} else {				/* bulk */		npkt = 0;		bsize = gspca_dev->cam.	bulk_size;		if (bsize == 0)			bsize = psize;		PDEBUG(D_STREAM, "bulk bsize:%d", bsize);		nurbs = 1;	}	gspca_dev->nurbs = nurbs;	for (n = 0; n < nurbs; n++) {		urb = usb_alloc_urb(npkt, GFP_KERNEL);		if (!urb) {			err("usb_alloc_urb failed");			destroy_urbs(gspca_dev);			return -ENOMEM;		}		urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,						bsize,						GFP_KERNEL,						&urb->transfer_dma);		if (urb->transfer_buffer == NULL) {			usb_free_urb(urb);			err("usb_buffer_urb failed");			destroy_urbs(gspca_dev);			return -ENOMEM;		}		gspca_dev->urb[n] = urb;		urb->dev = gspca_dev->dev;		urb->context = gspca_dev;		urb->transfer_buffer_length = bsize;		if (npkt != 0) {		/* ISOC */			urb->pipe = usb_rcvisocpipe(gspca_dev->dev,						    ep->desc.bEndpointAddress);			urb->transfer_flags = URB_ISO_ASAP					| URB_NO_TRANSFER_DMA_MAP;			urb->interval = ep->desc.bInterval;			urb->complete = isoc_irq;			urb->number_of_packets = npkt;			for (i = 0; i < npkt; i++) {				urb->iso_frame_desc[i].length = psize;				urb->iso_frame_desc[i].offset = psize * i;			}		} else {		/* bulk */			urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,						ep->desc.bEndpointAddress),			urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;			urb->complete = bulk_irq;		}	}	return 0;}/* * start the USB transfer */static int gspca_init_transfer(struct gspca_dev *gspca_dev){	struct usb_host_endpoint *ep;	int n, ret;	if (mutex_lock_interruptible(&gspca_dev->usb_lock))		return -ERESTARTSYS;	/* set the higher alternate setting and	 * loop until urb submit succeeds */	gspca_dev->alt = gspca_dev->nbalt;	for (;;) {		PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);		ep = get_ep(gspca_dev);		if (ep == NULL) {			ret = -EIO;			goto out;		}		ret = create_urbs(gspca_dev, ep);		if (ret < 0)			goto out;		/* start the cam */		ret = gspca_dev->sd_desc->start(gspca_dev);		if (ret < 0) {			destroy_urbs(gspca_dev);			goto out;		}		gspca_dev->streaming = 1;		atomic_set(&gspca_dev->nevent, 0);		/* bulk transfers are started by the subdriver */		if (gspca_dev->alt == 0)			break;		/* submit the URBs */		for (n = 0; n < gspca_dev->nurbs; n++) {			ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);			if (ret < 0) {				PDEBUG(D_ERR|D_STREAM,					"usb_submit_urb [%d] err %d", n, ret);				gspca_dev->streaming = 0;				destroy_urbs(gspca_dev);				if (ret == -ENOSPC)					break;	/* try the previous alt */				goto out;			}		}		if (ret >= 0)			break;	}out:	mutex_unlock(&gspca_dev->usb_lock);	return ret;}static int gspca_set_alt0(struct gspca_dev *gspca_dev){	int ret;	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);	if (ret < 0)		PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);	return ret;}/* Note: both the queue and the usb locks should be held when calling this */static void gspca_stream_off(struct gspca_dev *gspca_dev){	gspca_dev->streaming = 0;	atomic_set(&gspca_dev->nevent, 0);	if (gspca_dev->present) {		if (gspca_dev->sd_desc->stopN)			gspca_dev->sd_desc->stopN(gspca_dev);		destroy_urbs(gspca_dev);		gspca_set_alt0(gspca_dev);		if (gspca_dev->sd_desc->stop0)			gspca_dev->sd_desc->stop0(gspca_dev);		PDEBUG(D_STREAM, "stream off OK");	}}static void gspca_set_default_mode(struct gspca_dev *gspca_dev){	int i;	i = gspca_dev->cam.nmodes - 1;	/* take the highest mode */	gspca_dev->curr_mode = i;	gspca_dev->width = gspca_dev->cam.cam_mode[i].width;	gspca_dev->height = gspca_dev->cam.cam_mode[i].height;	gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;}static int wxh_to_mode(struct gspca_dev *gspca_dev,			int width, int height){	int i;	for (i = gspca_dev->cam.nmodes; --i > 0; ) {		if (width >= gspca_dev->cam.cam_mode[i].width		    && height >= gspca_dev->cam.cam_mode[i].height)			break;	}	return i;}/* * search a mode with the right pixel format */static int gspca_get_mode(struct gspca_dev *gspca_dev,			int mode,			int pixfmt){	int modeU, modeD;	modeU = modeD = mode;	while ((modeU < gspca_dev->cam.nmodes) || modeD >= 0) {		if (--modeD >= 0) {			if (gspca_dev->cam.cam_mode[modeD].pixelformat								== pixfmt)				return modeD;		}		if (++modeU < gspca_dev->cam.nmodes) {			if (gspca_dev->cam.cam_mode[modeU].pixelformat								== pixfmt)				return modeU;		}	}	return -EINVAL;}static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,				struct v4l2_fmtdesc *fmtdesc){	struct gspca_dev *gspca_dev = priv;	int i, j, index;	__u32 fmt_tb[8];	/* give an index to each format */	index = 0;	j = 0;	for (i = gspca_dev->cam.nmodes; --i >= 0; ) {		fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat;		j = 0;		for (;;) {			if (fmt_tb[j] == fmt_tb[index])				break;			j++;		}		if (j == index) {			if (fmtdesc->index == index)				break;		/* new format */			index++;			if (index >= sizeof fmt_tb / sizeof fmt_tb[0])				return -EINVAL;		}	}	if (i < 0)		return -EINVAL;		/* no more format */	fmtdesc->pixelformat = fmt_tb[index];	if (gspca_is_compressed(fmt_tb[index]))		fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;	fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;	fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;	fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;	fmtdesc->description[3] = fmtdesc->pixelformat >> 24;	fmtdesc->description[4] = '\0';	return 0;}static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,			    struct v4l2_format *fmt){	struct gspca_dev *gspca_dev = priv;	int mode;	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	mode = gspca_dev->curr_mode;	memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],		sizeof fmt->fmt.pix);	return 0;}static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,			struct v4l2_format *fmt){	int w, h, mode, mode2;	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	w = fmt->fmt.pix.width;	h = fmt->fmt.pix.height;#ifdef GSPCA_DEBUG	if (gspca_debug & D_CONF)		PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);#endif	/* search the closest mode for width and height */	mode = wxh_to_mode(gspca_dev, w, h);	/* OK if right palette */	if (gspca_dev->cam.cam_mode[mode].pixelformat						!= fmt->fmt.pix.pixelformat) {		/* else, search the closest mode with the same pixel format */		mode2 = gspca_get_mode(gspca_dev, mode,					fmt->fmt.pix.pixelformat);		if (mode2 >= 0)			mode = mode2;/*		else			;		 * no chance, return this mode */	}	memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],		sizeof fmt->fmt.pix);	return mode;			/* used when s_fmt */}static int vidioc_try_fmt_vid_cap(struct file *file,			      void *priv,			      struct v4l2_format *fmt){	struct gspca_dev *gspca_dev = priv;	int ret;	ret = try_fmt_vid_cap(gspca_dev, fmt);	if (ret < 0)		return ret;	return 0;}static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,			    struct v4l2_format *fmt){	struct gspca_dev *gspca_dev = priv;	int ret;	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	ret = try_fmt_vid_cap(gspca_dev, fmt);	if (ret < 0)		goto out;	if (gspca_dev->nframes != 0	    && fmt->fmt.pix.sizeimage > gspca_dev->frsz) {		ret = -EINVAL;		goto out;	}	if (ret == gspca_dev->curr_mode) {		ret = 0;		goto out;			/* same mode */	}	if (gspca_dev->streaming) {		ret = -EBUSY;		goto out;	}	gspca_dev->width = fmt->fmt.pix.width;	gspca_dev->height = fmt->fmt.pix.height;	gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;	gspca_dev->curr_mode = ret;	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	return ret;}static void gspca_delete(struct kref *kref){	struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref);	PDEBUG(D_STREAM, "device deleted");	kfree(gspca_dev->usb_buf);	kfree(gspca_dev);}static int dev_open(struct inode *inode, struct file *file){	struct gspca_dev *gspca_dev;	int ret;	PDEBUG(D_STREAM, "%s open", current->comm);	gspca_dev = (struct gspca_dev *) video_devdata(file);	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	if (!gspca_dev->present) {		ret = -ENODEV;		goto out;	}	if (gspca_dev->users > 4) {	/* (arbitrary value) */		ret = -EBUSY;		goto out;	}	gspca_dev->users++;	/* one more user */	kref_get(&gspca_dev->kref);	file->private_data = gspca_dev;#ifdef GSPCA_DEBUG	/* activate the v4l2 debug */	if (gspca_debug & D_V4L2)		gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL					| V4L2_DEBUG_IOCTL_ARG;	else		gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL					| V4L2_DEBUG_IOCTL_ARG);#endif	ret = 0;out:	mutex_unlock(&gspca_dev->queue_lock);	if (ret != 0)		PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);	else		PDEBUG(D_STREAM, "open done");	return ret;}static int dev_close(struct inode *inode, struct file *file){	struct gspca_dev *gspca_dev = file->private_data;	PDEBUG(D_STREAM, "%s close", current->comm);	if (mutex_lock_interruptible(&gspca_dev->queue_lock))		return -ERESTARTSYS;	gspca_dev->users--;	/* if the file did the capture, free the streaming resources */	if (gspca_dev->capt_file == file) {		if (gspca_dev->streaming) {			mutex_lock(&gspca_dev->usb_lock);			gspca_stream_off(gspca_dev);			mutex_unlock(&gspca_dev->usb_lock);		}		frame_free(gspca_dev);		gspca_dev->capt_file = NULL;		gspca_dev->memory = GSPCA_MEMORY_NO;	}	file->private_data = NULL;	mutex_unlock(&gspca_dev->queue_lock);	PDEBUG(D_STREAM, "close done");	kref_put(&gspca_dev->kref, gspca_delete);	return 0;}static int vidioc_querycap(struct file *file, void  *priv,			   struct v4l2_capability *cap){	struct gspca_dev *gspca_dev = priv;	memset(cap, 0, sizeof *cap);	strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);	if (gspca_dev->dev->product != NULL) {		strncpy(cap->card, gspca_dev->dev->product,			sizeof cap->card);	} else {		snprintf(cap->card, sizeof cap->card,			"USB Camera (%04x:%04x)",			le16_to_cpu(gspca_dev->dev->descriptor.idVendor),			le16_to_cpu(gspca_dev->dev->descriptor.idProduct));	}	strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name,		sizeof cap->bus_info);	cap->version = DRIVER_VERSION_NUMBER;	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE			  | V4L2_CAP_STREAMING			  | V4L2_CAP_READWRITE;	return 0;}static int vidioc_queryctrl(struct file *file, void *priv,			   struct v4l2_queryctrl *q_ctrl){	struct gspca_dev *gspca_dev = priv;	int i, ix;	u32 id;	ix = -1;	id = q_ctrl->id;	if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {		id &= V4L2_CTRL_ID_MASK;		id++;		for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {			if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)				continue;			if (ix < 0) {				ix = i;				continue;			}			if (gspca_dev->sd_desc->ctrls[i].qctrl.id				    > gspca_dev->sd_desc->ctrls[ix].qctrl.id)				continue;			ix = i;		}	}	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {		if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {			ix = i;			break;		}	}	if (ix < 0)		return -EINVAL;	memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,		sizeof *q_ctrl);	if (gspca_dev->ctrl_dis & (1 << ix))		q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;	return 0;}static int vidioc_s_ctrl(struct file *file, void *priv,			 struct v4l2_control *ctrl){	struct gspca_dev *gspca_dev = priv;	const struct ctrl *ctrls;	int i, ret;	for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;	     i < gspca_dev->sd_desc->nctrls;	     i++, ctrls++) {		if (ctrl->id != ctrls->qctrl.id)			continue;		if (gspca_dev->ctrl_dis & (1 << i))			return -EINVAL;		if (ctrl->value < ctrls->qctrl.minimum		    || ctrl->value > ctrls->qctrl.maximum)			return -ERANGE;		PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);		if (mutex_lock_interruptible(&gspca_dev->usb_lock))			return -ERESTARTSYS;		ret = ctrls->set(gspca_dev, ctrl->value);		mutex_unlock(&gspca_dev->usb_lock);		return ret;	}	return -EINVAL;}static int vidioc_g_ctrl(struct file *file, void *priv,			 struct v4l2_control *ctrl)

⌨️ 快捷键说明

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