extractedLnx/linux-2.4.24/drivers/usb/w9968cf.c_w9968cf_do_ioctl.c
static int
w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
{
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))] : "???")
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_vppmod_present)
? W9968CF_MAX_WIDTH : cam->maxwidth;
cap.maxheight = (cam->upscaling && w9968cf_vppmod_present)
? W9968CF_MAX_HEIGHT : 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 */
{
struct video_picture pict;
if (w9968cf_sensor_get_picture(cam, &pict))
return -EIO;
pict.depth = cam->picture.depth;
pict.palette = cam->picture.palette;
if (copy_to_user(arg, &pict, sizeof(pict)))
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_vppmod_present)
&& 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 (pict.depth != w9968cf_valid_depth(pict.palette)) {
DBG(4, "Depth %d bpp is not supported for %s palette. "
"VIDIOCSPICT failed.",
pict.depth, 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.palette != cam->picture.palette ||
pict.depth != cam->picture.depth)
{
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 ( ((pict.brightness != cam->picture.brightness) &&
(!cam->auto_brt)) ||
pict.hue != cam->picture.hue ||
pict.colour != cam->picture.colour ||
pict.contrast != cam->picture.contrast ||
pict.whiteness != cam->picture.whiteness ) {
if (w9968cf_sensor_set_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=%d, "
"x=%d, y=%d, %dx%d", 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 (%dx%d)."
"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 * w9968cf_get_max_bufsize(cam);
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 #%d, 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 (%d). "
"VIDIOCMCAPTURE failed.", mmap.frame)
return -EINVAL;
}
if (mmap.format!=cam->picture.palette &&
(cam->force_palette || !w9968cf_vppmod_present)) {
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 (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 -EINVAL;
}
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 #%d: %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 #%d 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(%d): successfully called.", mmap.frame)
return 0;
}
case VIDIOCSYNC: /* wait until the capture of a frame is finished */
{
unsigned int f_num = *((unsigned int *) arg);
struct w9968cf_frame_t* fr;
int err = 0;
if (f_num >= cam->nbuffers) {
DBG(4, "Invalid frame number (%d). "
"VIDIOCMCAPTURE failed.", f_num)
return -EINVAL;
}
DBG(6, "VIDIOCSYNC called for frame #%d", f_num)
fr = &cam->frame[f_num];
switch (fr->status) {
case F_UNUSED:
if (!fr->queued) {
DBG(4, "VIDIOSYNC: Frame #%d 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_vppmod_present)
w9968cf_postprocess_frame(cam, fr);
fr->status = F_UNUSED;
DBG(5, "VIDIOCSYNC(%d) 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:
{
struct video_buffer* buffer = (struct video_buffer*)arg;
memset(buffer, 0, sizeof(struct video_buffer));
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.