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

📄 pwc-if.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	spin_lock_irqsave(&pdev->ptrlock, flags);	/* First grab our read_frame; this is removed from all lists, so	   we can release the lock after this without problems */	if (pdev->read_frame != NULL) {		/* This can't theoretically happen */		PWC_ERROR("Huh? Read frame still in use?\n");		spin_unlock_irqrestore(&pdev->ptrlock, flags);		return ret;	}	if (pdev->full_frames == NULL) {		PWC_ERROR("Woops. No frames ready.\n");	}	else {		pdev->read_frame = pdev->full_frames;		pdev->full_frames = pdev->full_frames->next;		pdev->read_frame->next = NULL;	}	if (pdev->read_frame != NULL) {		/* Decompression is a lenghty process, so it's outside of the lock.		   This gives the isoc_handler the opportunity to fill more frames		   in the mean time.		*/		spin_unlock_irqrestore(&pdev->ptrlock, flags);		ret = pwc_decompress(pdev);		spin_lock_irqsave(&pdev->ptrlock, flags);		/* We're done with read_buffer, tack it to the end of the empty buffer list */		if (pdev->empty_frames == NULL) {			pdev->empty_frames = pdev->read_frame;			pdev->empty_frames_tail = pdev->empty_frames;		}		else {			pdev->empty_frames_tail->next = pdev->read_frame;			pdev->empty_frames_tail = pdev->read_frame;		}		pdev->read_frame = NULL;	}	spin_unlock_irqrestore(&pdev->ptrlock, flags);	return ret;}/**  \brief Advance pointers of image buffer (after each user request)*/void pwc_next_image(struct pwc_device *pdev){	pdev->image_used[pdev->fill_image] = 0;	pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;}/** * Print debug information when a frame is discarded because all of our buffer * is full */static void pwc_frame_dumped(struct pwc_device *pdev){	pdev->vframes_dumped++;	if (pdev->vframe_count < FRAME_LOWMARK)		return;	if (pdev->vframes_dumped < 20)		PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);	else if (pdev->vframes_dumped == 20)		PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",				pdev->vframe_count);}static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf){	int awake = 0;	/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus	   frames on the USB wire after an exposure change. This conditition is	   however detected  in the cam and a bit is set in the header.	   */	if (pdev->type == 730) {		unsigned char *ptr = (unsigned char *)fbuf->data;		if (ptr[1] == 1 && ptr[0] & 0x10) {			PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");			pdev->drop_frames += 2;			pdev->vframes_error++;		}		if ((ptr[0] ^ pdev->vmirror) & 0x01) {			if (ptr[0] & 0x01) {				pdev->snapshot_button_status = 1;				PWC_TRACE("Snapshot button pressed.\n");			}			else {				PWC_TRACE("Snapshot button released.\n");			}		}		if ((ptr[0] ^ pdev->vmirror) & 0x02) {			if (ptr[0] & 0x02)				PWC_TRACE("Image is mirrored.\n");			else				PWC_TRACE("Image is normal.\n");		}		pdev->vmirror = ptr[0] & 0x03;		/* Sometimes the trailer of the 730 is still sent as a 4 byte packet		   after a short frame; this condition is filtered out specifically. A 4 byte		   frame doesn't make sense anyway.		   So we get either this sequence:		   drop_bit set -> 4 byte frame -> short frame -> good frame		   Or this one:		   drop_bit set -> short frame -> good frame		   So we drop either 3 or 2 frames in all!		   */		if (fbuf->filled == 4)			pdev->drop_frames++;	}	else if (pdev->type == 740 || pdev->type == 720) {		unsigned char *ptr = (unsigned char *)fbuf->data;		if ((ptr[0] ^ pdev->vmirror) & 0x01) {			if (ptr[0] & 0x01) {				pdev->snapshot_button_status = 1;				PWC_TRACE("Snapshot button pressed.\n");			}			else				PWC_TRACE("Snapshot button released.\n");		}		pdev->vmirror = ptr[0] & 0x03;	}	/* In case we were instructed to drop the frame, do so silently.	   The buffer pointers are not updated either (but the counters are reset below).	   */	if (pdev->drop_frames > 0)		pdev->drop_frames--;	else {		/* Check for underflow first */		if (fbuf->filled < pdev->frame_total_size) {			PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"				       " discarded.\n", fbuf->filled);			pdev->vframes_error++;		}		else {			/* Send only once per EOF */			awake = 1; /* delay wake_ups */			/* Find our next frame to fill. This will always succeed, since we			 * nick a frame from either empty or full list, but if we had to			 * take it from the full list, it means a frame got dropped.			 */			if (pwc_next_fill_frame(pdev))				pwc_frame_dumped(pdev);		}	} /* !drop_frames */	pdev->vframe_count++;	return awake;}/* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */static void pwc_isoc_handler(struct urb *urb){	struct pwc_device *pdev;	int i, fst, flen;	int awake;	struct pwc_frame_buf *fbuf;	unsigned char *fillptr = NULL, *iso_buf = NULL;	awake = 0;	pdev = (struct pwc_device *)urb->context;	if (pdev == NULL) {		PWC_ERROR("isoc_handler() called with NULL device?!\n");		return;	}	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {		PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");		return;	}	if (urb->status != -EINPROGRESS && urb->status != 0) {		const char *errmsg;		errmsg = "Unknown";		switch(urb->status) {			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;			case -ETIME:		errmsg = "Device does not respond"; break;		}		PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);		/* Give up after a number of contiguous errors on the USB bus.		   Appearantly something is wrong so we simulate an unplug event.		 */		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)		{			PWC_INFO("Too many ISOC errors, bailing out.\n");			pdev->error_status = EIO;			awake = 1;			wake_up_interruptible(&pdev->frameq);		}		goto handler_end; // ugly, but practical	}	fbuf = pdev->fill_frame;	if (fbuf == NULL) {		PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");		awake = 1;		goto handler_end;	}	else {		fillptr = fbuf->data + fbuf->filled;	}	/* Reset ISOC error counter. We did get here, after all. */	pdev->visoc_errors = 0;	/* vsync: 0 = don't copy data		  1 = sync-hunt		  2 = synched	 */	/* Compact data */	for (i = 0; i < urb->number_of_packets; i++) {		fst  = urb->iso_frame_desc[i].status;		flen = urb->iso_frame_desc[i].actual_length;		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;		if (fst == 0) {			if (flen > 0) { /* if valid data... */				if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */					pdev->vsync = 2;					/* ...copy data to frame buffer, if possible */					if (flen + fbuf->filled > pdev->frame_total_size) {						PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);						pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */						pdev->vframes_error++;					}					else {						memmove(fillptr, iso_buf, flen);						fillptr += flen;					}				}				fbuf->filled += flen;			} /* ..flen > 0 */			if (flen < pdev->vlast_packet_size) {				/* Shorter packet... We probably have the end of an image-frame;				   wake up read() process and let select()/poll() do something.				   Decompression is done in user time over there.				   */				if (pdev->vsync == 2) {					if (pwc_rcv_short_packet(pdev, fbuf)) {						awake = 1;						fbuf = pdev->fill_frame;					}				}				fbuf->filled = 0;				fillptr = fbuf->data;				pdev->vsync = 1;			}			pdev->vlast_packet_size = flen;		} /* ..status == 0 */		else {			/* This is normally not interesting to the user, unless			 * you are really debugging something */			static int iso_error = 0;			iso_error++;			if (iso_error < 20)				PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);		}	}handler_end:	if (awake)		wake_up_interruptible(&pdev->frameq);	urb->dev = pdev->udev;	i = usb_submit_urb(urb, GFP_ATOMIC);	if (i != 0)		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);}int pwc_isoc_init(struct pwc_device *pdev){	struct usb_device *udev;	struct urb *urb;	int i, j, ret;	struct usb_interface *intf;	struct usb_host_interface *idesc = NULL;	if (pdev == NULL)		return -EFAULT;	if (pdev->iso_init)		return 0;	pdev->vsync = 0;	udev = pdev->udev;	/* Get the current alternate interface, adjust packet size */	if (!udev->actconfig)		return -EFAULT;	intf = usb_ifnum_to_if(udev, 0);	if (intf)		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);	if (!idesc)		return -EFAULT;	/* Search video endpoint */	pdev->vmax_packet_size = -1;	for (i = 0; i < idesc->desc.bNumEndpoints; i++) {		if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {			pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);			break;		}	}	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {		PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");		return -ENFILE; /* Odd error, that should be noticeable */	}	/* Set alternate interface */	ret = 0;	PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);	if (ret < 0)		return ret;	for (i = 0; i < MAX_ISO_BUFS; i++) {		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);		if (urb == NULL) {			PWC_ERROR("Failed to allocate urb %d\n", i);			ret = -ENOMEM;			break;		}		pdev->sbuf[i].urb = urb;		PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);	}	if (ret) {		/* De-allocate in reverse order */		while (i--) {			usb_free_urb(pdev->sbuf[i].urb);			pdev->sbuf[i].urb = NULL;		}		return ret;	}	/* init URB structure */	for (i = 0; i < MAX_ISO_BUFS; i++) {		urb = pdev->sbuf[i].urb;		urb->interval = 1; // devik		urb->dev = udev;		urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);		urb->transfer_flags = URB_ISO_ASAP;		urb->transfer_buffer = pdev->sbuf[i].data;		urb->transfer_buffer_length = ISO_BUFFER_SIZE;		urb->complete = pwc_isoc_handler;		urb->context = pdev;		urb->start_frame = 0;		urb->number_of_packets = ISO_FRAMES_PER_DESC;		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;		}	}	/* link */	for (i = 0; i < MAX_ISO_BUFS; i++) {		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);		if (ret)			PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);		else			PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);	}	/* All is done... */	pdev->iso_init = 1;	PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");	return 0;}static void pwc_iso_stop(struct pwc_device *pdev){	int i;	/* Unlinking ISOC buffers one by one */	for (i = 0; i < MAX_ISO_BUFS; i++) {		struct urb *urb;		urb = pdev->sbuf[i].urb;		if (urb != 0) {			PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);			usb_kill_urb(urb);		}	}}static void pwc_iso_free(struct pwc_device *pdev){	int i;	/* Freeing ISOC buffers one by one */	for (i = 0; i < MAX_ISO_BUFS; i++) {		struct urb *urb;		urb = pdev->sbuf[i].urb;		if (urb != 0) {			PWC_DEBUG_MEMORY("Freeing URB\n");			usb_free_urb(urb);			pdev->sbuf[i].urb = NULL;		}	}}void pwc_isoc_cleanup(struct pwc_device *pdev){	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");	if (pdev == NULL)		return;	if (pdev->iso_init == 0)		return;	pwc_iso_stop(pdev);	pwc_iso_free(pdev);	/* Stop camera, but only if we are sure the camera is still there (unplug	   is signalled by EPIPE)	 */	if (pdev->error_status && pdev->error_status != EPIPE) {		PWC_DEBUG_OPEN("Setting alternate interface 0.\n");		usb_set_interface(pdev->udev, 0, 0);	}	pdev->iso_init = 0;	PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");}int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot){	int ret, start;	/* Stop isoc stuff */	pwc_isoc_cleanup(pdev);	/* Reset parameters */	pwc_reset_buffers(pdev);	/* Try to set video mode... */	start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);	if (ret) {		PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");		/* That failed... restore old mode (we know that worked) */		start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);		if (start) {			PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");		}	}	if (start == 0)	{		if (pwc_isoc_init(pdev) < 0)		{			PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");			ret = -EAGAIN; /* let's try again, who knows if it works a second time */		}	}	pdev->drop_frames++; /* try to avoid garbage during switch */	return ret; /* Return original error code */}/********* * sysfs *********/static struct pwc_device *cd_to_pwc(struct device *cd){	struct video_device *vdev = to_video_device(cd);	return video_get_drvdata(vdev);}static ssize_t show_pan_tilt(struct device *class_dev,			     struct device_attribute *attr, char *buf){	struct pwc_device *pdev = cd_to_pwc(class_dev);	return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);}static ssize_t store_pan_tilt(struct device *class_dev,			      struct device_attribute *attr,			      const char *buf, size_t count){	struct pwc_device *pdev = cd_to_pwc(class_dev);	int pan, tilt;	int ret = -EINVAL;	if (strncmp(buf, "reset", 5) == 0)		ret = pwc_mpt_reset(pdev, 0x3);	else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)		ret = pwc_mpt_set_angle(pdev, pan, tilt);	if (ret < 0)		return ret;	return strlen(buf);}static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,		   store_pan_tilt);static ssize_t show_snapshot_button_status(struct device *class_dev,					   struct device_attribute *attr, char *buf){	struct pwc_device *pdev = cd_to_pwc(class_dev);	int status = pdev->snapshot_button_status;	pdev->snapshot_button_status = 0;	return sprintf(buf, "%d\n", status);}static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,		   NULL);static int pwc_create_sysfs_files(struct video_device *vdev)

⌨️ 快捷键说明

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