mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
camera and uvc: support uvc sensor
This commit is contained in:
@@ -130,7 +130,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
|
||||
#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 |\
|
||||
@@ -240,7 +240,6 @@ struct rk29_camera_dev
|
||||
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;
|
||||
@@ -266,12 +265,12 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
|
||||
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
|
||||
@@ -435,12 +434,14 @@ static int rk29_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt)
|
||||
{
|
||||
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;
|
||||
@@ -622,7 +623,6 @@ static void rk29_camera_init_videobuf(struct videobuf_queue *q,
|
||||
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)
|
||||
{
|
||||
@@ -771,9 +771,11 @@ static int rk29_camera_add_device(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));
|
||||
}
|
||||
|
||||
@@ -805,16 +807,6 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
|
||||
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;
|
||||
@@ -917,16 +909,16 @@ static int rk29_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt
|
||||
}
|
||||
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,
|
||||
@@ -943,12 +935,14 @@ static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_p
|
||||
|
||||
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;
|
||||
@@ -1082,7 +1076,7 @@ static int rk29_camera_set_crop(struct soc_camera_device *icd,
|
||||
|
||||
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)
|
||||
@@ -1110,6 +1104,7 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
|
||||
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;
|
||||
@@ -1123,13 +1118,31 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1154,6 +1167,8 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -1205,7 +1220,7 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
|
||||
/* 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;
|
||||
@@ -1215,7 +1230,7 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
|
||||
/* 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);
|
||||
|
||||
@@ -515,7 +515,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
|
||||
mutex_lock(&icf->vb_vidq.vb_lock);
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
if (icf->vb_vidq.bufs[0]) {
|
||||
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
|
||||
ret = -EBUSY;
|
||||
@@ -529,7 +529,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
i = 0;
|
||||
while (icf->vb_vidq.bufs[i] && (i<VIDEO_MAX_FRAME)) {
|
||||
if (icf->vb_vidq.bufs[i]->state != VIDEOBUF_NEEDS_INIT) {
|
||||
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
|
||||
dev_err(&icd->dev, "S_FMT denied: queue initialised, icf->vb_vidq.bufs[%d]->state:0x%x\n",i,icf->vb_vidq.bufs[i]->state);
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -640,9 +640,8 @@ static int soc_camera_streamoff(struct file *file, void *priv,
|
||||
|
||||
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
mutex_lock(&icd->video_lock);
|
||||
|
||||
/* This calls buf_release from host driver's videobuf_queue_ops for all
|
||||
* remaining buffers. When the last buffer is freed, stop capture */
|
||||
videobuf_streamoff(&icf->vb_vidq);
|
||||
@@ -651,6 +650,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
|
||||
if (ici->ops->s_stream)
|
||||
ici->ops->s_stream(icd, 0); /* ddl@rock-chips.com : Add stream control for host */
|
||||
|
||||
videobuf_mmap_free(&icf->vb_vidq); /* ddl@rock-chips.com : free video buf */
|
||||
mutex_unlock(&icd->video_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -84,6 +84,7 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -286,6 +287,8 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
|
||||
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;
|
||||
@@ -323,10 +326,31 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -455,6 +479,8 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
|
||||
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,
|
||||
|
||||
@@ -249,12 +249,17 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
|
||||
struct uvc_frame *frame;
|
||||
int ret;
|
||||
|
||||
if (fmt->type != stream->type)
|
||||
if (fmt->type != stream->type) {
|
||||
printk("uvc_v4l2_set_format, fmt->type(%d) != stream->type(%d)\n",fmt->type,stream->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uvc_queue_allocated(&stream->queue))
|
||||
if (uvc_queue_allocated(&stream->queue)) {
|
||||
printk("uvc_queue_allocated failed\n");
|
||||
return -EBUSY;
|
||||
|
||||
}
|
||||
|
||||
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -738,8 +743,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
}
|
||||
|
||||
case VIDIOC_S_FMT:
|
||||
if ((ret = uvc_acquire_privileges(handle)) < 0)
|
||||
if ((ret = uvc_acquire_privileges(handle)) < 0) {
|
||||
printk("uvc_acquire_privileges error.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return uvc_v4l2_set_format(stream, arg);
|
||||
|
||||
@@ -907,14 +914,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
}
|
||||
|
||||
case VIDIOC_QBUF:
|
||||
if (!uvc_has_privileges(handle))
|
||||
if (!uvc_has_privileges(handle)) {
|
||||
printk("uvcvideo: VIDIOC_QBUF uvc_has_privileges failed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return uvc_queue_buffer(&stream->queue, arg);
|
||||
|
||||
case VIDIOC_DQBUF:
|
||||
if (!uvc_has_privileges(handle))
|
||||
if (!uvc_has_privileges(handle)) {
|
||||
printk("uvcvideo: VIDIOC_DQBUF uvc_has_privileges failed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return uvc_dequeue_buffer(&stream->queue, arg,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
|
||||
67
drivers/media/video/uvc/uvc_video.c
Normal file → Executable file
67
drivers/media/video/uvc/uvc_video.c
Normal file → Executable file
@@ -684,9 +684,11 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
|
||||
|
||||
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;
|
||||
@@ -724,6 +726,42 @@ static void uvc_video_complete(struct urb *urb)
|
||||
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.
|
||||
@@ -808,6 +846,12 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_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)
|
||||
@@ -861,6 +905,14 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -912,6 +964,15 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
|
||||
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;
|
||||
|
||||
5
drivers/media/video/uvc/uvcvideo.h
Normal file → Executable file
5
drivers/media/video/uvc/uvcvideo.h
Normal file → Executable file
@@ -405,8 +405,11 @@ struct uvc_video_queue {
|
||||
struct mutex mutex; /* protects buffers and mainqueue */
|
||||
spinlock_t irqlock; /* protects irqqueue */
|
||||
|
||||
wait_queue_head_t wait; /* wait if mainqueue is empty */
|
||||
|
||||
struct list_head mainqueue;
|
||||
struct list_head irqqueue;
|
||||
|
||||
};
|
||||
|
||||
struct uvc_video_chain {
|
||||
@@ -465,6 +468,8 @@ struct uvc_streaming {
|
||||
unsigned int urb_size;
|
||||
|
||||
__u8 last_fid;
|
||||
|
||||
struct tasklet_struct *tasklet[UVC_URBS]; /* ddl@rock-chips.com */
|
||||
};
|
||||
|
||||
enum uvc_device_state {
|
||||
|
||||
Reference in New Issue
Block a user