static int stmfbio_set_blitter_palette(struct stmfb_info* i, u_long arg) { DPRINTK("palette: copying to i->pBlitterCLUT = %p.\n",i->pBlitterCLUT); if (!i->pBlitter || !i->pBlitterCLUT) return -ENODEV; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; if(stm_display_blitter_sync(i->pBlitter)<0) { DPRINTK("palette: sync blitter failed\n"); up(&i->framebufferLock); return -EINTR; } if(copy_from_user(i->pBlitterCLUT,(void*)(arg+offsetof(STMFBIO_PALETTE,entries)),sizeof(unsigned long)*256)) { DPRINTK("failed to copy palette from user data.\n"); up(&i->framebufferLock); return -EFAULT; } DPRINTK("palette: [ 0x%lx, 0x%lx, 0x%lx, 0x%lx ]\n",i->pBlitterCLUT[0],i->pBlitterCLUT[1],i->pBlitterCLUT[2],i->pBlitterCLUT[3]); up(&i->framebufferLock); return 0; }
static int __exit stmfb_remove(struct platform_device *pdev) { struct stmfb_info *i = (struct stmfb_info *)platform_get_drvdata(pdev); struct stmcore_display_pipeline_data *pd = *((struct stmcore_display_pipeline_data **)pdev->dev.platform_data); DPRINTK("\n"); if(!i) return 0; if(i->pBlitter) stm_display_blitter_sync(i->pBlitter); stmfb_destroyfb(i); stmfb_cleanup_info(i); platform_set_drvdata(pdev,NULL); module_put(pd->owner); return 0; }
int stmfb_ioctl(struct fb_info* fb, u_int cmd, u_long arg) { struct stmfb_info* i = (struct stmfb_info* )fb; switch (cmd) { case STMFBIO_GET_OUTPUTSTANDARDS: { struct stmfbio_outputstandards standards, *user = (void *) arg; DPRINTK("STMFBIO_GET_OUTPUTSTANDARDS\n"); if (get_user(standards.outputid, &user->outputid)) return -EFAULT; if (standards.outputid != STMFBIO_OUTPUTID_MAIN) return -EINVAL; if (down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; stmfb_get_outputstandards(i, &standards); up(&i->framebufferLock); if (put_user (standards.all_standards, &user->all_standards)) return -EFAULT; return 0; } break; case STMFBIO_GET_OUTPUTINFO: { struct stmfbio_outputinfo info, *user = (void *) arg; int ret; DPRINTK("STMFBIO_GET_OUTPUTINFO\n"); if (get_user(info.outputid, &user->outputid)) return -EFAULT; if (info.outputid != STMFBIO_OUTPUTID_MAIN) return -EINVAL; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; if (!i->current_videomode_valid) { up(&i->framebufferLock); return -EAGAIN; } ret = stmfb_videomode_to_outputinfo(&i->current_videomode, &info); up(&i->framebufferLock); if (!ret && copy_to_user ((void *) arg, &info, sizeof (info))) return -EFAULT; return ret; } break; case STMFBIO_SET_OUTPUTINFO: { struct stmfbio_outputinfo info; struct stmfb_videomode vm; int ret; DPRINTK("STMFBIO_SET_OUTPUTINFO\n"); if (copy_from_user (&info, (void *) arg, sizeof (info))) return -EFAULT; if (info.outputid != STMFBIO_OUTPUTID_MAIN) return -EINVAL; if (down_interruptible (&i->framebufferLock)) return -ERESTARTSYS; /* prevent the framebuffer kernel API from messing around w/ the config in the future, until all apps have exited */ i->fbdev_api_suspended = 1; ret = stmfb_outputinfo_to_videomode (i, &info, &vm); up (&i->framebufferLock); if (!ret) { /* * Re-create the VAR from the exact hardware description, this gives a * completely clean var, which is why we have to save and restore the * activate flags. Without this we get spurious mode changes when they * should have been just tests. */ enum _stmfbio_activate activate = info.activate; ret = stmfb_videomode_to_outputinfo (&vm, &info); info.activate = activate; if (!ret && ((activate & STMFBIO_ACTIVATE_MASK) == STMFBIO_ACTIVATE_IMMEDIATE)) ret = stmfb_set_videomode (info.outputid, &vm, i); if (!ret && copy_to_user ((void *) arg, &info, sizeof (info))) return -EFAULT; } return ret; } break; case STMFBIO_GET_PLANEMODE: { struct stmfbio_planeinfo plane, *user = (void *) arg; DPRINTK("STMFBIO_GET_PLANEMODE\n"); if (get_user (plane.layerid, &user->layerid)) return -EFAULT; if (plane.layerid != 0) return -EINVAL; if (down_interruptible (&i->framebufferLock)) return -ERESTARTSYS; if (!i->current_planeconfig_valid) { up (&i->framebufferLock); return -EAGAIN; } plane.config = i->current_planeconfig; plane.activate = STMFBIO_ACTIVATE_IMMEDIATE; up (&i->framebufferLock); if (copy_to_user ((void *) arg, &plane, sizeof (plane))) return -EFAULT; return 0; } break; case STMFBIO_SET_PLANEMODE: { struct stmfbio_planeinfo plane; int ret; DPRINTK("STMFBIO_SET_PLANEMODE\n"); if (copy_from_user (&plane, (void *) arg, sizeof (plane))) return -EFAULT; if (plane.layerid != 0) return -EINVAL; plane.config.bitdepth = stmfb_bitdepth_for_pixelformat (plane.config.format); if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; ret = stmfb_verify_planeinfo (i, &plane); up(&i->framebufferLock); if (!ret && ((plane.activate & STMFBIO_ACTIVATE_MASK) == STMFBIO_ACTIVATE_IMMEDIATE)) ret = stmfb_set_planemode (&plane, i); return ret; } break; case STMFBIO_PAN_PLANE: { struct stmfbio_plane_pan pan; int ret; DPRINTK("STMFBIO_PAN_PLANE\n"); if (copy_from_user (&pan, (void *) arg, sizeof (pan))) return -EFAULT; if (pan.layerid != 0) return -EINVAL; if (down_interruptible (&i->framebufferLock)) return -ERESTARTSYS; /* prevent the framebuffer kernel API from messing around w/ the config in the future, until all apps have exited */ i->fbdev_api_suspended = 1; ret = stmfb_set_plane_pan (&pan, i); up (&i->framebufferLock); return ret; } break; case STMFBIO_GET_VAR_SCREENINFO_EX: { DPRINTK("STMFBIO_GET_VAR_SCREENINFO_EX\n"); if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; if(copy_to_user((void*)arg,&i->current_var_ex,sizeof(struct stmfbio_var_screeninfo_ex))) { up(&i->framebufferLock); return -EFAULT; } up(&i->framebufferLock); break; } case STMFBIO_SET_VAR_SCREENINFO_EX: { struct stmfbio_var_screeninfo_ex tmp; int ret; DPRINTK("STMFBIO_SET_VAR_SCREENINFO_EX\n"); if(copy_from_user(&tmp, (void*)arg, sizeof(tmp))) return -EFAULT; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; /* * If we don't have a valid videomode, change an immediate activation to * a deferred one; the settings will take effect when the next valid video * mode is set. */ if(!i->current_planeconfig_valid && tmp.activate == STMFBIO_ACTIVATE_IMMEDIATE) tmp.activate = STMFBIO_ACTIVATE_ON_NEXT_CHANGE; ret = stmfb_set_var_ex(&tmp, i); up(&i->framebufferLock); if(ret != 0) { /* * Copy back the var to set the failed entry */ if(copy_to_user((void*)arg,&tmp, sizeof(tmp))) return -EFAULT; return ret; } break; } case STMFBIO_GET_OUTPUT_CONFIG: { struct stmfbio_output_configuration tmp; int ret; DPRINTK("STMFBIO_GET_OUTPUT_CONFIG\n"); if(copy_from_user(&tmp, (void*)arg, sizeof(tmp))) return -EFAULT; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; ret = stmfb_get_output_configuration(&tmp,i); up(&i->framebufferLock); if(ret == 0) { if(copy_to_user((void*)arg,&tmp,sizeof(tmp))) ret = -EFAULT; } return ret; } case STMFBIO_SET_OUTPUT_CONFIG: { struct stmfbio_output_configuration tmp; int ret; DPRINTK("STMFBIO_SET_OUTPUT_CONFIG\n"); if(copy_from_user(&tmp, (void*)arg, sizeof(tmp))) return -EFAULT; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; ret = stmfb_set_output_configuration(&tmp, i); up(&i->framebufferLock); if(ret != 0) { /* * Copy back the var to set the failed entry */ copy_to_user((void*)arg,&tmp, sizeof(tmp)); return ret; } break; } case STMFBIO_SET_PICTURE_CONFIG: { struct stmfbio_picture_configuration tmp; int ret; DPRINTK("STMFBIO_SET_PICTURE_CONFIG\n"); if(copy_from_user(&tmp, (void*)arg, sizeof(tmp))) return -EFAULT; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; ret = stmfb_set_picture_configuration(&tmp, i); up(&i->framebufferLock); return ret; } case STMFBIO_GET_AUXMEMORY2: { struct stmfbio_auxmem2 auxmem; if (copy_from_user (&auxmem, (void *) arg, sizeof (auxmem))) return -EFAULT; if (auxmem.index >= ARRAY_SIZE (i->AuxBase)) return -EINVAL; auxmem.physical = i->AuxBase[auxmem.index]; auxmem.size = i->AuxSize[auxmem.index]; if (copy_to_user ((void *) arg, &auxmem, sizeof (auxmem))) return -EFAULT; break; } case STMFBIO_GET_SHARED_AREA: { struct stmfbio_shared shared; shared.physical = i->ulPSharedAreaBase; shared.size = i->ulSharedAreaSize; if (copy_to_user ((void *) arg, &shared, sizeof (shared))) return -EFAULT; break; } case STMFBIO_BLT: { int ret; if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; ret = stmfbio_blt(i, arg); up(&i->framebufferLock); if(ret<0) { if(signal_pending(current)) return -ERESTARTSYS; else return ret; } break; } case STMFBIO_SET_BLITTER_PALETTE: return stmfbio_set_blitter_palette(i, arg); case STMFBIO_SYNC_BLITTER: { int err; if (!i->pBlitter) return -ENODEV; if(down_interruptible(&i->framebufferLock)) { DPRINTK(" taking framebuffer lock interrupted\n"); return -ERESTARTSYS; } if((err = stm_display_blitter_sync(i->pBlitter)) != 0) { up(&i->framebufferLock); if(signal_pending(current)) { DPRINTK(" sync interrupted\n"); return -ERESTARTSYS; } else { DPRINTK(" sync error! code = %d\n",err); return -EIO; } } up(&i->framebufferLock); break; } case STMFBIO_WAIT_NEXT: { int err; if (!i->pBlitter) return -ENODEV; if(down_interruptible(&i->framebufferLock)) { DPRINTK(" taking framebuffer lock interrupted\n"); return -ERESTARTSYS; } if((err = stm_display_blitter_waitnext(i->pBlitter)) != 0) { up(&i->framebufferLock); if(signal_pending(current)) { DPRINTK(" wait_next interrupted\n"); return -ERESTARTSYS; } else { DPRINTK(" wait_next error! code = %d\n",err); return -EIO; } } up(&i->framebufferLock); break; } case STMFBIO_GET_BLTLOAD: { if (!i->pBlitter) return -ENODEV; return put_user (stm_display_blitter_get_bltload (i->pBlitter), (unsigned long *) arg); } case STMFBIO_PRE_AUTH: return stmfbio_pre_auth(i); case STMFBIO_POST_AUTH: return stmfbio_post_auth(i, arg); case STMFBIO_WAIT_FOR_REAUTH: return stmfbio_wait_for_reauth(i, arg); case STMFBIO_SET_DAC_HD_POWER: { if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; stm_display_output_set_control(i->pFBMainOutput, STM_CTRL_DAC_HD_POWER, arg); up(&i->framebufferLock); return 0; } case STMFBIO_SET_DAC_HD_FILTER: { if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; stm_display_output_set_control(i->pFBMainOutput, STM_CTRL_DAC_HD_FILTER, arg); up(&i->framebufferLock); return 0; } case STMFBIO_SET_CGMS_ANALOG: { if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; stm_display_output_set_control(i->pFBMainOutput, STM_CTRL_CGMS_ANALOG, arg); up(&i->framebufferLock); return 0; } case FBIO_WAITFORVSYNC: { struct stmcore_display_pipeline_data *pd = *((struct stmcore_display_pipeline_data **)i->platformDevice->dev.platform_data); DPRINTK("FBIO_WAITFORVSYNC\n"); if(down_interruptible(&i->framebufferLock)) return -ERESTARTSYS; if(!i->current_videomode_valid) { up(&i->framebufferLock); return -ENODEV; } up(&i->framebufferLock); interruptible_sleep_on(&pd->display_runtime->vsync_wait_queue); if(signal_pending(current)) return -ERESTARTSYS; break; } case FBIOGET_VBLANK: { struct stmcore_display_pipeline_data *pd = *((struct stmcore_display_pipeline_data **)i->platformDevice->dev.platform_data); struct fb_vblank vblank; vblank.flags = FB_VBLANK_HAVE_COUNT; vblank.count = atomic_read (&pd->display_runtime->vsync_count); if (copy_to_user ((void *) arg, &vblank, sizeof (vblank))) return -EFAULT; break; } default: { DPRINTK(" Invalid IOCTL code 0x%08x\n",cmd); return -ENOTTY; } } return 0; }
static int stmfb_suspend(struct platform_device *pdev, pm_message_t state) { struct stmfb_info *i = (struct stmfb_info *)platform_get_drvdata(pdev); DPRINTK("\n"); if(!i) return 0; if (state.event == pdev->dev.power.power_state.event) return 0; acquire_console_sem(); if(down_interruptible(&i->framebufferLock)) { release_console_sem(); return -EINTR; } if(i->pBlitter) { if(stm_display_blitter_sync(i->pBlitter)<0) { release_console_sem(); up(&i->framebufferLock); return -EINTR; } } /* * Suspend the main output first (there must be one!) which will stop the * timing generator, hence any more vsync interrupts. */ if(i->pFBMainOutput) stm_display_output_suspend(i->pFBMainOutput); if(i->pFBDVO) stm_display_output_suspend(i->pFBDVO); /* * HDMI is different, we need to stop it completely, which will force * the display state to NEEDS_RESTART. Once we resume the main output and * get a new VSYNC interrupt the ISR will spot this state change and signal * the HDMI thread which will look to see if the connected device has changed * (i.e. someone plugged in a different TV) while we were suspended and bring * the HDMI output back up again (if required at all) in the correct state. */ if(i->hdmi) stm_display_output_stop(i->hdmi->hdmi_output); /* * We release the framebuffer lock here as the fb_set_suspend callbacks * might call back into the driver. */ up(&i->framebufferLock); fb_set_suspend(&i->info, 1); release_console_sem(); DPRINTK("finished suspending\n"); return 0; }