📄 pwc-if.c
字号:
/* 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) { 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) { 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){ struct pwc_device *pdev = video_get_drvdata(vdev); int rc; rc = device_create_file(&vdev->dev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0;err_button: device_remove_file(&vdev->dev, &dev_attr_button);err: PWC_ERROR("Could not create sysfs files.\n"); return rc;}static void pwc_remove_sysfs_files(struct video_device *vdev){ struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) device_remove_file(&vdev->dev, &dev_attr_pan_tilt); device_remove_file(&vdev->dev, &dev_attr_button);}#ifdef CONFIG_USB_PWC_DEBUGstatic const char *pwc_sensor_type_to_string(unsigned int sensor_type){ switch(sensor_type) { case 0x00: return "Hyundai CMOS sensor"; case 0x20: return "Sony CCD sensor + TDA8787"; case 0x2E: return "Sony CCD sensor + Exas 98L59"; case 0x2F: return "Sony CCD sensor + ADI 9804"; case 0x30: return "Sharp CCD sensor + TDA8787"; case 0x3E: return "Sharp CCD sensor + Exas 98L59"; case 0x3F: return "Sharp CCD sensor + ADI 9804"; case 0x40: return "UPA 1021 sensor"; case 0x100: return "VGA sensor"; case 0x101: return "PAL MR sensor"; default: return "unknown type of sensor"; }}#endif/***************************************************************************//* Video4Linux functions */static int pwc_video_open(struct inode *inode, struct file *file){ int i, ret; struct video_device *vdev = video_devdata(file); struct pwc_device *pdev; PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); pdev = video_get_drvdata(vdev); BUG_ON(!pdev); if (pdev->vopen) { PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); return -EBUSY; } mutex_lock(&pdev->modlock); if (!pdev->usb_init) { PWC_DEBUG_OPEN("Doing first time initialization.\n"); pdev->usb_init = 1; /* Query sensor type */ ret = pwc_get_cmos_sensor(pdev, &i); if (ret >= 0) { PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, pwc_sensor_type_to_string(i), i); } } /* Turn on camera */ if (power_save) { i = pwc_camera_power(pdev, 1); if (i < 0) PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i); } /* Set LED on/off time */ if (pwc_set_leds(pdev, led_on, led_off) < 0) PWC_DEBUG_OPEN("Failed to set LED on/off time.\n"); pwc_construct(pdev); /* set min/max sizes correct */ /* So far, so good. Allocate memory. */ i = pwc_allocate_buffers(pdev); if (i < 0) { PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); pwc_free_buffers(pdev); mutex_unlock(&pdev->modlock); return i; } /* Reset buffers & parameters */ pwc_reset_buffers(pdev); for (i = 0; i < pwc_mbufs; i++) pdev->image_used[i] = 0; pdev->vframe_count = 0; pdev->vframes_dumped = 0; pdev->vframes_error = 0; pdev->visoc_errors = 0; pdev->error_status = 0; pwc_construct(pdev); /* set min/max sizes correct */ /* Set some defaults */ pdev->vsnapshot = 0; /* Start iso pipe for video; first try the last used video size (or the default one); if that fails try QCIF/10 or QSIF/10; it that fails too, give up. */ i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); if (i) { unsigned int default_resolution; PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n"); if (pdev->type>= 730) default_resolution = PSZ_QSIF; else default_resolution = PSZ_QCIF; i = pwc_set_video_mode(pdev, pwc_image_sizes[default_resolution].x, pwc_image_sizes[default_resolution].y, 10, pdev->vcompression, 0); } if (i) { PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); pwc_free_buffers(pdev); mutex_unlock(&pdev->modlock); return i; } i = pwc_isoc_init(pdev); if (i) { PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i); pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); mutex_unlock(&pdev->modlock); return i; } /* Initialize the webcam to sane value */ pwc_set_brightness(pdev, 0x7fff); pwc_set_agc(pdev, 1, 0); pdev->vopen++; file->private_data = vdev; mutex_unlock(&pdev->modlock); PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); return 0;}static void pwc_cleanup(struct pwc_device *pdev){ pwc_remove_sysfs_files(pdev->vdev); video_unregister_device(pdev->vdev);}/* Note that all cleanup is done in the reverse order as in _open */static int pwc_video_close(struct inode *inode, struct file *file){ struct video_device *vdev = file->private_data; struct pwc_device *pdev; int i, hint; PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); lock_kernel(); pdev = video_get_drvdata(vdev); if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot programs) */ if (pdev->vframe_count > 20) PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); if (DEVICE_USE_CODEC1(pdev->type)) pwc_dec1_exit(); else pwc_dec23_exit();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -