* Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware.
*
- * Copyright (C) 2001-2005 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
*
* Based on:
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/pci.h>
#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include <asm/uaccess.h>
# define DEBUG_ON() debug_on=1
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
- __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \
+ __func__, reg, value, READ_BYTE(fb,reg)); \
gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
- __FUNCTION__, reg, value, READ_WORD(fb,reg)); \
+ __func__, reg, value, READ_WORD(fb,reg)); \
gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
static void
rattlerSetupPlanes(struct stifb_info *fb)
{
+ int saved_id, y;
+
+ /* Write RAMDAC pixel read mask register so all overlay
+ * planes are display-enabled. (CRX24 uses Bt462 pixel
+ * read mask register for overlay planes, not image planes).
+ */
CRX24_SETUP_RAMDAC(fb);
- /* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
- WRITE_WORD(0x83000300, fb, REG_14);
- SETUP_HW(fb);
- WRITE_BYTE(1, fb, REG_16b1);
+ /* change fb->id temporarily to fool SETUP_FB() */
+ saved_id = fb->id;
+ fb->id = CRX24_OVERLAY_PLANES;
+ SETUP_FB(fb);
+ fb->id = saved_id;
+
+ for (y = 0; y < fb->info.var.yres; ++y)
+ memset(fb->info.screen_base + y * fb->info.fix.line_length,
+ 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
- fb_memset(fb->info.fix.smem_start, 0xff,
- fb->info.var.yres*fb->info.fix.line_length);
-
CRX24_SET_OVLY_MASK(fb);
SETUP_FB(fb);
}
if (fb->info.var.bits_per_pixel == 32)
controlPlaneReg = 0x04000F00;
else
- controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
+ controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
else
- controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
+ controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
switch (enable) {
case ENABLE:
/* ------------------- driver specific functions --------------------------- */
-#define TMPBUFLEN 2048
-
-static ssize_t
-stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- char tmpbuf[TMPBUFLEN];
-
- if (!info || ! info->screen_base)
- return -ENODEV;
-
- if (p >= info->fix.smem_len)
- return 0;
- if (count >= info->fix.smem_len)
- count = info->fix.smem_len;
- if (count + p > info->fix.smem_len)
- count = info->fix.smem_len - p;
- if (count > sizeof(tmpbuf))
- count = sizeof(tmpbuf);
- if (count) {
- char *base_addr;
-
- base_addr = info->screen_base;
- memcpy_fromio(&tmpbuf, base_addr+p, count);
- count -= copy_to_user(buf, &tmpbuf, count);
- if (!count)
- return -EFAULT;
- *ppos += count;
- }
- return count;
-}
-
-static ssize_t
-stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
- unsigned long p = *ppos;
- size_t c;
- int err;
- char tmpbuf[TMPBUFLEN];
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
- if (p > info->fix.smem_len)
- return -ENOSPC;
- if (count >= info->fix.smem_len)
- count = info->fix.smem_len;
- err = 0;
- if (count + p > info->fix.smem_len) {
- count = info->fix.smem_len - p;
- err = -ENOSPC;
- }
-
- p += (unsigned long)info->screen_base;
- c = count;
- while (c) {
- int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
- err = -EFAULT;
- if (copy_from_user(&tmpbuf, buf, len))
- break;
- memcpy_toio(p, &tmpbuf, len);
- c -= len;
- p += len;
- buf += len;
- *ppos += len;
- }
- if (count-c)
- return (count-c);
- return err;
-}
-
static int
stifb_setcolreg(u_int regno, u_int red, u_int green,
u_int blue, u_int transp, struct fb_info *info)
static struct fb_ops stifb_ops = {
.owner = THIS_MODULE,
- .fb_read = stifb_read,
- .fb_write = stifb_write,
.fb_setcolreg = stifb_setcolreg,
.fb_blank = stifb_blank,
.fb_fillrect = cfb_fillrect,
* Initialization
*/
-int __init
-stifb_init_fb(struct sti_struct *sti, int bpp_pref)
+static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
{
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
char *dev_name;
int bpp, xres, yres;
- fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
+ fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
if (!fb) {
printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
return -ENODEV;
info = &fb->info;
/* set struct to a known state */
- memset(fb, 0, sizeof(*fb));
fix = &info->fix;
var = &info->var;
/* only supported cards are allowed */
switch (fb->id) {
case CRT_ID_VISUALIZE_EG:
- /* look for a double buffering device like e.g. the
- "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
- which won't work. The same device in non-double
- buffering mode returns "INTERNAL_EG_X1024". */
- if (strstr(sti->outptr.dev_name, "EG_DX")) {
- printk(KERN_WARNING
- "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
+ /* Visualize cards can run either in "double buffer" or
+ "standard" mode. Depending on the mode, the card reports
+ a different device name, e.g. "INTERNAL_EG_DX1024" in double
+ buffer mode and "INTERNAL_EG_X1024" in standard mode.
+ Since this driver only supports standard mode, we check
+ if the device name contains the string "DX" and tell the
+ user how to reconfigure the card. */
+ if (strstr(sti->outptr.dev_name, "DX")) {
+ printk(KERN_WARNING
+"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
+"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
sti->outptr.dev_name);
goto out_err0;
}
case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
/* FIXME: TomCat supports two heads:
* fb.iobase = REGION_BASE(fb_info,3);
- * fb.screen_base = (void*) REGION_BASE(fb_info,2);
+ * fb.screen_base = ioremap_nocache(REGION_BASE(fb_info,2),xxx);
* for now we only support the left one ! */
xres = fb->ngle_rom.x_size_visible;
yres = fb->ngle_rom.y_size_visible;
strcpy(fix->id, "stifb");
info->fbops = &stifb_ops;
- info->screen_base = (void*) REGION_BASE(fb,1);
+ info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
+ info->screen_size = fix->smem_len;
info->flags = FBINFO_DEFAULT;
info->pseudo_palette = &fb->pseudo_palette;
- /* This has to been done !!! */
- fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
+ /* This has to be done !!! */
+ if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
+ goto out_err1;
stifb_init_display(fb);
if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
fix->smem_start, fix->smem_start+fix->smem_len);
- goto out_err1;
+ goto out_err2;
}
if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
fix->mmio_start, fix->mmio_start+fix->mmio_len);
- goto out_err2;
+ goto out_err3;
}
if (register_framebuffer(&fb->info) < 0)
- goto out_err3;
+ goto out_err4;
sti->info = info; /* save for unregister_framebuffer() */
return 0;
-out_err3:
+out_err4:
release_mem_region(fix->mmio_start, fix->mmio_len);
-out_err2:
+out_err3:
release_mem_region(fix->smem_start, fix->smem_len);
-out_err1:
+out_err2:
fb_dealloc_cmap(&info->cmap);
+out_err1:
+ iounmap(info->screen_base);
out_err0:
kfree(fb);
return -ENXIO;
int __init
stifb_setup(char *options);
-int __init
-stifb_init(void)
+static int __init stifb_init(void)
{
struct sti_struct *sti;
struct sti_struct *def_sti;
unregister_framebuffer(sti->info);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ if (info->screen_base)
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
- kfree(info);
+ framebuffer_release(info);
}
sti->info = NULL;
}
int i;
if (!options || !*options)
- return 0;
+ return 1;
if (strncmp(options, "off", 3) == 0) {
stifb_disabled = 1;
stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
}
}
- return 0;
+ return 1;
}
__setup("stifb=", stifb_setup);