int mt9v111_set_autoexposure(struct usb_sn9c20x *dev) { __u16 buf[1]; int ret = 0; /* Switch to IFP-register address space: */ ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP); if (ret < 0) return -11; /* -EAGAIN */ /* Read current value of IFP-register 0x06: */ ret = sn9c20x_read_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf); if (ret < 0) { UDIA_ERROR("Error: setting of auto exposure failed: " "error while reading from IFP-register 0x06\n"); return ret; } /* Set new value for register 0x06: */ if (dev->vsettings.auto_exposure) { buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE; } else { buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE; } /* Write new value to IFP-register 0x06: */ ret = sn9c20x_write_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf); if (ret < 0) { UDIA_ERROR("Error: setting of auto exposure failed: " "error while writing to IFP-register 0x06\n"); return ret; } return 0; }
/** * @brief Dequeue a video buffer. * * @param queue * @param v4l2_buf * @param nonblocking * * @return 0 or negative error code * * If nonblocking is false, block until a buffer is * available. */ int microdia_dequeue_buffer(struct microdia_video_queue *queue, struct v4l2_buffer *v4l2_buf, int nonblocking) { struct microdia_buffer *buf; int ret = 0; if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2_buf->memory != V4L2_MEMORY_MMAP) { UDIA_ERROR("[E] Invalid buffer type (%u) " "and/or memory (%u).\n", v4l2_buf->type, v4l2_buf->memory); return -EINVAL; } mutex_lock(&queue->mutex); if (list_empty(&queue->mainqueue)) { UDIA_ERROR("[E] Empty buffer queue.\n"); ret = -EINVAL; goto done; } buf = list_first_entry(&queue->mainqueue, struct microdia_buffer, stream); ret = microdia_queue_waiton(buf, nonblocking); if (ret < 0) goto done; UDIA_DEBUG("Dequeuing buffer %u (%u, %u bytes).\n", buf->buf.index, buf->state, buf->buf.bytesused); switch (buf->state) { case MICRODIA_BUF_STATE_ERROR: UDIA_WARNING("[W] Corrupted data (transmission error).\n"); ret = -EIO; case MICRODIA_BUF_STATE_DONE: buf->state = MICRODIA_BUF_STATE_IDLE; break; case MICRODIA_BUF_STATE_IDLE: case MICRODIA_BUF_STATE_QUEUED: case MICRODIA_BUF_STATE_ACTIVE: default: UDIA_ERROR("[E] Invalid buffer state %u " "(driver bug?).\n", buf->state); ret = -EINVAL; goto done; } list_del(&buf->stream); __microdia_query_buffer(buf, v4l2_buf); done: mutex_unlock(&queue->mutex); return ret; }
int mt9v111_select_address_space(struct usb_sn9c20x *dev, __u8 address_space) { __u8 buf[2]; int retI2C; int k; /* check if selection is valid: */ if ((address_space != MT9V111_ADDRESSSPACE_IFP) && (address_space != MT9V111_ADDRESSSPACE_SENSOR)) { UDIA_WARNING("invalid register address space " "selection for sensor MT9V111/MI0360SOC !\n"); return -1; } /* read address space slection register: */ k = 0; retI2C = -1; while ((k < 3) && (retI2C != 0)) { retI2C = sn9c20x_read_i2c_data(dev, 2, 0x01, buf); if (retI2C != 0 && k < 2) udelay(1000); k++; } if (retI2C != 0) { UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): " "read of reg0x01 (address space selection) failed !\n"); return -1; } /* check current address space: */ if ((buf[0] != 0x00) || (buf[1] != address_space)) { k = 0; retI2C = -1; while ((k < 3) && (retI2C != 0)) { /* switch address space: */ buf[0] = 0x00; buf[1] = address_space; retI2C = sn9c20x_write_i2c_data(dev, 2, 0x01, buf); if (retI2C != 0 && k < 2) udelay(1000); k++; } if (retI2C != 0) { if (address_space == MT9V111_ADDRESSSPACE_IFP) UDIA_ERROR("MT9V111/MI0360SOC " "(I2C-slave 0x5c): switch to IFP " "address space failed !\n"); else UDIA_ERROR("MT9V111/MI0360SOC " "(I2C-slave 0x5c): switch to sensor " "core address space failed !\n"); return -1; } } return 0; }
int mt9m111_set_autoexposure(struct usb_sn9c20x *dev) { int ret; __u16 data, page; ret = 0; page = 1; ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page); ret |= sn9c20x_read_i2c_data16(dev, 1, 0x06, &data); if (dev->vsettings.auto_exposure == 1) { data |= 0x7000; } else if (dev->vsettings.auto_exposure == 0) { data &= ~0x7000; } else return -EINVAL; ret |= sn9c20x_write_i2c_data16(dev, 1, 0x06, &data); page = 0; ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page); if (ret < 0) { UDIA_ERROR("Error: setting of auto exposure failed: " "error while writing to IFP-register 0x06\n"); return ret; } return 0; }
/** * @brief Queue a video buffer. * * @param queue * @param v4l2_buf * * @return 0 or negative error code * * Attempting to queue a buffer that has already been * queued will return -EINVAL. */ int microdia_queue_buffer(struct microdia_video_queue *queue, struct v4l2_buffer *v4l2_buf) { struct microdia_buffer *buf; unsigned long flags; int ret = 0; UDIA_DEBUG("Queuing buffer %u.\n", v4l2_buf->index); if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || v4l2_buf->memory != V4L2_MEMORY_MMAP) { UDIA_ERROR("[E] Invalid buffer type (%u) " "and/or memory (%u).\n", v4l2_buf->type, v4l2_buf->memory); return -EINVAL; } mutex_lock(&queue->mutex); if (v4l2_buf->index >= queue->count) { UDIA_ERROR("[E] Out of range index.\n"); ret = -EINVAL; goto done; } buf = &queue->buffer[v4l2_buf->index]; if (buf->state != MICRODIA_BUF_STATE_IDLE) { UDIA_ERROR("[E] Invalid buffer state " "(%u).\n", buf->state); ret = -EINVAL; goto done; } buf->state = MICRODIA_BUF_STATE_QUEUED; buf->buf.bytesused = 0; list_add_tail(&buf->stream, &queue->mainqueue); spin_lock_irqsave(&queue->irqlock, flags); list_add_tail(&buf->queue, &queue->irqqueue); spin_unlock_irqrestore(&queue->irqlock, flags); done: mutex_unlock(&queue->mutex); return ret; }