📄 sn9c102_core.c
字号:
void *pos, *sof, *eof; len = urb->iso_frame_desc[i].actual_length; status = urb->iso_frame_desc[i].status; pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; if (status) { DBG(3, "Error in isochronous frame") (*f)->state = F_ERROR; continue; } PDBGG("Isochrnous frame: length %u, #%u i", len, i) /* NOTE: It is probably correct to assume that SOF and EOF headers do not occur between two consecutive packets, but who knows..Whatever is the truth, this assumption doesn't introduce bugs. */redo: sof = sn9c102_find_sof_header(cam, pos, len); if (!sof) { eof = sn9c102_find_eof_header(cam, pos, len); if ((*f)->state == F_GRABBING) {end_of_frame: img = len; if (eof) img = (eof > pos) ? eof - pos - 1 : 0; if ((*f)->buf.bytesused+img > imagesize) { u32 b = (*f)->buf.bytesused + img - imagesize; img = imagesize - (*f)->buf.bytesused; DBG(3, "Expected EOF not found: " "video frame cut") if (eof) DBG(3, "Exceeded limit: +%u " "bytes", (unsigned)(b)) } memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, img); if ((*f)->buf.bytesused == 0) do_gettimeofday(&(*f)->buf.timestamp); (*f)->buf.bytesused += img; if ((*f)->buf.bytesused == imagesize || (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X && eof)) { u32 b = (*f)->buf.bytesused; (*f)->state = F_DONE; (*f)->buf.sequence= ++cam->frame_count; spin_lock_irqsave(&cam->queue_lock, lock_flags); list_move_tail(&(*f)->frame, &cam->outqueue); if (!list_empty(&cam->inqueue)) (*f) = list_entry( cam->inqueue.next, struct sn9c102_frame_t, frame ); else (*f) = NULL; spin_unlock_irqrestore(&cam->queue_lock , lock_flags); memcpy(cam->sysfs.frame_header, cam->sof_header, sizeof(sn9c102_sof_header_t)); DBG(3, "Video frame captured: " "%lu bytes", (unsigned long)(b)) if (!(*f)) goto resubmit_urb; } else if (eof) { (*f)->state = F_ERROR; DBG(3, "Not expected EOF after %lu " "bytes of image data", (unsigned long)((*f)->buf.bytesused)) } if (sof) /* (1) */ goto start_of_frame; } else if (eof) { DBG(3, "EOF without SOF") continue; } else { PDBGG("Ignoring pointless isochronous frame") continue; } } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {start_of_frame: (*f)->state = F_GRABBING; (*f)->buf.bytesused = 0; len -= (sof - pos); pos = sof; DBG(3, "SOF detected: new video frame") if (len) goto redo; } else if ((*f)->state == F_GRABBING) { eof = sn9c102_find_eof_header(cam, pos, len); if (eof && eof < sof) goto end_of_frame; /* (1) */ else { if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) { eof = sof-sizeof(sn9c102_sof_header_t); goto end_of_frame; } else { DBG(3, "SOF before expected EOF after " "%lu bytes of image data", (unsigned long)((*f)->buf.bytesused)) goto start_of_frame; } } } }resubmit_urb: urb->dev = cam->usbdev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0 && err != -EPERM) { cam->state |= DEV_MISCONFIGURED; DBG(1, "usb_submit_urb() failed") } wake_up_interruptible(&cam->wait_frame);}static int sn9c102_start_transfer(struct sn9c102_device* cam){ struct usb_device *udev = cam->usbdev; struct urb* urb; const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512, 680, 800, 900, 1023}; const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; s8 i, j; int err = 0; for (i = 0; i < SN9C102_URBS; i++) { cam->transfer_buffer[i] = kmalloc(SN9C102_ISO_PACKETS * psz, GFP_KERNEL); if (!cam->transfer_buffer[i]) { err = -ENOMEM; DBG(1, "Not enough memory") goto free_buffers; } } for (i = 0; i < SN9C102_URBS; i++) { urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); cam->urb[i] = urb; if (!urb) { err = -ENOMEM; DBG(1, "usb_alloc_urb() failed") goto free_urbs; } urb->dev = udev; urb->context = cam; urb->pipe = usb_rcvisocpipe(udev, 1); urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = SN9C102_ISO_PACKETS; urb->complete = sn9c102_urb_complete; urb->transfer_buffer = cam->transfer_buffer[i]; urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; urb->interval = 1; for (j = 0; j < SN9C102_ISO_PACKETS; j++) { urb->iso_frame_desc[j].offset = psz * j; urb->iso_frame_desc[j].length = psz; } } /* Enable video */ if (!(cam->reg[0x01] & 0x04)) { err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); if (err) { err = -EIO; DBG(1, "I/O hardware error") goto free_urbs; } } err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); if (err) { DBG(1, "usb_set_interface() failed") goto free_urbs; } cam->frame_current = NULL; for (i = 0; i < SN9C102_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); if (err) { for (j = i-1; j >= 0; j--) usb_kill_urb(cam->urb[j]); DBG(1, "usb_submit_urb() failed, error %d", err) goto free_urbs; } } return 0;free_urbs: for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) usb_free_urb(cam->urb[i]);free_buffers: for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) kfree(cam->transfer_buffer[i]); return err;}static int sn9c102_stop_transfer(struct sn9c102_device* cam){ struct usb_device *udev = cam->usbdev; s8 i; int err = 0; if (cam->state & DEV_DISCONNECTED) return 0; for (i = SN9C102_URBS-1; i >= 0; i--) { usb_kill_urb(cam->urb[i]); usb_free_urb(cam->urb[i]); kfree(cam->transfer_buffer[i]); } err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ if (err) DBG(3, "usb_set_interface() failed") return err;}int sn9c102_stream_interrupt(struct sn9c102_device* cam){ int err = 0; cam->stream = STREAM_INTERRUPT; err = wait_event_timeout(cam->wait_stream, (cam->stream == STREAM_OFF) || (cam->state & DEV_DISCONNECTED), SN9C102_URB_TIMEOUT); if (cam->state & DEV_DISCONNECTED) return -ENODEV; else if (err) { cam->state |= DEV_MISCONFIGURED; DBG(1, "The camera is misconfigured. To use it, close and " "open /dev/video%d again.", cam->v4ldev->minor) return err; } return 0;}/*****************************************************************************/static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count){ char str[5]; char* endp; unsigned long val; if (len < 4) { strncpy(str, buff, len); str[len+1] = '\0'; } else { strncpy(str, buff, 4); str[4] = '\0'; } val = simple_strtoul(str, &endp, 0); *count = 0; if (val <= 0xff) *count = (ssize_t)(endp - str); if ((*count) && (len == *count+1) && (buff[*count] == '\n')) *count += 1; return (u8)val;}/* NOTE 1: being inside one of the following methods implies that the v4l device exists for sure (see kobjects and reference counters) NOTE 2: buffers are PAGE_SIZE long*/static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf){ struct sn9c102_device* cam; ssize_t count; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } count = sprintf(buf, "%u\n", cam->sysfs.reg); up(&sn9c102_sysfs_lock); return count;} static ssize_t sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len){ struct sn9c102_device* cam; u8 index; ssize_t count; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } index = sn9c102_strtou8(buf, len, &count); if (index > 0x1f || !count) { up(&sn9c102_sysfs_lock); return -EINVAL; } cam->sysfs.reg = index; DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg) DBG(3, "Written bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_t sn9c102_show_val(struct class_device* cd, char* buf){ struct sn9c102_device* cam; ssize_t count; int val; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { up(&sn9c102_sysfs_lock); return -EIO; } count = sprintf(buf, "%d\n", val); DBG(3, "Read bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;} static ssize_tsn9c102_store_val(struct class_device* cd, const char* buf, size_t len){ struct sn9c102_device* cam; u8 value; ssize_t count; int err; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } value = sn9c102_strtou8(buf, len, &count); if (!count) { up(&sn9c102_sysfs_lock); return -EINVAL; } err = sn9c102_write_reg(cam, value, cam->sysfs.reg); if (err) { up(&sn9c102_sysfs_lock); return -EIO; } DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", cam->sysfs.reg, value) DBG(3, "Written bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf){ struct sn9c102_device* cam; ssize_t count; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); DBG(3, "Read bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_t sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len){ struct sn9c102_device* cam; u8 index; ssize_t count; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } index = sn9c102_strtou8(buf, len, &count); if (!count) { up(&sn9c102_sysfs_lock); return -EINVAL; } cam->sysfs.i2c_reg = index; DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg) DBG(3, "Written bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf){ struct sn9c102_device* cam; ssize_t count; int val; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) { up(&sn9c102_sysfs_lock); return -ENOSYS; } if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { up(&sn9c102_sysfs_lock); return -EIO; } count = sprintf(buf, "%d\n", val); DBG(3, "Read bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;} static ssize_tsn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len){ struct sn9c102_device* cam; u8 value; ssize_t count; int err; if (down_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { up(&sn9c102_sysfs_lock); return -ENODEV; } if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { up(&sn9c102_sysfs_lock); return -ENOSYS; } value = sn9c102_strtou8(buf, len, &count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -