Re: [PATCH] video: fbdev: add HP Visualize FX driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/31/21 21:49, Sven Schnelle wrote:
> This adds a framebuffer driver for HP's visualize series of
> cards. The aim is to support all FX2 - FX10 types but currently only
> FX5 is tested as i don't have any other card.
>
> Currently no mmap of video memory is supported as i haven't figured
> out how to access VRAM directly.
>
> Signed-off-by: Sven Schnelle <svens@xxxxxxxxxxxxxx>

That's really cool!



> ---
>  drivers/video/fbdev/Kconfig       |  14 +
>  drivers/video/fbdev/Makefile      |   2 +-
>  drivers/video/fbdev/visualizefx.c | 602 ++++++++++++++++++++++++++++++
>  3 files changed, 617 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/video/fbdev/visualizefx.c
>
> diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
> index 6ed5e608dd04..ee963f755047 100644
> --- a/drivers/video/fbdev/Kconfig
> +++ b/drivers/video/fbdev/Kconfig
> @@ -566,6 +566,20 @@ config FB_STI
>
>  	  It is safe to enable this option, so you should probably say "Y".
>
> +config FB_VISUALIZEFX
> +	tristate "HP Visualize FX support"
> +	depends on FB && PCI && PARISC
> +	select FB_CFB_FILLRECT
> +	select FB_CFB_COPYAREA
> +	select FB_CFB_IMAGEBLIT
> +	select RATIONAL

You should add "default y", so that it automatically gets enabled on parisc machines:

        default y

Other than that you may add an:

Acked-by: Helge Deller <deller@xxxxxx>

Thanks!
Helge


> +	  help
> +	    Frame buffer driver for the HP Visualize FX cards. These cards are
> +	    commonly found in PA-RISC workstations. Currently only FX5 has been
> +	    tested.
> +
> +	    Say Y if you have such a card.
> +
>  config FB_MAC
>  	bool "Generic Macintosh display support"
>  	depends on (FB = y) && MAC
> diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
> index 477b9624b703..3ef26907a3a4 100644
> --- a/drivers/video/fbdev/Makefile
> +++ b/drivers/video/fbdev/Makefile
> @@ -129,6 +129,6 @@ obj-$(CONFIG_FB_MX3)		  += mx3fb.o
>  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
>  obj-$(CONFIG_FB_SSD1307)	  += ssd1307fb.o
>  obj-$(CONFIG_FB_SIMPLE)           += simplefb.o
> -
> +obj-$(CONFIG_FB_VISUALIZEFX)	  += visualizefx.o
>  # the test framebuffer is last
>  obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
> diff --git a/drivers/video/fbdev/visualizefx.c b/drivers/video/fbdev/visualizefx.c
> new file mode 100644
> index 000000000000..9318e07be1aa
> --- /dev/null
> +++ b/drivers/video/fbdev/visualizefx.c
> @@ -0,0 +1,602 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Framebuffer driver for Visualize FX cards commonly found in PA-RISC machines
> + *
> + * Copyright (c) 2021 Sven Schnelle <svens@xxxxxxxxxxxxxx>
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/pci.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/rational.h>
> +
> +#define VISFX_VRAM_ENDIANESS_WRITE	0xa4303c
> +#define VISFX_VRAM_ENDIANESS_READ	0xaa0408
> +#define VISFX_VRAM_ENDIANESS_BIG	0xe4e4e4e4
> +#define VISFX_VRAM_ENDIANESS_LITTLE	0x1b1b1b1b
> +
> +#define VISFX_STATUS			0x641400
> +
> +#define VISFX_COLOR_MASK		0x800018
> +#define VISFX_COLOR_INDEX		0x800020
> +#define VISFX_COLOR_VALUE		0x800024
> +
> +#define VISFX_SYNC_POLARITY		0x800044
> +#define VISFX_SYNC_VISIBLE_SIZE		0x80005c
> +#define VISFX_SYNC_HORIZ_CONF		0x800060
> +#define VISFX_SYNC_VERT_CONF		0x800068
> +#define VISFX_SYNC_MASTER_PLL		0x8000a0
> +#define VISFX_SYNC_PLL_STATUS		0x8000b8
> +
> +#define VISFX_VRAM_WRITE_MODE		0xa00808
> +#define VISFX_VRAM_MASK			0xa0082c
> +#define VISFX_FGCOLOR			0xa0083c
> +#define VISFX_BGCOLOR			0xa00844
> +#define VISFX_WRITE_MASK		0xa0084c
> +#define VISFX_VRAM_WRITE_DATA_INCRX	0xa60000
> +#define VISFX_VRAM_WRITE_DATA_INCRY	0xa68000
> +#define VISFX_SCREEN_SIZE		0xac1054
> +#define VISFX_VRAM_WRITE_DEST		0xac1000
> +
> +#define VISFX_START			0xb3c000
> +#define VISFX_SIZE			0xb3c808
> +#define VISFX_HEIGHT			0xb3c008
> +#define VISFX_DST			0xb3cc00
> +
> +#define VISFX_DFP_ENABLE		0x10000
> +#define VISFX_HSYNC_POSITIVE		0x40000
> +#define VISFX_VSYNC_POSITIVE		0x80000
> +
> +#define VISFX_SYNC_PLL_BASE		49383 /* 20.25MHz in ps */
> +
> +#define VISFX_CURSOR_POS		0x400000
> +#define VISFX_CURSOR_INDEX		0x400004
> +#define VISFX_CURSOR_DATA		0x400008
> +#define VISFX_CURSOR_COLOR		0x400010
> +#define VISFX_CURSOR_ENABLE		0x80000000
> +
> +#define VISFX_VRAM_WRITE_MODE_BITMAP	0x02000000
> +#define VISFX_VRAM_WRITE_MODE_COLOR	0x050004c0
> +#define VISFX_VRAM_WRITE_MODE_FILL	0x05000080
> +
> +#define VISFX_FB_LENGTH			0x01000000
> +#define VISFX_FB_OFFSET			0x01000000
> +#define NR_PALETTE 256
> +
> +struct visfx_par {
> +	u32 pseudo_palette[256];
> +	unsigned long debug_reg;
> +	void __iomem *reg_base;
> +	unsigned long reg_size;
> +	int open_count;
> +};
> +
> +static u32 visfx_readl(struct fb_info *info, int reg)
> +{
> +	struct visfx_par *par = info->par;
> +
> +	return le32_to_cpu(readl(par->reg_base + reg));
> +}
> +
> +static void visfx_writel(struct fb_info *info, int reg, u32 val)
> +{
> +	struct visfx_par *par = info->par;
> +
> +	return writel(cpu_to_le32(val), par->reg_base + reg);
> +}
> +
> +static void visfx_write_vram(struct fb_info *info, int reg, u32 val)
> +{
> +	struct visfx_par *par = info->par;
> +
> +	return writel(val, par->reg_base + reg);
> +}
> +
> +static void visfx_bmove_wait(struct fb_info *info)
> +{
> +	while (visfx_readl(info, VISFX_STATUS));
> +}
> +
> +static ssize_t visfx_sysfs_show_reg(struct device *dev,
> +				    struct device_attribute *attr,
> +				    char *buf)
> +{
> +	struct fb_info *info = pci_get_drvdata(container_of(dev, struct pci_dev, dev));
> +	struct visfx_par *par = info->par;
> +
> +	return sprintf(buf, "%08x\n", visfx_readl(info, par->debug_reg));
> +}
> +
> +static ssize_t visfx_sysfs_store_reg(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct fb_info *info = pci_get_drvdata(container_of(dev, struct pci_dev, dev));
> +	struct visfx_par *par = info->par;
> +	unsigned long data;
> +	char *p;
> +
> +	p = strchr(buf, '=');
> +	if (p)
> +		*p = '\0';
> +
> +	if (kstrtoul(buf, 16, &par->debug_reg))
> +		return -EINVAL;
> +
> +	if (par->debug_reg > par->reg_size)
> +		return -EINVAL;
> +
> +	if (p) {
> +		if (kstrtoul(p+1, 16, &data))
> +			return -EINVAL;
> +		visfx_writel(info, par->debug_reg, data);
> +	}
> +	return count;
> +}
> +
> +static DEVICE_ATTR(reg, 0600, visfx_sysfs_show_reg, visfx_sysfs_store_reg);
> +
> +static void visfx_set_vram_addr(struct fb_info *info, int x, int y)
> +{
> +	visfx_writel(info, VISFX_VRAM_WRITE_DEST, (y << 16) | x);
> +}
> +
> +static void visfx_set_bmove_color(struct fb_info *info, int fg, int bg)
> +{
> +	visfx_writel(info, VISFX_BGCOLOR, 0x01010101 * bg);
> +	visfx_writel(info, VISFX_FGCOLOR, 0x01010101 * fg);
> +}
> +
> +static void visfx_imageblit_mono(struct fb_info *info, const char *data, int dx, int dy,
> +				 int width, int height, int fg_color, int bg_color)
> +{
> +	int _width, x, y;
> +	u32 tmp;
> +
> +	visfx_set_bmove_color(info, fg_color, bg_color);
> +	visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_COLOR);
> +	visfx_writel(info, VISFX_VRAM_MASK, 0xffffffff);
> +
> +	for (x = 0, _width = width; _width > 0; _width -= 32, x += 4) {
> +		visfx_set_vram_addr(info, dx + x * 8, dy);
> +		if (_width >= 32) {
> +			for (y = 0; y < height; y++) {
> +				memcpy(&tmp, &data[y * (width / 8) + x], 4);
> +				visfx_write_vram(info, VISFX_VRAM_WRITE_DATA_INCRY, tmp);
> +			}
> +		} else {
> +			visfx_writel(info, VISFX_VRAM_MASK, GENMASK(31, 31 - _width + 1));
> +			for (y = 0; y < height; y++) {
> +				tmp = 0;
> +				memcpy(&tmp, &data[y * (width / 8) + x], ((_width-1)/8)+1);
> +				visfx_write_vram(info, VISFX_VRAM_WRITE_DATA_INCRY, tmp);
> +			}
> +		}
> +	}
> +}
> +
> +static void visfx_setup_unknown(struct fb_info *info)
> +{
> +	visfx_writel(info, 0xb08044, 0x1b);
> +	visfx_writel(info, 0xb08048, 0x1b);
> +	visfx_writel(info, 0x920860, 0xe4);
> +	visfx_writel(info, 0xa00818, 0);
> +	visfx_writel(info, 0xa00404, 0);
> +	visfx_writel(info, 0x921110, 0);
> +	visfx_writel(info, 0x9211d8, 0);
> +	visfx_writel(info, 0xa0086c, 0);
> +	visfx_writel(info, 0x921114, 0);
> +	visfx_writel(info, 0xac1050, 0);
> +	visfx_writel(info, 0xa00858, 0xb0);
> +
> +	visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_BITMAP);
> +	visfx_writel(info, VISFX_WRITE_MASK, 0xffffffff);
> +	visfx_writel(info, VISFX_VRAM_MASK, 0xffffffff);
> +#ifdef __BIG_ENDIAN
> +	visfx_writel(info, VISFX_VRAM_ENDIANESS_READ, VISFX_VRAM_ENDIANESS_BIG);
> +	visfx_writel(info, VISFX_VRAM_ENDIANESS_WRITE, VISFX_VRAM_ENDIANESS_BIG);
> +#else
> +	visfx_writel(info, VISFX_VRAM_ENDIANESS_READ, VISFX_VRAM_ENDIANESS_LITTLE);
> +	visfx_writel(info, VISFX_VRAM_ENDIANESS_WRITE, VISFX_VRAM_ENDIANESS_LITTLE);
> +#endif
> +}
> +
> +static void visfx_imageblit(struct fb_info *info, const struct fb_image *image)
> +{
> +	int x, y;
> +
> +	visfx_bmove_wait(info);
> +	visfx_writel(info, VISFX_WRITE_MASK, 0xffffffff);
> +
> +	switch (image->depth) {
> +	case 1:
> +		visfx_imageblit_mono(info, image->data, image->dx, image->dy,
> +				     image->width, image->height,
> +				     image->fg_color, image->bg_color);
> +		break;
> +	case 8:
> +		visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_BITMAP);
> +
> +		for (y = 0; y < image->height; y++) {
> +			u32 data = 0;
> +			int pos = 0;
> +
> +			visfx_writel(info, VISFX_WRITE_MASK, 0xffffffff);
> +			visfx_set_vram_addr(info, image->dx, image->dy + y);
> +
> +			for (x = 0; x < image->width; x++) {
> +				pos = x & 3;
> +				data |= ((u8 *)image->data)[y * image->height + x] << (pos * 8);
> +				if (pos == 3) {
> +					visfx_write_vram(info, VISFX_VRAM_WRITE_DATA_INCRX, data);
> +					data = 0;
> +				}
> +			}
> +
> +			if (x && pos != 3) {
> +				visfx_write_vram(info, VISFX_WRITE_MASK, (1 << ((pos+1) * 8))-1);
> +				visfx_write_vram(info, VISFX_VRAM_WRITE_DATA_INCRX, data);
> +			}
> +		}
> +		break;
> +
> +	default:
> +		break;
> +	}
> +}
> +
> +static void visfx_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
> +{
> +	visfx_bmove_wait(info);
> +	visfx_writel(info, VISFX_WRITE_MASK, 0xffffffff);
> +	visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_FILL);
> +	visfx_set_bmove_color(info, fr->color, 0);
> +	visfx_writel(info, VISFX_START, (fr->dx << 16) | fr->dy);
> +	visfx_writel(info, VISFX_SIZE, (fr->width << 16) | fr->height);
> +}
> +
> +static u32 visfx_cmap_entry(struct fb_cmap *cmap, int color)
> +{
> +	return (((cmap->blue[color] & 0xff)) |
> +		((cmap->green[color] & 0xff) << 8) |
> +		(cmap->red[color] & 0xff) << 16);
> +}
> +
> +static int visfx_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> +{
> +	int i;
> +
> +	visfx_writel(info, VISFX_COLOR_INDEX, cmap->start);
> +
> +	for (i = 0; i < cmap->len; i++)
> +		visfx_writel(info, VISFX_COLOR_VALUE, visfx_cmap_entry(cmap, i));
> +
> +	visfx_writel(info, VISFX_COLOR_MASK, 0xff);
> +	visfx_writel(info, 0x80004c, 0xc);
> +	visfx_writel(info, 0x800000, 0);
> +	return 0;
> +}
> +
> +static void visfx_get_video_mode(struct fb_info *info)
> +{
> +	struct fb_var_screeninfo *var = &info->var;
> +	unsigned long n, d;
> +	u32 tmp;
> +
> +	tmp = visfx_readl(info, VISFX_SYNC_VISIBLE_SIZE);
> +	var->xres = (tmp & 0xffff) + 1;
> +	var->yres = (tmp >> 16) + 1;
> +
> +	tmp = visfx_readl(info, VISFX_SYNC_MASTER_PLL);
> +	n = (tmp & 0xff) + 1;
> +	d = ((tmp >> 8) & 0xff) + 1;
> +	var->pixclock = (VISFX_SYNC_PLL_BASE / d) * n;
> +
> +	tmp = visfx_readl(info, VISFX_SYNC_HORIZ_CONF);
> +	var->left_margin = ((tmp >> 20) & 0x1ff) + 1;
> +	var->hsync_len = (((tmp >> 12) & 0xff) + 1) * 4;
> +	var->right_margin = (tmp & 0x1ff) + 1;
> +
> +	tmp = visfx_readl(info, VISFX_SYNC_VERT_CONF);
> +	var->upper_margin = ((tmp >> 16) & 0xff) + 1;
> +	var->vsync_len = ((tmp >> 8) & 0xff) + 1;
> +	var->lower_margin = (tmp & 0xff) + 1;
> +
> +	tmp = visfx_readl(info, VISFX_SYNC_POLARITY);
> +	if (tmp & VISFX_HSYNC_POSITIVE)
> +		var->sync |= FB_SYNC_HOR_HIGH_ACT;
> +	if (tmp & VISFX_VSYNC_POSITIVE)
> +		var->sync |= FB_SYNC_VERT_HIGH_ACT;
> +
> +	var->red.length = 8;
> +	var->green.length = 8;
> +	var->blue.length = 8;
> +	var->bits_per_pixel = 8;
> +	var->grayscale = 0;
> +	var->xres_virtual = var->xres;
> +	var->yres_virtual = var->yres;
> +	info->screen_size = 2048 * var->yres;
> +}
> +
> +static void visfx_set_pll(struct fb_info *info, unsigned long clock)
> +{
> +	unsigned long n, d, tmp;
> +
> +	rational_best_approximation(clock, VISFX_SYNC_PLL_BASE, 0x3f, 0x3f, &n, &d);
> +	tmp = (((d * 4) - 1) << 8) | ((n * 4) - 1);
> +	visfx_writel(info, VISFX_SYNC_MASTER_PLL, 0x520000 | tmp);
> +	while (visfx_readl(info, VISFX_SYNC_PLL_STATUS) & 0xffffff)
> +		udelay(10);
> +	visfx_writel(info, VISFX_SYNC_MASTER_PLL, 0x530000 | tmp);
> +	while (visfx_readl(info, VISFX_SYNC_PLL_STATUS) & 0xffffff)
> +		udelay(10);
> +}
> +
> +static int visfx_set_par(struct fb_info *info)
> +{
> +	u32 xres, yres, hbp, hsw, hfp, vbp, vsw, vfp, tmp;
> +	struct fb_var_screeninfo *var = &info->var;
> +
> +
> +	xres = var->xres;
> +	yres = var->yres;
> +	hsw = var->hsync_len / 4 - 1;
> +	hfp = var->right_margin - 1;
> +	hbp = var->left_margin - 1;
> +	vsw = var->vsync_len - 1;
> +	vfp = var->lower_margin - 1;
> +	vbp = var->upper_margin - 1;
> +
> +	visfx_set_pll(info, var->pixclock);
> +	visfx_writel(info, VISFX_SYNC_VISIBLE_SIZE, ((yres - 1) << 16) | (xres - 1));
> +	visfx_writel(info, VISFX_SYNC_HORIZ_CONF, (hbp << 20) | (hsw << 12) | (0xc << 8) | hfp);
> +	visfx_writel(info, VISFX_SYNC_VERT_CONF, (vbp << 16) | (vsw << 8) | vfp);
> +	visfx_writel(info, VISFX_SCREEN_SIZE, (xres << 16) | yres);
> +
> +	tmp = VISFX_DFP_ENABLE;
> +	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> +		tmp |= VISFX_HSYNC_POSITIVE;
> +	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> +		tmp |= VISFX_VSYNC_POSITIVE;
> +	visfx_writel(info, VISFX_SYNC_POLARITY, tmp);
> +
> +	visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_BITMAP);
> +
> +	visfx_get_video_mode(info);
> +	return 0;
> +}
> +
> +static int visfx_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> +	if (var->pixclock > VISFX_SYNC_PLL_BASE ||
> +	    var->left_margin > 512 ||
> +	    var->right_margin > 512 ||
> +	    var->hsync_len > 512 ||
> +	    var->lower_margin > 256 ||
> +	    var->upper_margin > 256 ||
> +	    var->vsync_len > 256 ||
> +		var->xres > 2048 ||
> +		var->yres > 2048)
> +		return -EINVAL;
> +	return 0;
> +}
> +
> +static void visfx_update_cursor_image_line(struct fb_info *info,
> +					   struct fb_cursor *cursor, int y)
> +{
> +	unsigned int x, bytecnt;
> +	u32 data[2] = { 0 };
> +	u8 d, m;
> +
> +	bytecnt = cursor->image.width / 8;
> +
> +	for (x = 0; x < bytecnt && x < 8; x++) {
> +		m = cursor->mask[y * bytecnt + x];
> +		d = cursor->image.data[y * bytecnt + x];
> +
> +		if (cursor->rop == ROP_XOR)
> +			((u8 *)data)[x] = d ^ m;
> +		else
> +			((u8 *)data)[x] = d & m;
> +	}
> +
> +	visfx_writel(info, VISFX_CURSOR_DATA, data[0]);
> +	visfx_writel(info, VISFX_CURSOR_DATA, data[1]);
> +}
> +
> +static void visfx_update_cursor_image(struct fb_info *info,
> +				      struct fb_cursor *cursor)
> +{
> +	int y, height = cursor->image.height;
> +
> +	if (height > 128)
> +		height = 128;
> +
> +	visfx_writel(info, VISFX_CURSOR_INDEX, 0);
> +	for (y = 0; y < height; y++)
> +		visfx_update_cursor_image_line(info, cursor, y);
> +
> +	for (; y < 256; y++)
> +		visfx_writel(info, VISFX_CURSOR_DATA, 0);
> +}
> +
> +static int visfx_cursor(struct fb_info *info, struct fb_cursor *cursor)
> +{
> +	u32 tmp;
> +
> +	if (cursor->set & (FB_CUR_SETIMAGE|FB_CUR_SETSHAPE))
> +		visfx_update_cursor_image(info, cursor);
> +
> +	if (cursor->set & FB_CUR_SETCMAP) {
> +		tmp = visfx_cmap_entry(&info->cmap, cursor->image.fg_color);
> +		visfx_writel(info, VISFX_CURSOR_COLOR, tmp);
> +	}
> +
> +	tmp = (cursor->image.dx << 16) | (cursor->image.dy & 0xffff);
> +	if (cursor->enable)
> +		tmp |= VISFX_CURSOR_ENABLE;
> +	visfx_writel(info, VISFX_CURSOR_POS, tmp);
> +	return 0;
> +}
> +
> +static int visfx_open(struct fb_info *info, int user)
> +{
> +	struct visfx_par *par = info->par;
> +
> +	if (user && par->open_count++ == 0)
> +		visfx_writel(info, VISFX_VRAM_WRITE_MODE, VISFX_VRAM_WRITE_MODE_BITMAP);
> +
> +	return 0;
> +}
> +
> +static int visfx_release(struct fb_info *info, int user)
> +{
> +	struct visfx_par *par = info->par;
> +
> +	if (user)
> +		par->open_count--;
> +
> +	return 0;
> +}
> +
> +static const struct fb_ops visfx_ops = {
> +	.owner		= THIS_MODULE,
> +	.fb_open	= visfx_open,
> +	.fb_release	= visfx_release,
> +	.fb_setcmap	= visfx_setcmap,
> +	.fb_fillrect	= visfx_fillrect,
> +	.fb_imageblit	= visfx_imageblit,
> +	.fb_set_par	= visfx_set_par,
> +	.fb_check_var	= visfx_check_var,
> +	.fb_cursor	= visfx_cursor,
> +};
> +
> +static struct fb_fix_screeninfo visfx_fix = {
> +	.type = FB_TYPE_PACKED_PIXELS,
> +	.visual = FB_VISUAL_PSEUDOCOLOR,
> +	.id = "Visualize FX",
> +};
> +
> +static int visfx_probe(struct pci_dev *pdev,
> +		       const struct pci_device_id *ent)
> +{
> +	struct visfx_par *par;
> +	struct fb_info *info;
> +	int ret;
> +
> +	info = framebuffer_alloc(sizeof(struct visfx_par), &pdev->dev);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	par = info->par;
> +
> +	ret = pci_enable_device(pdev);
> +	if (ret)
> +		goto err_out_free;
> +
> +	ret = pci_request_regions(pdev, KBUILD_MODNAME);
> +	if (ret)
> +		goto err_out_disable;
> +
> +	par->reg_size = pci_resource_len(pdev, 0);
> +	par->reg_base = pci_ioremap_bar(pdev, 0);
> +	par->open_count = 0;
> +
> +	if (!par->reg_base) {
> +		ret = -ENOMEM;
> +		goto err_out_release;
> +	}
> +
> +	pci_set_drvdata(pdev, info);
> +
> +	info->fbops = &visfx_ops;
> +	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT;
> +	info->fix = visfx_fix;
> +	info->pseudo_palette = par->pseudo_palette;
> +	info->fix.smem_start = pci_resource_start(pdev, 0) + VISFX_FB_OFFSET;
> +	info->fix.smem_len = VISFX_FB_LENGTH;
> +	info->screen_base = par->reg_base + VISFX_FB_OFFSET;
> +	info->fix.type = FB_TYPE_PACKED_PIXELS;
> +	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
> +	info->fix.line_length = 2048;
> +	info->fix.accel = FB_ACCEL_NONE;
> +
> +	visfx_setup_unknown(info);
> +	visfx_get_video_mode(info);
> +	info->var.accel_flags = info->flags;
> +
> +	ret = device_create_file(&pdev->dev, &dev_attr_reg);
> +	if (ret)
> +		goto err_out_iounmap;
> +
> +	ret = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
> +	if (ret)
> +		goto err_out_remove;
> +
> +	ret = register_framebuffer(info);
> +	if (ret)
> +		goto err_out_dealloc_cmap;
> +	return 0;
> +
> +err_out_dealloc_cmap:
> +	fb_dealloc_cmap(&info->cmap);
> +err_out_remove:
> +	device_remove_file(&pdev->dev, &dev_attr_reg);
> +err_out_iounmap:
> +	pci_iounmap(pdev, par->reg_base);
> +err_out_release:
> +	pci_release_regions(pdev);
> +err_out_disable:
> +	pci_disable_device(pdev);
> +err_out_free:
> +	framebuffer_release(info);
> +	return ret;
> +}
> +
> +static void __exit visfx_remove(struct pci_dev *pdev)
> +{
> +	struct fb_info *info = pci_get_drvdata(pdev);
> +	struct visfx_par *par = info->par;
> +
> +	device_remove_file(&pdev->dev, &dev_attr_reg);
> +	unregister_framebuffer(info);
> +	pci_iounmap(pdev, par->reg_base);
> +	framebuffer_release(info);
> +	pci_release_regions(pdev);
> +	pci_disable_device(pdev);
> +}
> +
> +static const struct pci_device_id visfx_pci_tbl[] = {
> +	{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x1008) },
> +	{ 0 },
> +};
> +MODULE_DEVICE_TABLE(pci, visfx_pci_tbl);
> +
> +static struct pci_driver visfx_driver = {
> +	.name      = KBUILD_MODNAME,
> +	.id_table  = visfx_pci_tbl,
> +	.probe     = visfx_probe,
> +	.remove    = visfx_remove,
> +};
> +
> +static int __init visfx_init(void)
> +{
> +	return pci_register_driver(&visfx_driver);
> +}
> +module_init(visfx_init);
> +
> +static void __exit visfx_exit(void)
> +{
> +	pci_unregister_driver(&visfx_driver);
> +}
> +module_exit(visfx_exit);
> +
> +MODULE_AUTHOR("Sven Schnelle <svens@xxxxxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Framebuffer driver for HP Visualize FX cards");
> +MODULE_LICENSE("GPL");
>





[Index of Archives]     [Linux SoC]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux