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;
}