📄 matroxfb_crtc2.c
字号:
DAC1064_global_init(PMINFO2); DAC1064_global_restore(PMINFO2); down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 && ACCESS_FBINFO(outputs[out]).output->program) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data); } } for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 && ACCESS_FBINFO(outputs[out]).output->start) { ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data); } } up_read(&ACCESS_FBINFO(altout).lock); matroxfb_dh_cfbX_init(m2info); } m2info->initialized = 1; return 0;#undef m2info}static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, struct fb_info* info) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) matroxfb_dh_pan_var(m2info, var); return 0;#undef m2info}static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) { MINFO_FROM(m2info->primary_dev); matroxfb_enable_irq(PMINFO 0); memset(vblank, 0, sizeof(*vblank)); vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK; /* mask out reserved bits + field number (odd/even) */ vblank->vcount = mga_inl(0x3C48) & 0x000007FF; /* compatibility stuff */ if (vblank->vcount >= m2info->fbcon.var.yres) vblank->flags |= FB_VBLANK_VBLANKING; if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { vblank->flags |= FB_VBLANK_HAVE_COUNT; /* Only one writer, aligned int value... it should work without lock and without atomic_t */ vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt; } return 0;}static int matroxfb_dh_ioctl(struct inode* inode, struct file* file, unsigned int cmd, unsigned long arg, struct fb_info* info) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); DBG(__FUNCTION__) switch (cmd) { case FBIOGET_VBLANK: { struct fb_vblank vblank; int err; err = matroxfb_dh_get_vblank(m2info, &vblank); if (err) return err; if (copy_to_user((void __user *)arg, &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; if (crt != 0) return -ENODEV; return matroxfb_wait_for_sync(PMINFO 1); } case MATROXFB_SET_OUTPUT_MODE: case MATROXFB_GET_OUTPUT_MODE: case MATROXFB_GET_ALL_OUTPUTS: { return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon)); } case MATROXFB_SET_OUTPUT_CONNECTION: { u_int32_t tmp; int out; int changes; if (get_user(tmp, (u_int32_t __user *)arg)) return -EFAULT; for (out = 0; out < 32; out++) { if (tmp & (1 << out)) { if (out >= MATROXFB_MAX_OUTPUTS) return -ENXIO; if (!ACCESS_FBINFO(outputs[out]).output) return -ENXIO; switch (ACCESS_FBINFO(outputs[out]).src) { case MATROXFB_SRC_NONE: case MATROXFB_SRC_CRTC2: break; default: return -EBUSY; } } } if (ACCESS_FBINFO(devflags.panellink)) { if (tmp & MATROXFB_OUTPUT_CONN_DFP) return -EINVAL; if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp) return -EBUSY; } changes = 0; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (tmp & (1 << out)) { if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) { changes = 1; ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2; } } else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { changes = 1; ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE; } } if (!changes) return 0; matroxfb_dh_set_par(info); return 0; } case MATROXFB_GET_OUTPUT_CONNECTION: { u_int32_t conn = 0; int out; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { conn |= 1 << out; } } if (put_user(conn, (u_int32_t __user *)arg)) return -EFAULT; return 0; } case MATROXFB_GET_AVAILABLE_OUTPUTS: { u_int32_t tmp = 0; int out; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).output) { switch (ACCESS_FBINFO(outputs[out]).src) { case MATROXFB_SRC_NONE: case MATROXFB_SRC_CRTC2: tmp |= 1 << out; break; } } } if (ACCESS_FBINFO(devflags.panellink)) { tmp &= ~MATROXFB_OUTPUT_CONN_DFP; if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) { tmp = 0; } } if (put_user(tmp, (u_int32_t __user *)arg)) return -EFAULT; return 0; } } return -ENOTTY;#undef m2info}static int matroxfb_dh_blank(int blank, struct fb_info* info) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) switch (blank) { case 1: case 2: case 3: case 4: default:; } /* do something... */ return 0;#undef m2info}static struct fb_ops matroxfb_dh_ops = { .owner = THIS_MODULE, .fb_open = matroxfb_dh_open, .fb_release = matroxfb_dh_release, .fb_check_var = matroxfb_dh_check_var, .fb_set_par = matroxfb_dh_set_par, .fb_setcolreg = matroxfb_dh_setcolreg, .fb_pan_display =matroxfb_dh_pan_display, .fb_blank = matroxfb_dh_blank, .fb_ioctl = matroxfb_dh_ioctl, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit,};static struct fb_var_screeninfo matroxfb_dh_defined = { 640,480,640,480,/* W,H, virtual W,H */ 0,0, /* offset */ 32, /* depth */ 0, /* gray */ {0,0,0}, /* R */ {0,0,0}, /* G */ {0,0,0}, /* B */ {0,0,0}, /* alpha */ 0, /* nonstd */ FB_ACTIVATE_NOW, -1,-1, /* display size */ 0, /* accel flags */ 39721L,48L,16L,33L,10L, 96L,2,0, /* no sync info */ FB_VMODE_NONINTERLACED, 0, {0,0,0,0,0}};static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {#define minfo (m2info->primary_dev) void* oldcrtc2; m2info->fbcon.fbops = &matroxfb_dh_ops; m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; m2info->fbcon.flags |= FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; m2info->fbcon.pseudo_palette = m2info->cmap; fb_alloc_cmap(&m2info->fbcon.cmap, 256, 1); if (mem < 64) mem *= 1024; if (mem < 64*1024) mem *= 1024; mem &= ~0x00000FFF; /* PAGE_MASK? */ if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len)) m2info->video.offbase = ACCESS_FBINFO(video.len) - mem; else if (ACCESS_FBINFO(video.len) < mem) { return -ENOMEM; } else { /* check yres on first head... */ m2info->video.borrowed = mem; ACCESS_FBINFO(video.len_usable) -= mem; m2info->video.offbase = ACCESS_FBINFO(video.len_usable); } m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase; m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem; m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase; m2info->mmio.base = ACCESS_FBINFO(mmio.base); m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase); m2info->mmio.len = ACCESS_FBINFO(mmio.len); matroxfb_dh_init_fix(m2info); if (register_framebuffer(&m2info->fbcon)) { return -ENXIO; } if (!m2info->initialized) fb_set_var(&m2info->fbcon, &matroxfb_dh_defined); down_write(&ACCESS_FBINFO(crtc2.lock)); oldcrtc2 = ACCESS_FBINFO(crtc2.info); ACCESS_FBINFO(crtc2.info) = m2info; up_write(&ACCESS_FBINFO(crtc2.lock)); if (oldcrtc2) { printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n", oldcrtc2); } return 0;#undef minfo}/* ************************** */static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {#define minfo (m2info->primary_dev) if (matroxfb_dh_regit(PMINFO m2info)) { printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n"); return -1; } printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n", ACCESS_FBINFO(fbcon.node), m2info->fbcon.node); m2info->fbcon_registered = 1; return 0;#undef minfo}static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {#define minfo (m2info->primary_dev) if (m2info->fbcon_registered) { int id; struct matroxfb_dh_fb_info* crtc2; down_write(&ACCESS_FBINFO(crtc2.lock)); crtc2 = ACCESS_FBINFO(crtc2.info); if (crtc2 == m2info) ACCESS_FBINFO(crtc2.info) = NULL; up_write(&ACCESS_FBINFO(crtc2.lock)); if (crtc2 != m2info) { printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n", crtc2, m2info); printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n"); return; } id = m2info->fbcon.node; unregister_framebuffer(&m2info->fbcon); /* return memory back to primary head */ ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed; printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id); m2info->fbcon_registered = 0; }#undef minfo}static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) { struct matroxfb_dh_fb_info* m2info; /* hardware is CRTC2 incapable... */ if (!ACCESS_FBINFO(devflags.crtc2)) return NULL; m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL); if (!m2info) { printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n"); return NULL; } memset(m2info, 0, sizeof(*m2info)); m2info->primary_dev = MINFO; if (matroxfb_dh_registerfb(m2info)) { kfree(m2info); printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n"); return NULL; } return m2info;}static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) { matroxfb_dh_deregisterfb(crtc2); kfree(crtc2);}static struct matroxfb_driver crtc2 = { .name = "Matrox G400 CRTC2", .probe = matroxfb_crtc2_probe, .remove = matroxfb_crtc2_remove };static int matroxfb_crtc2_init(void) { if (fb_get_options("matrox_crtc2fb", NULL)) return -ENODEV; matroxfb_register_driver(&crtc2); return 0;}static void matroxfb_crtc2_exit(void) { matroxfb_unregister_driver(&crtc2);}MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");MODULE_LICENSE("GPL");module_init(matroxfb_crtc2_init);module_exit(matroxfb_crtc2_exit);/* we do not have __setup() yet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -