extractedLnx/linux-2.6.15/drivers/usb/media/sn9c102_core.c_sn9c102_ioctl_v4l2.c
static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
unsigned int cmd, void __user * arg)
{
struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
switch (cmd) {
case VIDIOC_QUERYCAP:
{
struct v4l2_capability cap = {
.driver = "sn9c102",
.version = SN9C102_MODULE_VERSION_CODE,
.capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING,
};
strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
if (usb_make_path(cam->usbdev, cap.bus_info,
sizeof(cap.bus_info)) < 0)
strlcpy(cap.bus_info, cam->dev.bus_id,
sizeof(cap.bus_info));
if (copy_to_user(arg, &cap, sizeof(cap)))
return -EFAULT;
return 0;
}
case VIDIOC_ENUMINPUT:
{
struct v4l2_input i;
if (copy_from_user(&i, arg, sizeof(i)))
return -EFAULT;
if (i.index)
return -EINVAL;
memset(&i, 0, sizeof(i));
strcpy(i.name, "USB");
if (copy_to_user(arg, &i, sizeof(i)))
return -EFAULT;
return 0;
}
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
{
int index;
if (copy_from_user(&index, arg, sizeof(index)))
return -EFAULT;
if (index != 0)
return -EINVAL;
return 0;
}
case VIDIOC_QUERYCTRL:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_queryctrl qc;
u8 i, n;
if (copy_from_user(&qc, arg, sizeof(qc)))
return -EFAULT;
n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);
for (i = 0; i < n; i++)
if (qc.id && qc.id == s->qctrl[i].id) {
memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
if (copy_to_user(arg, &qc, sizeof(qc)))
return -EFAULT;
return 0;
}
return -EINVAL;
}
case VIDIOC_G_CTRL:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_control ctrl;
int err = 0;
if (!s->get_ctrl)
return -EINVAL;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
err = s->get_ctrl(cam, &ctrl);
if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
return -EFAULT;
return err;
}
case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_control ctrl;
u8 i, n;
int err = 0;
if (!s->set_ctrl)
return -EINVAL;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
n = sizeof(s->qctrl) / sizeof(s->qctrl[0]);
for (i = 0; i < n; i++)
if (ctrl.id == s->qctrl[i].id) {
if (ctrl.value < s->qctrl[i].minimum ||
ctrl.value > s->qctrl[i].maximum)
return -ERANGE;
ctrl.value -= ctrl.value % s->qctrl[i].step;
break;
}
if ((err = s->set_ctrl(cam, &ctrl)))
return err;
s->_qctrl[i].default_value = ctrl.value;
PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
(unsigned long)ctrl.id, (unsigned long)ctrl.value)
return 0;
}
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cc->pixelaspect.numerator = 1;
cc->pixelaspect.denominator = 1;
if (copy_to_user(arg, cc, sizeof(*cc)))
return -EFAULT;
return 0;
}
case VIDIOC_G_CROP:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_crop crop = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
};
memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
if (copy_to_user(arg, &crop, sizeof(crop)))
return -EFAULT;
return 0;
}
case VIDIOC_S_CROP:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_crop crop;
struct v4l2_rect* rect;
struct v4l2_rect* bounds = &(s->cropcap.bounds);
struct v4l2_pix_format* pix_format = &(s->pix_format);
u8 scale;
const enum sn9c102_stream_state stream = cam->stream;
const u32 nbuffers = cam->nbuffers;
u32 i;
int err = 0;
if (copy_from_user(&crop, arg, sizeof(crop)))
return -EFAULT;
rect = &(crop.c);
if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (cam->module_param.force_munmap)
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.")
return -EINVAL;
}
/* Preserve R,G or B origin */
rect->left = (s->_rect.left & 1L) ?
rect->left | 1L : rect->left & ~1L;
rect->top = (s->_rect.top & 1L) ?
rect->top | 1L : rect->top & ~1L;
if (rect->width < 16)
rect->width = 16;
if (rect->height < 16)
rect->height = 16;
if (rect->width > bounds->width)
rect->width = bounds->width;
if (rect->height > bounds->height)
rect->height = bounds->height;
if (rect->left < bounds->left)
rect->left = bounds->left;
if (rect->top < bounds->top)
rect->top = bounds->top;
if (rect->left + rect->width > bounds->left + bounds->width)
rect->left = bounds->left+bounds->width - rect->width;
if (rect->top + rect->height > bounds->top + bounds->height)
rect->top = bounds->top+bounds->height - rect->height;
rect->width &= ~15L;
rect->height &= ~15L;
if (SN9C102_PRESERVE_IMGSCALE) {
/* Calculate the actual scaling factor */
u32 a, b;
a = rect->width * rect->height;
b = pix_format->width * pix_format->height;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
} else
scale = 1;
if (cam->stream == STREAM_ON)
if ((err = sn9c102_stream_interrupt(cam)))
return err;
if (copy_to_user(arg, &crop, sizeof(crop))) {
cam->stream = stream;
return -EFAULT;
}
if (cam->module_param.force_munmap || cam->io == IO_READ)
sn9c102_release_buffers(cam);
err = sn9c102_set_crop(cam, rect);
if (s->set_crop)
err += s->set_crop(cam, rect);
err += sn9c102_set_scale(cam, scale);
if (err) { /* atomic, no rollback in ioctl() */
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of hardware "
"problems. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
return -EIO;
}
s->pix_format.width = rect->width/scale;
s->pix_format.height = rect->height/scale;
memcpy(&(s->_rect), rect, sizeof(*rect));
if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
nbuffers != sn9c102_request_buffers(cam, nbuffers,
cam->io)) {
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_CROP failed because of not enough "
"memory. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
return -ENOMEM;
}
cam->stream = stream;
return 0;
}
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc fmtd;
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
if (fmtd.index == 0) {
strcpy(fmtd.description, "bayer rgb");
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
} else if (fmtd.index == 1) {
strcpy(fmtd.description, "compressed");
fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
} else
return -EINVAL;
fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
return -EFAULT;
return 0;
}
case VIDIOC_G_FMT:
{
struct v4l2_format format;
struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
if (copy_from_user(&format, arg, sizeof(format)))
return -EFAULT;
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
pfmt->field = V4L2_FIELD_NONE;
memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
if (copy_to_user(arg, &format, sizeof(format)))
return -EFAULT;
return 0;
}
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT:
{
struct sn9c102_sensor* s = cam->sensor;
struct v4l2_format format;
struct v4l2_pix_format* pix;
struct v4l2_pix_format* pfmt = &(s->pix_format);
struct v4l2_rect* bounds = &(s->cropcap.bounds);
struct v4l2_rect rect;
u8 scale;
const enum sn9c102_stream_state stream = cam->stream;
const u32 nbuffers = cam->nbuffers;
u32 i;
int err = 0;
if (copy_from_user(&format, arg, sizeof(format)))
return -EFAULT;
pix = &(format.fmt.pix);
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memcpy(&rect, &(s->_rect), sizeof(rect));
{ /* calculate the actual scaling factor */
u32 a, b;
a = rect.width * rect.height;
b = pix->width * pix->height;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
}
rect.width = scale * pix->width;
rect.height = scale * pix->height;
if (rect.width < 16)
rect.width = 16;
if (rect.height < 16)
rect.height = 16;
if (rect.width > bounds->left + bounds->width - rect.left)
rect.width = bounds->left + bounds->width - rect.left;
if (rect.height > bounds->top + bounds->height - rect.top)
rect.height = bounds->top + bounds->height - rect.top;
rect.width &= ~15L;
rect.height &= ~15L;
{ /* adjust the scaling factor */
u32 a, b;
a = rect.width * rect.height;
b = pix->width * pix->height;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
}
pix->width = rect.width / scale;
pix->height = rect.height / scale;
if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
pix->priv = pfmt->priv; /* bpp */
pix->colorspace = pfmt->colorspace;
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
? 0 : (pix->width * pix->priv) / 8;
pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
pix->field = V4L2_FIELD_NONE;
if (cmd == VIDIOC_TRY_FMT) {
if (copy_to_user(arg, &format, sizeof(format)))
return -EFAULT;
return 0;
}
if (cam->module_param.force_munmap)
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.")
return -EINVAL;
}
if (cam->stream == STREAM_ON)
if ((err = sn9c102_stream_interrupt(cam)))
return err;
if (copy_to_user(arg, &format, sizeof(format))) {
cam->stream = stream;
return -EFAULT;
}
if (cam->module_param.force_munmap || cam->io == IO_READ)
sn9c102_release_buffers(cam);
err += sn9c102_set_pix_format(cam, pix);
err += sn9c102_set_crop(cam, &rect);
if (s->set_pix_format)
err += s->set_pix_format(cam, pix);
if (s->set_crop)
err += s->set_crop(cam, &rect);
err += sn9c102_set_scale(cam, scale);
if (err) { /* atomic, no rollback in ioctl() */
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of hardware "
"problems. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
return -EIO;
}
memcpy(pfmt, pix, sizeof(*pix));
memcpy(&(s->_rect), &rect, sizeof(rect));
if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
nbuffers != sn9c102_request_buffers(cam, nbuffers,
cam->io)) {
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_FMT failed because of not enough "
"memory. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
return -ENOMEM;
}
cam->stream = stream;
return 0;
}
case VIDIOC_G_JPEGCOMP:
{
if (copy_to_user(arg, &cam->compression,
sizeof(cam->compression)))
return -EFAULT;
return 0;
}
case VIDIOC_S_JPEGCOMP:
{
struct v4l2_jpegcompression jc;
const enum sn9c102_stream_state stream = cam->stream;
int err = 0;
if (copy_from_user(&jc, arg, sizeof(jc)))
return -EFAULT;
if (jc.quality != 0 && jc.quality != 1)
return -EINVAL;
if (cam->stream == STREAM_ON)
if ((err = sn9c102_stream_interrupt(cam)))
return err;
err += sn9c102_set_compression(cam, &jc);
if (err) { /* atomic, no rollback in ioctl() */
cam->state |= DEV_MISCONFIGURED;
DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
"problems. To use the camera, close and open "
"/dev/video%d again.", cam->v4ldev->minor)
return -EIO;
}
cam->compression.quality = jc.quality;
cam->stream = stream;
return 0;
}
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers rb;
u32 i;
int err;
if (copy_from_user(&rb, arg, sizeof(rb)))
return -EFAULT;
if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
rb.memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose "
"the mmap I/O method")
return -EINVAL;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.")
return -EINVAL;
}
if (cam->stream == STREAM_ON)
if ((err = sn9c102_stream_interrupt(cam)))
return err;
sn9c102_empty_framequeues(cam);
sn9c102_release_buffers(cam);
if (rb.count)
rb.count = sn9c102_request_buffers(cam, rb.count,
IO_MMAP);
if (copy_to_user(arg, &rb, sizeof(rb))) {
sn9c102_release_buffers(cam);
cam->io = IO_NONE;
return -EFAULT;
}
cam->io = rb.count ? IO_MMAP : IO_NONE;
return 0;
}
case VIDIOC_QUERYBUF:
{
struct v4l2_buffer b;
if (copy_from_user(&b, arg, sizeof(b)))
return -EFAULT;
if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
b.index >= cam->nbuffers || cam->io != IO_MMAP)
return -EINVAL;
memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
if (cam->frame[b.index].vma_use_count)
b.flags |= V4L2_BUF_FLAG_MAPPED;
if (cam->frame[b.index].state == F_DONE)
b.flags |= V4L2_BUF_FLAG_DONE;
else if (cam->frame[b.index].state != F_UNUSED)
b.flags |= V4L2_BUF_FLAG_QUEUED;
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
return 0;
}
case VIDIOC_QBUF:
{
struct v4l2_buffer b;
unsigned long lock_flags;
if (copy_from_user(&b, arg, sizeof(b)))
return -EFAULT;
if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
b.index >= cam->nbuffers || cam->io != IO_MMAP)
return -EINVAL;
if (cam->frame[b.index].state != F_UNUSED)
return -EINVAL;
cam->frame[b.index].state = F_QUEUED;
spin_lock_irqsave(&cam->queue_lock, lock_flags);
list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
PDBGG("Frame #%lu queued", (unsigned long)b.index)
return 0;
}
case VIDIOC_DQBUF:
{
struct v4l2_buffer b;
struct sn9c102_frame_t *f;
unsigned long lock_flags;
int err = 0;
if (copy_from_user(&b, arg, sizeof(b)))
return -EFAULT;
if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
return -EINVAL;
if (list_empty(&cam->outqueue)) {
if (cam->stream == STREAM_OFF)
return -EINVAL;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
err = wait_event_interruptible
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED) );
if (err)
return err;
if (cam->state & DEV_DISCONNECTED)
return -ENODEV;
if (cam->state & DEV_MISCONFIGURED)
return -EIO;
}
spin_lock_irqsave(&cam->queue_lock, lock_flags);
f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
frame);
list_del(cam->outqueue.next);
spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
f->state = F_UNUSED;
memcpy(&b, &f->buf, sizeof(b));
if (f->vma_use_count)
b.flags |= V4L2_BUF_FLAG_MAPPED;
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index)
return 0;
}
case VIDIOC_STREAMON:
{
int type;
if (copy_from_user(&type, arg, sizeof(type)))
return -EFAULT;
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
if (list_empty(&cam->inqueue))
return -EINVAL;
cam->stream = STREAM_ON;
DBG(3, "Stream on")
return 0;
}
case VIDIOC_STREAMOFF:
{
int type, err;
if (copy_from_user(&type, arg, sizeof(type)))
return -EFAULT;
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
if (cam->stream == STREAM_ON)
if ((err = sn9c102_stream_interrupt(cam)))
return err;
sn9c102_empty_framequeues(cam);
DBG(3, "Stream off")
return 0;
}
case VIDIOC_G_PARM:
{
struct v4l2_streamparm sp;
if (copy_from_user(&sp, arg, sizeof(sp)))
return -EFAULT;
if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
sp.parm.capture.extendedmode = 0;
sp.parm.capture.readbuffers = cam->nreadbuffers;
if (copy_to_user(arg, &sp, sizeof(sp)))
return -EFAULT;
return 0;
}
case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
{
struct v4l2_streamparm sp;
if (copy_from_user(&sp, arg, sizeof(sp)))
return -EFAULT;
if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
sp.parm.capture.extendedmode = 0;
if (sp.parm.capture.readbuffers == 0)
sp.parm.capture.readbuffers = cam->nreadbuffers;
if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
if (copy_to_user(arg, &sp, sizeof(sp)))
return -EFAULT;
cam->nreadbuffers = sp.parm.capture.readbuffers;
return 0;
}
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
return -EINVAL;
default:
return -EINVAL;
}
}
Generated by GNU enscript 1.6.4.