static int matroxfb_ioctl()

in fbdev/matrox/matroxfb_base.c [874:1167]


static int matroxfb_ioctl(struct fb_info *info,
			  unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct matrox_fb_info *minfo = info2minfo(info);

	DBG(__func__)

	if (minfo->dead) {
		return -ENXIO;
	}

	switch (cmd) {
		case FBIOGET_VBLANK:
			{
				struct fb_vblank vblank;
				int err;

				err = matroxfb_get_vblank(minfo, &vblank);
				if (err)
					return err;
				if (copy_to_user(argp, &vblank, sizeof(vblank)))
					return -EFAULT;
				return 0;
			}
		case FBIO_WAITFORVSYNC:
			{
				u_int32_t crt;

				if (get_user(crt, (u_int32_t __user *)arg))
					return -EFAULT;

				return matroxfb_wait_for_sync(minfo, crt);
			}
		case MATROXFB_SET_OUTPUT_MODE:
			{
				struct matroxioc_output_mode mom;
				struct matrox_altout *oproc;
				int val;

				if (copy_from_user(&mom, argp, sizeof(mom)))
					return -EFAULT;
				if (mom.output >= MATROXFB_MAX_OUTPUTS)
					return -ENXIO;
				down_read(&minfo->altout.lock);
				oproc = minfo->outputs[mom.output].output;
				if (!oproc) {
					val = -ENXIO;
				} else if (!oproc->verifymode) {
					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
						val = 0;
					} else {
						val = -EINVAL;
					}
				} else {
					val = oproc->verifymode(minfo->outputs[mom.output].data, mom.mode);
				}
				if (!val) {
					if (minfo->outputs[mom.output].mode != mom.mode) {
						minfo->outputs[mom.output].mode = mom.mode;
						val = 1;
					}
				}
				up_read(&minfo->altout.lock);
				if (val != 1)
					return val;
				switch (minfo->outputs[mom.output].src) {
					case MATROXFB_SRC_CRTC1:
						matroxfb_set_par(info);
						break;
					case MATROXFB_SRC_CRTC2:
						{
							struct matroxfb_dh_fb_info* crtc2;

							down_read(&minfo->crtc2.lock);
							crtc2 = minfo->crtc2.info;
							if (crtc2)
								crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon);
							up_read(&minfo->crtc2.lock);
						}
						break;
				}
				return 0;
			}
		case MATROXFB_GET_OUTPUT_MODE:
			{
				struct matroxioc_output_mode mom;
				struct matrox_altout *oproc;
				int val;

				if (copy_from_user(&mom, argp, sizeof(mom)))
					return -EFAULT;
				if (mom.output >= MATROXFB_MAX_OUTPUTS)
					return -ENXIO;
				down_read(&minfo->altout.lock);
				oproc = minfo->outputs[mom.output].output;
				if (!oproc) {
					val = -ENXIO;
				} else {
					mom.mode = minfo->outputs[mom.output].mode;
					val = 0;
				}
				up_read(&minfo->altout.lock);
				if (val)
					return val;
				if (copy_to_user(argp, &mom, sizeof(mom)))
					return -EFAULT;
				return 0;
			}
		case MATROXFB_SET_OUTPUT_CONNECTION:
			{
				u_int32_t tmp;
				int i;
				int changes;

				if (copy_from_user(&tmp, argp, sizeof(tmp)))
					return -EFAULT;
				for (i = 0; i < 32; i++) {
					if (tmp & (1 << i)) {
						if (i >= MATROXFB_MAX_OUTPUTS)
							return -ENXIO;
						if (!minfo->outputs[i].output)
							return -ENXIO;
						switch (minfo->outputs[i].src) {
							case MATROXFB_SRC_NONE:
							case MATROXFB_SRC_CRTC1:
								break;
							default:
								return -EBUSY;
						}
					}
				}
				if (minfo->devflags.panellink) {
					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
							return -EINVAL;
						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
							if (minfo->outputs[i].src == MATROXFB_SRC_CRTC2) {
								return -EBUSY;
							}
						}
					}
				}
				changes = 0;
				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
					if (tmp & (1 << i)) {
						if (minfo->outputs[i].src != MATROXFB_SRC_CRTC1) {
							changes = 1;
							minfo->outputs[i].src = MATROXFB_SRC_CRTC1;
						}
					} else if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
						changes = 1;
						minfo->outputs[i].src = MATROXFB_SRC_NONE;
					}
				}
				if (!changes)
					return 0;
				matroxfb_set_par(info);
				return 0;
			}
		case MATROXFB_GET_OUTPUT_CONNECTION:
			{
				u_int32_t conn = 0;
				int i;

				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
					if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
						conn |= 1 << i;
					}
				}
				if (put_user(conn, (u_int32_t __user *)arg))
					return -EFAULT;
				return 0;
			}
		case MATROXFB_GET_AVAILABLE_OUTPUTS:
			{
				u_int32_t conn = 0;
				int i;

				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
					if (minfo->outputs[i].output) {
						switch (minfo->outputs[i].src) {
							case MATROXFB_SRC_NONE:
							case MATROXFB_SRC_CRTC1:
								conn |= 1 << i;
								break;
						}
					}
				}
				if (minfo->devflags.panellink) {
					if (conn & MATROXFB_OUTPUT_CONN_DFP)
						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
				}
				if (put_user(conn, (u_int32_t __user *)arg))
					return -EFAULT;
				return 0;
			}
		case MATROXFB_GET_ALL_OUTPUTS:
			{
				u_int32_t conn = 0;
				int i;

				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
					if (minfo->outputs[i].output) {
						conn |= 1 << i;
					}
				}
				if (put_user(conn, (u_int32_t __user *)arg))
					return -EFAULT;
				return 0;
			}
		case VIDIOC_QUERYCAP:
			{
				struct v4l2_capability r;

				memset(&r, 0, sizeof(r));
				strcpy(r.driver, "matroxfb");
				strcpy(r.card, "Matrox");
				sprintf(r.bus_info, "PCI:%s", pci_name(minfo->pcidev));
				r.version = KERNEL_VERSION(1,0,0);
				r.capabilities = V4L2_CAP_VIDEO_OUTPUT;
				if (copy_to_user(argp, &r, sizeof(r)))
					return -EFAULT;
				return 0;

			}
		case VIDIOC_QUERYCTRL:
			{
				struct v4l2_queryctrl qctrl;
				int err;

				if (copy_from_user(&qctrl, argp, sizeof(qctrl)))
					return -EFAULT;

				down_read(&minfo->altout.lock);
				if (!minfo->outputs[1].output) {
					err = -ENXIO;
				} else if (minfo->outputs[1].output->getqueryctrl) {
					err = minfo->outputs[1].output->getqueryctrl(minfo->outputs[1].data, &qctrl);
				} else {
					err = -EINVAL;
				}
				up_read(&minfo->altout.lock);
				if (err >= 0 &&
				    copy_to_user(argp, &qctrl, sizeof(qctrl)))
					return -EFAULT;
				return err;
			}
		case VIDIOC_G_CTRL:
			{
				struct v4l2_control ctrl;
				int err;

				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
					return -EFAULT;

				down_read(&minfo->altout.lock);
				if (!minfo->outputs[1].output) {
					err = -ENXIO;
				} else if (minfo->outputs[1].output->getctrl) {
					err = minfo->outputs[1].output->getctrl(minfo->outputs[1].data, &ctrl);
				} else {
					err = -EINVAL;
				}
				up_read(&minfo->altout.lock);
				if (err >= 0 &&
				    copy_to_user(argp, &ctrl, sizeof(ctrl)))
					return -EFAULT;
				return err;
			}
		case VIDIOC_S_CTRL:
			{
				struct v4l2_control ctrl;
				int err;

				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
					return -EFAULT;

				down_read(&minfo->altout.lock);
				if (!minfo->outputs[1].output) {
					err = -ENXIO;
				} else if (minfo->outputs[1].output->setctrl) {
					err = minfo->outputs[1].output->setctrl(minfo->outputs[1].data, &ctrl);
				} else {
					err = -EINVAL;
				}
				up_read(&minfo->altout.lock);
				return err;
			}
	}
	return -ENOTTY;
}