sn9c102_core.c
字号:
goto end_of_frame; /* (1) */ 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;}/*****************************************************************************/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 ((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; } value = sn9c102_strtou8(buf, len, &count); if (!count) { up(&sn9c102_sysfs_lock); return -EINVAL; } err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); if (err) { up(&sn9c102_sysfs_lock); return -EIO; } DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", cam->sysfs.i2c_reg, value) DBG(3, "Written bytes: %zd", count) up(&sn9c102_sysfs_lock); return count;}static ssize_tsn9c102_store_green(struct class_device* cd, const char* buf, size_t len){ ssize_t res = 0; u8 value; ssize_t count; value = sn9c102_strtou8(buf, len, &count); if (!count || value > 0x0f) return -EINVAL; if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) res = sn9c102_store_val(cd, buf, len); return res;}static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val);static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);static void sn9c102_create_sysfs(struct sn9c102_device* cam){ struct video_device *v4ldev = cam->v4ldev; video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); video_device_create_file(v4ldev, &class_device_attr_green); if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); }}/*****************************************************************************/static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale){ u8 r = 0; int err = 0; if (scale == 1) r = cam->reg[0x18] & 0xcf; else if (scale == 2) { r = cam->reg[0x18] & 0xcf; r |= 0x10; } else if (scale == 4) r = cam->reg[0x18] | 0x20; err += sn9c102_write_reg(cam, r, 0x18); if (err) return -EIO; PDBGG("Scaling factor: %u", scale) return 0;}static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect){ struct sn9c102_sensor* s = cam->sensor; u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), v_start = (u8)(rect->top - s->cropcap.bounds.top), h_size = (u8)(rect->width / 16), v_size = (u8)(rect->height / 16), ae_strx = 0x00, ae_stry = 0x00, ae_endx = h_size / 2, ae_endy = v_size / 2; int err = 0; err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, h_size, 0x15); err += sn9c102_write_reg(cam, v_size, 0x16); err += sn9c102_write_reg(cam, ae_strx, 0x1c); err += sn9c102_write_reg(cam, ae_stry, 0x1d); err += sn9c102_write_reg(cam, ae_endx, 0x1e); err += sn9c102_write_reg(cam, ae_endy, 0x1f); if (err) return -EIO; PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " "%u %u %u %u", h_start, v_start, h_size, v_size) return 0;}static int sn9c102_init(struct sn9c102_device* cam){ struct sn9c102_sensor* s = cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; u8 i = 0, n = 0; int err = 0; if (!(cam->state & DEV_INITIALIZED)) { init_waitqueue_head(&cam->open); qctrl = s->qctrl; rect = &(s->cropcap.defrect); } else { /* use current values */ qctrl = s->_qctrl; rect = &(s->_rect); } err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); err += sn9c102_set_crop(cam, rect); if (err) return err; if (s->init) { err = s->init(cam); if (err) { DBG(3, "Sensor initialization failed") return err; } } if (s->set_crop) if ((err = s->set_crop(cam, rect))) { DBG(3, "set_crop() failed") return err; } if (s->set_ctrl) { n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); for (i = 0; i < n; i++) if (s->qctrl[i].id != 0 && !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { ctrl.id = s->qctrl[i].id; ctrl.value = qctrl[i].default_value; err = s->set_ctrl(cam, &ctrl); if (err) { DBG(3, "Set control failed") return err; } } } if (!(cam->state & DEV_INITIALIZED)) { init_MUTEX(&cam->fileop_sem); spin_lock_init(&cam->queue_lock); init_waitqueue_head(&cam->wait_frame); init_waitqueue_head(&cam->wait_stream); memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); memcpy(&(s->_rect), &(s->cropcap.defrect), sizeof(struct v4l2_rect)); cam->state |= DEV_INITIALIZED; } DBG(2, "Initialization succeeded") return 0;}static void sn9c102_release_resources(struct sn9c102_device* cam){ down(&sn9c102_sysfs_lock); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor) video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); up(&sn9c102_sysfs_lock); kfree(cam->control_buffer);}/*****************************************************************************/static int sn9c102_open(struct inode* inode, struct file* filp){ struct sn9c102_device* cam; int err = 0; /* This is the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&sn9c102_disconnect)) return -ERESTARTSYS; cam = video_get_drvdata(video_devdata(filp)); if (down_interruptible(&cam->dev_sem)) { up_read(&sn9c102_disconnect);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -