📄 cyber2000fb.c
字号:
fb_get_fix: gen_get_fix, fb_get_var: gen_get_var, fb_get_cmap: gen_get_cmap,};/* * Enable access to the extended registers */static void cyber2000fb_enable_extregs(struct cfb_info *cfb){ cfb->func_use_count += 1; if (cfb->func_use_count == 1) { int old; old = cyber2000_grphr(FUNC_CTL); cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL); }}/* * Disable access to the extended registers */static void cyber2000fb_disable_extregs(struct cfb_info *cfb){ if (cfb->func_use_count == 1) { int old; old = cyber2000_grphr(FUNC_CTL); cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL); } cfb->func_use_count -= 1;}/* * This is the only "static" reference to the internal data structures * of this driver. It is here solely at the moment to support the other * CyberPro modules external to this driver. */static struct cfb_info *int_cfb_info;/* * Attach a capture/tv driver to the core CyberX0X0 driver. */int cyber2000fb_attach(struct cyberpro_info *info, int idx){ if (int_cfb_info != NULL) { info->dev = int_cfb_info->dev; info->regs = CyberRegs; info->fb = int_cfb_info->fb.screen_base; info->fb_size = int_cfb_info->fb.fix.smem_len; info->enable_extregs = cyber2000fb_enable_extregs; info->disable_extregs = cyber2000fb_disable_extregs; info->info = int_cfb_info; strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name)); MOD_INC_USE_COUNT; } return int_cfb_info != NULL;}/* * Detach a capture/tv driver from the core CyberX0X0 driver. */void cyber2000fb_detach(int idx){ MOD_DEC_USE_COUNT;}EXPORT_SYMBOL(cyber2000fb_attach);EXPORT_SYMBOL(cyber2000fb_detach);/* * These parameters give * 640x480, hsync 31.5kHz, vsync 60Hz */static struct fb_videomode __devinitdata cyber2000fb_default_mode = { refresh: 60, xres: 640, yres: 480, pixclock: 39722, left_margin: 56, right_margin: 16, upper_margin: 34, lower_margin: 9, hsync_len: 88, vsync_len: 2, sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, vmode: FB_VMODE_NONINTERLACED};static char igs_regs[] __devinitdata = { 0x12, 0x00, 0x13, 0x00, 0x16, 0x00, 0x31, 0x00, 0x32, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x70, 0x0b, 0x73, 0x30, 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8};/* * We need to wake up the CyberPro, and make sure its in linear memory * mode. Unfortunately, this is specific to the platform and card that * we are running on. * * On x86 and ARM, should we be initialising the CyberPro first via the * IO registers, and then the MMIO registers to catch all cases? Can we * end up in the situation where the chip is in MMIO mode, but not awake * on an x86 system? * * Note that on the NetWinder, the firmware automatically detects the * type, width and size, and leaves this in extended registers 0x71 and * 0x72 for us. */static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot){ int i; /* * Wake up the CyberPro. */#ifdef __sparc__#ifdef __sparc_v9__#error "You loose, consult DaveM."#else /* * SPARC does not have an "outb" instruction, so we generate * I/O cycles storing into a reserved memory space at * physical address 0x3000000 */ { unsigned char *iop; iop = ioremap(0x3000000, 0x5000); if (iop == NULL) { prom_printf("iga5000: cannot map I/O\n"); return -ENOMEM; } writeb(0x18, iop + 0x46e8); writeb(0x01, iop + 0x102); writeb(0x08, iop + 0x46e8); writeb(0x33, iop + 0x3ce); writeb(0x01, iop + 0x3cf); iounmap((void *)iop); }#endif if (at_boot) { /* * Use mclk from BIOS. Only read this if we're * initialising this card for the first time. * FIXME: what about hotplug? */ cfb->mclk_mult = cyber2000_grphr(MCLK_MULT); cfb->mclk_div = cyber2000_grphr(MCLK_DIV); }#endif#ifdef __i386__ /* * x86 is simple, we just do regular outb's instead of * cyber2000_outb. */ outb(0x18, 0x46e8); outb(0x01, 0x102); outb(0x08, 0x46e8); outb(0x33, 0x3ce); outb(0x01, 0x3cf); if (at_boot) { /* * Use mclk from BIOS. Only read this if we're * initialising this card for the first time. * FIXME: what about hotplug? */ cfb->mclk_mult = cyber2000_grphr(MCLK_MULT); cfb->mclk_div = cyber2000_grphr(MCLK_DIV); }#endif#ifdef __arm__ cyber2000_outb(0x18, 0x46e8); cyber2000_outb(0x01, 0x102); cyber2000_outb(0x08, 0x46e8); cyber2000_outb(0x33, 0x3ce); cyber2000_outb(0x01, 0x3cf); /* * MCLK on the NetWinder is fixed at 75MHz */ cfb->mclk_mult = 0xdb; cfb->mclk_div = 0x54;#endif /* * Initialise the CyberPro */ for (i = 0; i < sizeof(igs_regs); i += 2) cyber2000_grphw(igs_regs[i], igs_regs[i+1]); if (at_boot) { /* * get the video RAM size and width from the VGA register. * This should have been already initialised by the BIOS, * but if it's garbage, claim default 1MB VRAM (woody) */ cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1); cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2); } else { /* * Reprogram the MEM_CTL1 and MEM_CTL2 registers */ cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1); cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2); } /* * Ensure thatwe are using the correct PLL. * (CyberPro 5000's may be programmed to use * an additional set of PLLs. */ cyber2000_outb(0xba, 0x3ce); cyber2000_outb(cyber2000_inb(0x3cf) & 0x80, 0x3cf);}static struct cfb_info * __devinitcyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id){ struct cfb_info *cfb; cfb = kmalloc(sizeof(struct cfb_info) + sizeof(struct display) + sizeof(u32) * 16, GFP_KERNEL); if (!cfb) return NULL; memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display)); cfb->currcon = -1; cfb->dev = dev; cfb->ref_ps = 69842; cfb->divisors[0] = 1; cfb->divisors[1] = 2; cfb->divisors[2] = 4; if (id->driver_data == FB_ACCEL_IGS_CYBER2010) cfb->divisors[3] = 6; else cfb->divisors[3] = 8; sprintf(cfb->fb.fix.id, "CyberPro%4X", id->device); cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; cfb->fb.fix.type_aux = 0; cfb->fb.fix.xpanstep = 0; cfb->fb.fix.ypanstep = 1; cfb->fb.fix.ywrapstep = 0; cfb->fb.fix.accel = id->driver_data; cfb->fb.var.nonstd = 0; cfb->fb.var.activate = FB_ACTIVATE_NOW; cfb->fb.var.height = -1; cfb->fb.var.width = -1; cfb->fb.var.accel_flags = FB_ACCELF_TEXT; strcpy(cfb->fb.modename, cfb->fb.fix.id); strcpy(cfb->fb.fontname, "Acorn8x8"); cfb->fb.fbops = &cyber2000fb_ops; cfb->fb.changevar = NULL; cfb->fb.switch_con = cyber2000fb_switch; cfb->fb.updatevar = cyber2000fb_updatevar; cfb->fb.blank = cyber2000fb_blank; cfb->fb.flags = FBINFO_FLAG_DEFAULT; cfb->fb.disp = (struct display *)(cfb + 1); cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1); fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); return cfb;}static void __devinitcyberpro_free_fb_info(struct cfb_info *cfb){ if (cfb) { /* * Free the colourmap */ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); kfree(cfb); }}/* * Map in the registers */static int __devinitcyberpro_map_mmio(struct cfb_info *cfb, struct pci_dev *dev){ u_long mmio_base; mmio_base = pci_resource_start(dev, 0) + MMIO_OFFSET; cfb->fb.fix.mmio_start = mmio_base + PCI_PHYS_OFFSET; cfb->fb.fix.mmio_len = MMIO_SIZE; if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) { printk("%s: memory mapped IO in use\n", cfb->fb.fix.id); return -EBUSY; } CyberRegs = ioremap(mmio_base, MMIO_SIZE); if (!CyberRegs) { printk("%s: unable to map memory mapped IO\n", cfb->fb.fix.id); return -ENOMEM; } return 0;}/* * Unmap registers */static void __devinit cyberpro_unmap_mmio(struct cfb_info *cfb){ if (cfb && CyberRegs) { iounmap(CyberRegs); CyberRegs = NULL; release_mem_region(cfb->fb.fix.mmio_start - PCI_PHYS_OFFSET, cfb->fb.fix.mmio_len); }}/* * Map in screen memory */static int __devinitcyberpro_map_smem(struct cfb_info *cfb, struct pci_dev *dev, u_long smem_len){ u_long smem_base; smem_base = pci_resource_start(dev, 0); cfb->fb.fix.smem_start = smem_base + PCI_PHYS_OFFSET; cfb->fb.fix.smem_len = smem_len; if (!request_mem_region(smem_base, smem_len, "frame buffer")) { printk("%s: frame buffer in use\n", cfb->fb.fix.id); return -EBUSY; } cfb->fb.screen_base = ioremap(smem_base, smem_len); if (!cfb->fb.screen_base) { printk("%s: unable to map screen memory\n", cfb->fb.fix.id); return -ENOMEM; } return 0;}static void __devinit cyberpro_unmap_smem(struct cfb_info *cfb){ if (cfb && cfb->fb.screen_base) { iounmap(cfb->fb.screen_base); cfb->fb.screen_base = NULL; release_mem_region(cfb->fb.fix.smem_start - PCI_PHYS_OFFSET, cfb->fb.fix.smem_len); }}static int __devinitcyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id){ struct cfb_info *cfb; u_int h_sync, v_sync; u_long smem_size; int err; err = pci_enable_device(dev); if (err) return err; err = -ENOMEM; cfb = cyberpro_alloc_fb_info(dev, id); if (!cfb) goto failed; err = cyberpro_map_mmio(cfb, dev); if (err) goto failed; cyberpro_init_hw(cfb, 1); switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break; case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break; default: smem_size = 0x00100000; break; } err = cyberpro_map_smem(cfb, dev, smem_size); if (err) goto failed; if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, &cyber2000fb_default_mode, 8)) { printk("%s: no valid mode found\n", cfb->fb.fix.id); goto failed; } cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 / (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual); if (cfb->fb.var.yres_virtual < cfb->fb.var.yres) cfb->fb.var.yres_virtual = cfb->fb.var.yres; cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb); /* * Calculate the hsync and vsync frequencies. Note that * we split the 1e12 constant up so that we can preserve * the precision and fit the results into 32-bit registers. * (1953125000 * 512 = 1e12) */ h_sync = 1953125000 / cfb->fb.var.pixclock; h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin + cfb->fb.var.right_margin + cfb->fb.var.hsync_len); v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin + cfb->fb.var.lower_margin + cfb->fb.var.vsync_len); printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10, cfb->fb.var.xres, cfb->fb.var.yres, h_sync / 1000, h_sync % 1000, v_sync); err = register_framebuffer(&cfb->fb); if (err < 0) goto failed; /* * Our driver data */ dev->driver_data = cfb; if (int_cfb_info == NULL) int_cfb_info = cfb; return 0;failed: cyberpro_unmap_smem(cfb); cyberpro_unmap_mmio(cfb); cyberpro_free_fb_info(cfb); return err;}static void __devexit cyberpro_remove(struct pci_dev *dev){ struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; if (cfb) { /* * If unregister_framebuffer fails, then * we will be leaving hooks that could cause * oopsen laying around. */ if (unregister_framebuffer(&cfb->fb)) printk(KERN_WARNING "%s: danger Will Robinson, " "danger danger! Oopsen imminent!\n", cfb->fb.fix.id); cyberpro_unmap_smem(cfb); cyberpro_unmap_mmio(cfb); cyberpro_free_fb_info(cfb); /* * Ensure that the driver data is no longer * valid. */ dev->driver_data = NULL; if (cfb == int_cfb_info) int_cfb_info = NULL; }}static void cyberpro_suspend(struct pci_dev *dev){}/* * Re-initialise the CyberPro hardware */static void cyberpro_resume(struct pci_dev *dev){ struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; if (cfb) { cyberpro_init_hw(cfb, 0); /* * Restore the old video mode and the palette. * We also need to tell fbcon to redraw the console. */ cfb->fb.var.activate = FB_ACTIVATE_NOW; cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb); }}static struct pci_device_id cyberpro_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 }, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 }, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 }, { 0, }};MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);static struct pci_driver cyberpro_driver = { name: "CyberPro", probe: cyberpro_probe, remove: cyberpro_remove, suspend: cyberpro_suspend, resume: cyberpro_resume, id_table: cyberpro_pci_table};/* * I don't think we can use the "module_init" stuff here because * the fbcon stuff may not be initialised yet. Hence the #ifdef * around module_init. */int __init cyber2000fb_init(void){ return pci_module_init(&cyberpro_driver);}static void __exit cyberpro_exit(void){ pci_unregister_driver(&cyberpro_driver);}#ifdef MODULEmodule_init(cyber2000fb_init);#endifmodule_exit(cyberpro_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -