#define CAM_IPPWORK_IS_EN() ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))
//Configure Macro
-#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 2)
/* limit to rk29 hardware capabilities */
#define RK29_CAM_BUS_PARAM (SOCAM_MASTER |\
spinlock_t lock;
struct videobuf_buffer *active;
- struct videobuf_queue *vb_vidq_ptr;
struct rk29_camera_reg reginfo_suspend;
struct workqueue_struct *camera_wq;
struct rk29_camera_work *camera_work;
struct soc_camera_device *icd = vq->priv_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk29_camera_dev *pcdev = ici->priv;
- int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
/* planar capture requires Y, U and V buffers to be page aligned */
#if 0
+ int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
*size = PAGE_ALIGN(icd->user_width* icd->user_height * bytes_per_pixel); /* Y pages UV pages, yuv422*/
pcdev->vipmem_bsize = PAGE_ALIGN(pcdev->host_width * pcdev->host_height * bytes_per_pixel);
#else
{
switch (pixfmt)
{
- case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_YUV422P:
{
*ippfmt = IPP_Y_CBCR_H2V1;
break;
}
- case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV420:
{
*ippfmt = IPP_Y_CBCR_H2V2;
break;
V4L2_FIELD_NONE,
sizeof(struct rk29_buffer),
icd);
- pcdev->vb_vidq_ptr = q; /* ddl@rock-chips.com */
}
static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera_device *icd)
{
if (control) {
sd = dev_get_drvdata(control);
v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_IOREQUEST,(void*)pcdev->pdata);
+ #if 0
ret = v4l2_subdev_call(sd,core, init, 0);
if (ret)
goto ebusy;
+ #endif
v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_CB_REGISTER,(void*)(&pcdev->icd_cb));
}
v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_DEACTIVATE,NULL);
rk29_camera_deactivate(pcdev);
- /* ddl@rock-chips.com: Call videobuf_mmap_free here for free the struct video_buffer which malloc in videobuf_alloc */
- #if 0
- if (pcdev->vb_vidq_ptr) {
- videobuf_mmap_free(pcdev->vb_vidq_ptr);
- pcdev->vb_vidq_ptr = NULL;
- }
- #else
- pcdev->vb_vidq_ptr = NULL;
- #endif
-
if (pcdev->camera_work) {
kfree(pcdev->camera_work);
pcdev->camera_work = NULL;
}
static const struct soc_camera_data_format rk29_camera_formats[] = {
{
- .name = "Planar YUV420 12 bit",
+ .name = "YUV420 NV12",
.depth = 12,
- .fourcc = V4L2_PIX_FMT_YUV420,
+ .fourcc = V4L2_PIX_FMT_NV12,
.colorspace = V4L2_COLORSPACE_JPEG,
},{
- .name = "Planar YUV422 16 bit",
+ .name = "YUV422 NV16",
.depth = 16,
- .fourcc = V4L2_PIX_FMT_YUV422P,
+ .fourcc = V4L2_PIX_FMT_NV16,
.colorspace = V4L2_COLORSPACE_JPEG,
- },{
+ },{
.name = "Raw Bayer RGB 10 bit",
.depth = 16,
.fourcc = V4L2_PIX_FMT_SGRBG10,
switch (host_pixfmt)
{
- case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_YUV422P: /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV422P is V4L2_PIX_FMT_NV16 actually in 0.0.1 driver */
vip_ctrl_val |= VIPREGYUV422;
pcdev->frame_inval = RK29_CAM_FRAME_INVAL_DC;
pcdev->pixfmt = host_pixfmt;
break;
- case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV420: /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV420 is V4L2_PIX_FMT_NV12 actually in 0.0.1 driver */
vip_ctrl_val |= VIPREGYUV420;
if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
&pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
- icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?4 : 0);
+ icd->current_fmt->fourcc == V4L2_PIX_FMT_NV16 ?4 : 0);
ret = v4l2_subdev_call(sd, video, s_fmt, &f);
if (ret < 0)
struct v4l2_format cam_f = *f;
struct v4l2_rect rect;
int ret,usr_w,usr_h;
+ int stream_on = 0;
usr_w = pix->width;
usr_h = pix->height;
}
cam_fmt = xlate->cam_fmt;
+ /* ddl@rock-chips.com: sensor init code transmit in here after open */
+ if ((pcdev->frame_inval == RK29_CAM_FRAME_INVAL_INIT) && (pcdev->active == NULL)
+ && list_empty(&pcdev->capture)) {
+ v4l2_subdev_call(sd,core, init, 0);
+ }
+ stream_on = read_vip_reg(RK29_VIP_CTRL);
+ if (stream_on & ENABLE_CAPTURE)
+ write_vip_reg(RK29_VIP_CTRL, (stream_on & (~ENABLE_CAPTURE)));
cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f);
cam_f.fmt.pix.pixelformat = pix->pixelformat;
*pix = cam_f.fmt.pix;
#ifdef CONFIG_VIDEO_RK29_WORK_IPP
if ((pix->width != usr_w) || (pix->height != usr_h)) {
+ if (unlikely((pix->width <16) || (pix->width > 8190) || (pix->height < 16) || (pix->height > 8190))) {
+ RK29CAMERA_TR("Senor and IPP both invalid source resolution(%dx%d)\n",pix->width,pix->height);
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
+ if (unlikely((usr_w <16) || (usr_w > 2047) || (usr_h < 16) || (usr_h > 2047))) {
+ RK29CAMERA_TR("Senor and IPP both invalid destination resolution(%dx%d)\n",usr_w,usr_h);
+ ret = -EINVAL;
+ goto RK29_CAMERA_SET_FMT_END;
+ }
pix->width = usr_w;
pix->height = usr_h;
}
}
RK29_CAMERA_SET_FMT_END:
+ if (stream_on & ENABLE_CAPTURE)
+ write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL) | ENABLE_CAPTURE));
if (ret)
RK29CAMERA_TR("\n%s..%d.. ret = %d \n",__FUNCTION__,__LINE__, ret);
return ret;
/* limit to rk29 hardware capabilities */
v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
&pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
- pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+ pixfmt == V4L2_PIX_FMT_NV16 ? 4 : 0);
pix->bytesperline = pix->width * DIV_ROUND_UP(xlate->host_fmt->depth, 8);
pix->sizeimage = pix->height * pix->bytesperline;
/* limit to sensor capabilities */
ret = v4l2_subdev_call(sd, video, try_fmt, f);
pix->pixelformat = pixfmt;
- #ifdef CONFIG_VIDEO_RK29_WORK_IPP
+ #ifdef CONFIG_VIDEO_RK29_WORK_IPP
if ((pix->width > usr_w) && (pix->height > usr_h)) {
if (is_capture) {
vipmem_is_overflow = (PAGE_ALIGN((pix->width*pix->height*icd->current_fmt->depth+7)>>3) > pcdev->vipmem_size);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->mainqueue);
INIT_LIST_HEAD(&queue->irqqueue);
+ init_waitqueue_head(&queue->wait); /* ddl@rock-chips.com : This design copied from video-buf */
queue->type = type;
}
list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
+ wake_up_interruptible_sync(&queue->wait); /* ddl@rock-chips.com : This design copied from video-buf */
+
done:
mutex_unlock(&queue->mutex);
return ret;
}
mutex_lock(&queue->mutex);
+ /* ddl@rock-chips.com : This design copied from video-buf */
+checks:
if (list_empty(&queue->mainqueue)) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
- ret = -EINVAL;
- goto done;
+ if (nonblocking) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ //uvc_trace(UVC_TRACE_CAPTURE, "dequeue_buffer: waiting on buffer\n");
+ printk("dequeue_buffer: waiting on buffer\n");
+ /* Drop lock to avoid deadlock with qbuf */
+ mutex_unlock(&queue->mutex);
+
+ /* Checking list_empty and streaming is safe without
+ * locks because we goto checks to validate while
+ * holding locks before proceeding */
+ ret = wait_event_interruptible(queue->wait,
+ ((!list_empty(&queue->mainqueue)) || (!(queue->flags & UVC_QUEUE_STREAMING))));
+ mutex_lock(&queue->mutex);
+
+ if (ret)
+ goto done;
+
+ goto checks;
+ }
}
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
struct uvc_buffer *buf;
unsigned long flags;
+ wake_up_interruptible_sync(&queue->wait); /* ddl@rock-chips.com : This design copied from video-buf */
+
spin_lock_irqsave(&queue->irqlock, flags);
while (!list_empty(&queue->irqqueue)) {
buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
urb->transfer_buffer_length = stream->urb_size - len;
}
-
-static void uvc_video_complete(struct urb *urb)
-{
+/* ddl@rock-chips.com : uvc_video_complete is run in_interrupt(), so uvc decode operation delay run in tasklet for
+* usb host reenable interrupt soon
+*/
+static void uvc_video_complete_fun (struct urb *urb)
+{
struct uvc_streaming *stream = urb->context;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *buf = NULL;
ret);
}
}
+static void uvc_video_complete_tasklet(unsigned long data)
+{
+ struct urb *urb = (struct urb*)data;
+ struct uvc_streaming *stream = urb->context;
+ struct tasklet_struct *tasklet = NULL;
+ int i;
+
+ uvc_video_complete_fun(urb);
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (stream->urb[i] == urb) {
+ tasklet = stream->tasklet[i];
+ break;
+ }
+ }
+
+ return;
+}
+static void uvc_video_complete(struct urb *urb)
+{
+ int i;
+ struct uvc_streaming *stream = urb->context;
+ struct tasklet_struct *tasklet = NULL;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if (stream->urb[i] == urb) {
+ tasklet = stream->tasklet[i];
+ break;
+ }
+ }
+
+ if (tasklet != NULL) {
+ tasklet_schedule(tasklet);
+ } else {
+ uvc_video_complete_fun(urb);
+ }
+}
/*
* Free transfer buffers.
usb_kill_urb(urb);
usb_free_urb(urb);
stream->urb[i] = NULL;
+ /* ddl@rock-chips.com */
+ if (stream->tasklet[i]) {
+ tasklet_kill(stream->tasklet[i]);
+ kfree(stream->tasklet[i]);
+ stream->tasklet[i] = NULL;
+ }
}
if (free_buffers)
}
stream->urb[i] = urb;
+ /* ddl@rock-chips.com */
+ stream->tasklet[i] = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+ if (stream->tasklet[i] == NULL) {
+ uvc_printk(KERN_ERR, "device %s requested tasklet memory fail!\n",
+ stream->dev->name);
+ } else {
+ tasklet_init(stream->tasklet[i], uvc_video_complete_tasklet, (unsigned long)urb);
+ }
}
return 0;
urb->transfer_dma = stream->urb_dma[i];
stream->urb[i] = urb;
+
+ /* ddl@rock-chips.com */
+ stream->tasklet[i] = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+ if (stream->tasklet[i] == NULL) {
+ uvc_printk(KERN_ERR, "device %s requested tasklet memory fail!\n",
+ stream->dev->name);
+ } else {
+ tasklet_init(stream->tasklet[i], uvc_video_complete_tasklet, (unsigned long)urb);
+ }
}
return 0;