extractedLnx/linux-2.5.5/drivers/usb/ov511.c_ov511_ioctl_internal.c
static int
ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
PDEBUG(5, "IOCtl: 0x%X", cmd);
if (!ov511->dev)
return -EIO;
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability b;
PDEBUG(4, "VIDIOCGCAP");
memset(&b, 0, sizeof(b));
sprintf(b.name, "%s USB Camera",
ov511->bridge == BRG_OV511 ? "OV511" :
ov511->bridge == BRG_OV511PLUS ? "OV511+" :
ov511->bridge == BRG_OV518 ? "OV518" :
ov511->bridge == BRG_OV518PLUS ? "OV518+" :
"unknown");
b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
if (ov511->has_tuner)
b.type |= VID_TYPE_TUNER;
b.channels = ov511->num_inputs;
b.audios = ov511->has_audio_proc ? 1:0;
b.maxwidth = ov511->maxwidth;
b.maxheight = ov511->maxheight;
b.minwidth = ov511->minwidth;
b.minheight = ov511->minheight;
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
return 0;
}
case VIDIOCGCHAN:
{
struct video_channel v;
PDEBUG(4, "VIDIOCGCHAN");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
if ((unsigned)(v.channel) >= ov511->num_inputs) {
err("Invalid channel (%d)", v.channel);
return -EINVAL;
}
v.norm = ov511->norm;
v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0;
v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
// v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0;
v.tuners = (ov511->has_tuner) ? 1:0;
decoder_get_input_name(ov511, v.channel, v.name);
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCSCHAN:
{
struct video_channel v;
int err;
PDEBUG(4, "VIDIOCSCHAN");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Make sure it's not a camera */
if (!ov511->has_decoder) {
if (v.channel == 0)
return 0;
else
return -EINVAL;
}
if (v.norm != VIDEO_MODE_PAL &&
v.norm != VIDEO_MODE_NTSC &&
v.norm != VIDEO_MODE_SECAM &&
v.norm != VIDEO_MODE_AUTO) {
err("Invalid norm (%d)", v.norm);
return -EINVAL;
}
if ((unsigned)(v.channel) >= ov511->num_inputs) {
err("Invalid channel (%d)", v.channel);
return -EINVAL;
}
err = decoder_set_input(ov511, v.channel);
if (err)
return err;
err = decoder_set_norm(ov511, v.norm);
if (err)
return err;
return 0;
}
case VIDIOCGPICT:
{
struct video_picture p;
PDEBUG(4, "VIDIOCGPICT");
memset(&p, 0, sizeof(p));
if (sensor_get_picture(ov511, &p))
return -EIO;
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
return 0;
}
case VIDIOCSPICT:
{
struct video_picture p;
int i;
PDEBUG(4, "VIDIOCSPICT");
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
if (!ov511_get_depth(p.palette))
return -EINVAL;
if (sensor_set_picture(ov511, &p))
return -EIO;
if (force_palette && p.palette != force_palette) {
info("Palette rejected (%d)", p.palette);
return -EINVAL;
}
// FIXME: Format should be independent of frames
if (p.palette != ov511->frame[0].format) {
PDEBUG(4, "Detected format change");
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov511->wq);
if (signal_pending(current)) return -EINTR;
mode_init_regs(ov511, ov511->frame[0].width,
ov511->frame[0].height, p.palette,
ov511->sub_flag);
}
PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov511->frame[i].depth = p.depth;
ov511->frame[i].format = p.palette;
}
return 0;
}
case VIDIOCGCAPTURE:
{
int vf;
PDEBUG(4, "VIDIOCGCAPTURE");
if (copy_from_user(&vf, arg, sizeof(vf)))
return -EFAULT;
ov511->sub_flag = vf;
return 0;
}
case VIDIOCSCAPTURE:
{
struct video_capture vc;
PDEBUG(4, "VIDIOCSCAPTURE");
if (copy_from_user(&vc, arg, sizeof(vc)))
return -EFAULT;
if (vc.flags)
return -EINVAL;
if (vc.decimation)
return -EINVAL;
vc.x &= ~3L;
vc.y &= ~1L;
vc.y &= ~31L;
if (vc.width == 0)
vc.width = 32;
vc.height /= 16;
vc.height *= 16;
if (vc.height == 0)
vc.height = 16;
ov511->subx = vc.x;
ov511->suby = vc.y;
ov511->subw = vc.width;
ov511->subh = vc.height;
return 0;
}
case VIDIOCSWIN:
{
struct video_window vw;
int i, result;
if (copy_from_user(&vw, arg, sizeof(vw)))
return -EFAULT;
PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
vw.width, vw.height);
#if 0
if (vw.flags)
return -EINVAL;
if (vw.clipcount)
return -EINVAL;
if (vw.height != ov511->maxheight)
return -EINVAL;
if (vw.width != ov511->maxwidth)
return -EINVAL;
#endif
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov511->wq);
if (signal_pending(current)) return -EINTR;
result = mode_init_regs(ov511, vw.width, vw.height,
ov511->frame[0].format, ov511->sub_flag);
if (result < 0)
return result;
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov511->frame[i].width = vw.width;
ov511->frame[i].height = vw.height;
}
return 0;
}
case VIDIOCGWIN:
{
struct video_window vw;
memset(&vw, 0, sizeof(vw));
vw.x = 0; /* FIXME */
vw.y = 0;
vw.width = ov511->frame[0].width;
vw.height = ov511->frame[0].height;
vw.flags = 30;
PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
if (copy_to_user(arg, &vw, sizeof(vw)))
return -EFAULT;
return 0;
}
case VIDIOCGMBUF:
{
struct video_mbuf vm;
int i;
PDEBUG(4, "VIDIOCGMBUF");
memset(&vm, 0, sizeof(vm));
vm.size = OV511_NUMFRAMES
* MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
vm.frames = OV511_NUMFRAMES;
vm.offsets[0] = 0;
for (i = 1; i < OV511_NUMFRAMES; i++) {
vm.offsets[i] = vm.offsets[i-1]
+ MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
}
if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
return 0;
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
int ret, depth;
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
PDEBUG(4, "CMCAPTURE");
PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
depth = ov511_get_depth(vm.format);
if (!depth) {
err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
return -EINVAL;
}
if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
return -EINVAL;
}
if (vm.width > ov511->maxwidth
|| vm.height > ov511->maxheight) {
err("VIDIOCMCAPTURE: requested dimensions too big");
return -EINVAL;
}
if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) {
PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
return -EBUSY;
}
if (force_palette && vm.format != force_palette) {
info("palette rejected (%d)", vm.format);
return -EINVAL;
}
if ((ov511->frame[vm.frame].width != vm.width) ||
(ov511->frame[vm.frame].height != vm.height) ||
(ov511->frame[vm.frame].format != vm.format) ||
(ov511->frame[vm.frame].sub_flag != ov511->sub_flag) ||
(ov511->frame[vm.frame].depth != depth)) {
PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov511->wq);
if (signal_pending(current)) return -EINTR;
ret = mode_init_regs(ov511, vm.width, vm.height,
vm.format, ov511->sub_flag);
#if 0
if (ret < 0) {
PDEBUG(1, "Got error while initializing regs ");
return ret;
}
#endif
ov511->frame[vm.frame].width = vm.width;
ov511->frame[vm.frame].height = vm.height;
ov511->frame[vm.frame].format = vm.format;
ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
ov511->frame[vm.frame].depth = depth;
}
/* Mark it as ready */
ov511->frame[vm.frame].grabstate = FRAME_READY;
PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);
return ov511_new_frame(ov511, vm.frame);
}
case VIDIOCSYNC:
{
int fnum, rc;
struct ov511_frame *frame;
if (copy_from_user((void *)&fnum, arg, sizeof(int)))
return -EFAULT;
if ((unsigned)fnum >= OV511_NUMFRAMES) {
err("VIDIOCSYNC: invalid frame (%d)", fnum);
return -EINVAL;
}
frame = &ov511->frame[fnum];
PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
frame->grabstate);
switch (frame->grabstate) {
case FRAME_UNUSED:
return -EINVAL;
case FRAME_READY:
case FRAME_GRABBING:
case FRAME_ERROR:
redo:
if (!ov511->dev)
return -EIO;
rc = wait_event_interruptible(frame->wq,
(frame->grabstate == FRAME_DONE)
|| (frame->grabstate == FRAME_ERROR));
if (rc)
return rc;
if (frame->grabstate == FRAME_ERROR) {
int ret;
if ((ret = ov511_new_frame(ov511, fnum)) < 0)
return ret;
goto redo;
}
/* Fall through */
case FRAME_DONE:
if (ov511->snap_enabled && !frame->snapshot) {
int ret;
if ((ret = ov511_new_frame(ov511, fnum)) < 0)
return ret;
goto redo;
}
frame->grabstate = FRAME_UNUSED;
/* Reset the hardware snapshot button */
/* FIXME - Is this the best place for this? */
if ((ov511->snap_enabled) && (frame->snapshot)) {
frame->snapshot = 0;
ov51x_clear_snapshot(ov511);
}
/* Decompression, format conversion, etc... */
ov511_postprocess(ov511, frame);
break;
} /* end switch */
return 0;
}
case VIDIOCGFBUF:
{
struct video_buffer vb;
PDEBUG(4, "VIDIOCSCHAN");
memset(&vb, 0, sizeof(vb));
vb.base = NULL; /* frame buffer not supported, not used */
if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
return -EFAULT;
return 0;
}
case VIDIOCGUNIT:
{
struct video_unit vu;
PDEBUG(4, "VIDIOCGUNIT");
memset(&vu, 0, sizeof(vu));
vu.video = ov511->vdev.minor; /* Video minor */
vu.vbi = VIDEO_NO_UNIT; /* VBI minor */
vu.radio = VIDEO_NO_UNIT; /* Radio minor */
vu.audio = VIDEO_NO_UNIT; /* Audio minor */
vu.teletext = VIDEO_NO_UNIT; /* Teletext minor */
if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
return -EFAULT;
return 0;
}
case VIDIOCGTUNER:
{
struct video_tuner v;
PDEBUG(4, "VIDIOCGTUNER");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
if (!ov511->has_tuner || v.tuner) // Only tuner 0
return -EINVAL;
strcpy(v.name, "Television");
// FIXME: Need a way to get the real values
v.rangelow = 0;
v.rangehigh = ~0;
v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC |
VIDEO_TUNER_SECAM;
v.mode = 0; /* FIXME: Not sure what this is yet */
v.signal = 0xFFFF; /* unknown */
call_i2c_clients(ov511, cmd, &v);
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCSTUNER:
{
struct video_tuner v;
int err;
PDEBUG(4, "VIDIOCSTUNER");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Only no or one tuner for now */
if (!ov511->has_tuner || v.tuner)
return -EINVAL;
/* and it only has certain valid modes */
if (v.mode != VIDEO_MODE_PAL &&
v.mode != VIDEO_MODE_NTSC &&
v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;
/* Is this right/necessary? */
err = decoder_set_norm(ov511, v.mode);
if (err)
return err;
call_i2c_clients(ov511, cmd, &v);
return 0;
}
case VIDIOCGFREQ:
{
unsigned long v = ov511->freq;
PDEBUG(4, "VIDIOCGFREQ");
if (!ov511->has_tuner)
return -EINVAL;
#if 0
/* FIXME: this is necessary for testing */
v = 46*16;
#endif
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCSFREQ:
{
unsigned long v;
if (!ov511->has_tuner)
return -EINVAL;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
PDEBUG(4, "VIDIOCSFREQ: %lx", v);
ov511->freq = v;
call_i2c_clients(ov511, cmd, &v);
return 0;
}
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
{
/* FIXME: Implement this... */
return 0;
}
default:
PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
return -ENOIOCTLCMD;
} /* end switch */
return 0;
}
Generated by GNU enscript 1.6.4.