extractedLnx/linux-2.6.9/drivers/usb/media/w9968cf.c_w9968cf_v4l_ioctl.c
static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
unsigned int cmd, void __user * arg)
{
struct w9968cf_device* cam;
const char* v4l1_ioctls[] = {
"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
"SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
"SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
"SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
"GVBIFMT", "SVBIFMT"
};
#define V4L1_IOCTL(cmd) \
((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \
v4l1_ioctls[_IOC_NR((cmd))] : "?")
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
switch (cmd) {
case VIDIOCGCAP: /* get video capability */
{
struct video_capability cap = {
.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
.channels = 1,
.audios = 0,
.minwidth = cam->minwidth,
.minheight = cam->minheight,
};
sprintf(cap.name, "W996[87]CF USB Camera #%d",
cam->v4ldev->minor);
cap.maxwidth = (cam->upscaling && w9968cf_vpp)
? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
: cam->maxwidth;
cap.maxheight = (cam->upscaling && w9968cf_vpp)
? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
: cam->maxheight;
if (copy_to_user(arg, &cap, sizeof(cap)))
return -EFAULT;
DBG(5, "VIDIOCGCAP successfully called")
return 0;
}
case VIDIOCGCHAN: /* get video channel informations */
{
struct video_channel chan;
if (copy_from_user(&chan, arg, sizeof(chan)))
return -EFAULT;
if (chan.channel != 0)
return -EINVAL;
strcpy(chan.name, "Camera");
chan.tuners = 0;
chan.flags = 0;
chan.type = VIDEO_TYPE_CAMERA;
chan.norm = VIDEO_MODE_AUTO;
if (copy_to_user(arg, &chan, sizeof(chan)))
return -EFAULT;
DBG(5, "VIDIOCGCHAN successfully called")
return 0;
}
case VIDIOCSCHAN: /* set active channel */
{
struct video_channel chan;
if (copy_from_user(&chan, arg, sizeof(chan)))
return -EFAULT;
if (chan.channel != 0)
return -EINVAL;
DBG(5, "VIDIOCSCHAN successfully called")
return 0;
}
case VIDIOCGPICT: /* get image properties of the picture */
{
if (w9968cf_sensor_get_picture(cam))
return -EIO;
if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
return -EFAULT;
DBG(5, "VIDIOCGPICT successfully called")
return 0;
}
case VIDIOCSPICT: /* change picture settings */
{
struct video_picture pict;
int err = 0;
if (copy_from_user(&pict, arg, sizeof(pict)))
return -EFAULT;
if ( (cam->force_palette || !w9968cf_vpp)
&& pict.palette != cam->picture.palette ) {
DBG(4, "Palette %s rejected: only %s is allowed",
symbolic(v4l1_plist, pict.palette),
symbolic(v4l1_plist, cam->picture.palette))
return -EINVAL;
}
if (!w9968cf_valid_palette(pict.palette)) {
DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
symbolic(v4l1_plist, pict.palette))
return -EINVAL;
}
if (!cam->force_palette) {
if (cam->decompression == 0) {
if (w9968cf_need_decompression(pict.palette)) {
DBG(4, "Decompression disabled: palette %s is not "
"allowed. VIDIOCSPICT failed",
symbolic(v4l1_plist, pict.palette))
return -EINVAL;
}
} else if (cam->decompression == 1) {
if (!w9968cf_need_decompression(pict.palette)) {
DBG(4, "Decompression forced: palette %s is not "
"allowed. VIDIOCSPICT failed",
symbolic(v4l1_plist, pict.palette))
return -EINVAL;
}
}
}
if (pict.depth != w9968cf_valid_depth(pict.palette)) {
DBG(4, "Requested depth %u bpp is not valid for %s "
"palette: ignored and changed to %u bpp",
pict.depth, symbolic(v4l1_plist, pict.palette),
w9968cf_valid_depth(pict.palette))
pict.depth = w9968cf_valid_depth(pict.palette);
}
if (pict.palette != cam->picture.palette) {
if(*cam->requested_frame
|| cam->frame_current->queued) {
err = wait_event_interruptible
( cam->wait_queue,
cam->disconnected ||
(!*cam->requested_frame &&
!cam->frame_current->queued) );
if (err)
return err;
if (cam->disconnected)
return -ENODEV;
}
if (w9968cf_stop_transfer(cam))
goto ioctl_fail;
if (w9968cf_set_picture(cam, pict))
goto ioctl_fail;
if (w9968cf_start_transfer(cam))
goto ioctl_fail;
} else if (w9968cf_sensor_update_picture(cam, pict))
return -EIO;
DBG(5, "VIDIOCSPICT successfully called")
return 0;
}
case VIDIOCSWIN: /* set capture area */
{
struct video_window win;
int err = 0;
if (copy_from_user(&win, arg, sizeof(win)))
return -EFAULT;
DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
"x=%u, y=%u, %ux%u", win.clipcount, win.flags,
win.x, win.y, win.width, win.height)
if (win.clipcount != 0 || win.flags != 0)
return -EINVAL;
if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
(u16*)&win.height))) {
DBG(4, "Resolution not supported (%ux%u). "
"VIDIOCSWIN failed", win.width, win.height)
return err;
}
if (win.x != cam->window.x ||
win.y != cam->window.y ||
win.width != cam->window.width ||
win.height != cam->window.height) {
if(*cam->requested_frame
|| cam->frame_current->queued) {
err = wait_event_interruptible
( cam->wait_queue,
cam->disconnected ||
(!*cam->requested_frame &&
!cam->frame_current->queued) );
if (err)
return err;
if (cam->disconnected)
return -ENODEV;
}
if (w9968cf_stop_transfer(cam))
goto ioctl_fail;
/* This _must_ be called before set_window() */
if (w9968cf_set_picture(cam, cam->picture))
goto ioctl_fail;
if (w9968cf_set_window(cam, win))
goto ioctl_fail;
if (w9968cf_start_transfer(cam))
goto ioctl_fail;
}
DBG(5, "VIDIOCSWIN successfully called. ")
return 0;
}
case VIDIOCGWIN: /* get current window properties */
{
if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
return -EFAULT;
DBG(5, "VIDIOCGWIN successfully called")
return 0;
}
case VIDIOCGMBUF: /* request for memory (mapped) buffer */
{
struct video_mbuf mbuf;
u8 i;
mbuf.size = cam->nbuffers * cam->frame[0].size;
mbuf.frames = cam->nbuffers;
for (i = 0; i < cam->nbuffers; i++)
mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
(unsigned long)cam->frame[0].buffer;
if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
return -EFAULT;
DBG(5, "VIDIOCGMBUF successfully called")
return 0;
}
case VIDIOCMCAPTURE: /* start the capture to a frame */
{
struct video_mmap mmap;
struct w9968cf_frame_t* fr;
int err = 0;
if (copy_from_user(&mmap, arg, sizeof(mmap)))
return -EFAULT;
DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
mmap.frame, symbolic(v4l1_plist, mmap.format),
mmap.width, mmap.height)
if (mmap.frame >= cam->nbuffers) {
DBG(4, "Invalid frame number (%u). "
"VIDIOCMCAPTURE failed", mmap.frame)
return -EINVAL;
}
if (mmap.format!=cam->picture.palette &&
(cam->force_palette || !w9968cf_vpp)) {
DBG(4, "Palette %s rejected: only %s is allowed",
symbolic(v4l1_plist, mmap.format),
symbolic(v4l1_plist, cam->picture.palette))
return -EINVAL;
}
if (!w9968cf_valid_palette(mmap.format)) {
DBG(4, "Palette %s not supported. "
"VIDIOCMCAPTURE failed",
symbolic(v4l1_plist, mmap.format))
return -EINVAL;
}
if (!cam->force_palette) {
if (cam->decompression == 0) {
if (w9968cf_need_decompression(mmap.format)) {
DBG(4, "Decompression disabled: palette %s is not "
"allowed. VIDIOCSPICT failed",
symbolic(v4l1_plist, mmap.format))
return -EINVAL;
}
} else if (cam->decompression == 1) {
if (!w9968cf_need_decompression(mmap.format)) {
DBG(4, "Decompression forced: palette %s is not "
"allowed. VIDIOCSPICT failed",
symbolic(v4l1_plist, mmap.format))
return -EINVAL;
}
}
}
if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
(u16*)&mmap.height))) {
DBG(4, "Resolution not supported (%dx%d). "
"VIDIOCMCAPTURE failed",
mmap.width, mmap.height)
return err;
}
fr = &cam->frame[mmap.frame];
if (mmap.width != cam->window.width ||
mmap.height != cam->window.height ||
mmap.format != cam->picture.palette) {
struct video_window win;
struct video_picture pict;
if(*cam->requested_frame
|| cam->frame_current->queued) {
DBG(6, "VIDIOCMCAPTURE. Change settings for "
"frame #%u: %dx%d, format %s. Wait...",
mmap.frame, mmap.width, mmap.height,
symbolic(v4l1_plist, mmap.format))
err = wait_event_interruptible
( cam->wait_queue,
cam->disconnected ||
(!*cam->requested_frame &&
!cam->frame_current->queued) );
if (err)
return err;
if (cam->disconnected)
return -ENODEV;
}
memcpy(&win, &cam->window, sizeof(win));
memcpy(&pict, &cam->picture, sizeof(pict));
win.width = mmap.width;
win.height = mmap.height;
pict.palette = mmap.format;
if (w9968cf_stop_transfer(cam))
goto ioctl_fail;
/* This before set_window */
if (w9968cf_set_picture(cam, pict))
goto ioctl_fail;
if (w9968cf_set_window(cam, win))
goto ioctl_fail;
if (w9968cf_start_transfer(cam))
goto ioctl_fail;
} else if (fr->queued) {
DBG(6, "Wait until frame #%u is free", mmap.frame)
err = wait_event_interruptible(cam->wait_queue,
cam->disconnected ||
(!fr->queued));
if (err)
return err;
if (cam->disconnected)
return -ENODEV;
}
w9968cf_push_frame(cam, mmap.frame);
DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
return 0;
}
case VIDIOCSYNC: /* wait until the capture of a frame is finished */
{
unsigned int f_num;
struct w9968cf_frame_t* fr;
int err = 0;
if (copy_from_user(&f_num, arg, sizeof(f_num)))
return -EFAULT;
if (f_num >= cam->nbuffers) {
DBG(4, "Invalid frame number (%u). "
"VIDIOCMCAPTURE failed", f_num)
return -EINVAL;
}
DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
fr = &cam->frame[f_num];
switch (fr->status) {
case F_UNUSED:
if (!fr->queued) {
DBG(4, "VIDIOSYNC: Frame #%u not requested!",
f_num)
return -EFAULT;
}
case F_ERROR:
case F_GRABBING:
err = wait_event_interruptible(cam->wait_queue,
(fr->status == F_READY)
|| cam->disconnected);
if (err)
return err;
if (cam->disconnected)
return -ENODEV;
break;
case F_READY:
break;
}
if (w9968cf_vpp)
w9968cf_postprocess_frame(cam, fr);
fr->status = F_UNUSED;
DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
return 0;
}
case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
{
struct video_unit unit = {
.video = cam->v4ldev->minor,
.vbi = VIDEO_NO_UNIT,
.radio = VIDEO_NO_UNIT,
.audio = VIDEO_NO_UNIT,
.teletext = VIDEO_NO_UNIT,
};
if (copy_to_user(arg, &unit, sizeof(unit)))
return -EFAULT;
DBG(5, "VIDIOCGUNIT successfully called")
return 0;
}
case VIDIOCKEY:
return 0;
case VIDIOCGFBUF:
{
if (clear_user(arg, sizeof(struct video_buffer)))
return -EFAULT;
DBG(5, "VIDIOCGFBUF successfully called")
return 0;
}
case VIDIOCGTUNER:
{
struct video_tuner tuner;
if (copy_from_user(&tuner, arg, sizeof(tuner)))
return -EFAULT;
if (tuner.tuner != 0)
return -EINVAL;
strcpy(tuner.name, "no_tuner");
tuner.rangelow = 0;
tuner.rangehigh = 0;
tuner.flags = VIDEO_TUNER_NORM;
tuner.mode = VIDEO_MODE_AUTO;
tuner.signal = 0xffff;
if (copy_to_user(arg, &tuner, sizeof(tuner)))
return -EFAULT;
DBG(5, "VIDIOCGTUNER successfully called")
return 0;
}
case VIDIOCSTUNER:
{
struct video_tuner tuner;
if (copy_from_user(&tuner, arg, sizeof(tuner)))
return -EFAULT;
if (tuner.tuner != 0)
return -EINVAL;
if (tuner.mode != VIDEO_MODE_AUTO)
return -EINVAL;
DBG(5, "VIDIOCSTUNER successfully called")
return 0;
}
case VIDIOCSFBUF:
case VIDIOCCAPTURE:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOCSPLAYMODE:
case VIDIOCSWRITEMODE:
case VIDIOCGPLAYINFO:
case VIDIOCSMICROCODE:
case VIDIOCGVBIFMT:
case VIDIOCSVBIFMT:
DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
"(type 0x%01X, "
"n. 0x%01X, "
"dir. 0x%01X, "
"size 0x%02X)",
V4L1_IOCTL(cmd),
_IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
return -EINVAL;
default:
DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
"type 0x%01X, "
"n. 0x%01X, "
"dir. 0x%01X, "
"size 0x%02X",
V4L1_IOCTL(cmd),
_IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
return -ENOIOCTLCMD;
} /* end of switch */
ioctl_fail:
cam->misconfigured = 1;
DBG(1, "VIDIOC%s failed because of hardware problems. "
"To use the camera, close and open it again.", V4L1_IOCTL(cmd))
return -EFAULT;
}
Generated by GNU enscript 1.6.4.