mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
[PATCH] i810fb: Add i2c/DDC support
Add ddc/i2c support for i810fb. This will allow the driver to get display information, especially for monitors with fickle timings. The i2c support depends on CONFIG_FB_I810_GTF. Changed __init* to __devinit* Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Alexander Nyberg <alexn@telia.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
829e79b680
commit
74f6ae84b2
@ -751,6 +751,12 @@ config FB_I810_GTF
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config FB_I810_I2C
|
||||
bool "Enable DDC Support"
|
||||
depends on FB_I810 && I2C && FB_I810_GTF
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
|
||||
config FB_INTEL
|
||||
tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
|
||||
depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
obj-$(CONFIG_FB_I810) += i810fb.o
|
||||
|
||||
|
||||
i810fb-objs := i810_main.o i810_accel.o
|
||||
|
||||
ifdef CONFIG_FB_I810_GTF
|
||||
@ -12,3 +11,7 @@ i810fb-objs += i810_gtf.o
|
||||
else
|
||||
i810fb-objs += i810_dvt.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FB_I810_I2C
|
||||
i810fb-objs += i810-i2c.o
|
||||
endif
|
||||
|
257
drivers/video/i810/i810-i2c.c
Normal file
257
drivers/video/i810/i810-i2c.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*-*- linux-c -*-
|
||||
* linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support
|
||||
*
|
||||
* Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/fb.h>
|
||||
#include "i810.h"
|
||||
#include "i810_regs.h"
|
||||
#include "../edid.h"
|
||||
|
||||
#define I810_DDC 0x50
|
||||
/* bit locations in the registers */
|
||||
#define SCL_DIR_MASK 0x0001
|
||||
#define SCL_DIR 0x0002
|
||||
#define SCL_VAL_MASK 0x0004
|
||||
#define SCL_VAL_OUT 0x0008
|
||||
#define SCL_VAL_IN 0x0010
|
||||
#define SDA_DIR_MASK 0x0100
|
||||
#define SDA_DIR 0x0200
|
||||
#define SDA_VAL_MASK 0x0400
|
||||
#define SDA_VAL_OUT 0x0800
|
||||
#define SDA_VAL_IN 0x1000
|
||||
|
||||
#define DEBUG /* define this for verbose EDID parsing output */
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTK(fmt, args...) printk(fmt,## args)
|
||||
#else
|
||||
#define DPRINTK(fmt, args...)
|
||||
#endif
|
||||
|
||||
static void i810i2c_setscl(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
|
||||
SCL_DIR_MASK | SCL_VAL_MASK);
|
||||
i810_readl(mmio, GPIOB); /* flush posted write */
|
||||
}
|
||||
|
||||
static void i810i2c_setsda(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
|
||||
SDA_DIR_MASK | SDA_VAL_MASK);
|
||||
i810_readl(mmio, GPIOB); /* flush posted write */
|
||||
}
|
||||
|
||||
static int i810i2c_getscl(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, SCL_DIR_MASK);
|
||||
i810_writel(mmio, GPIOB, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOB) & SCL_VAL_IN));
|
||||
}
|
||||
|
||||
static int i810i2c_getsda(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOB, SDA_DIR_MASK);
|
||||
i810_writel(mmio, GPIOB, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOB) & SDA_VAL_IN));
|
||||
}
|
||||
|
||||
static void i810ddc_setscl(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
|
||||
SCL_DIR_MASK | SCL_VAL_MASK);
|
||||
i810_readl(mmio, GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static void i810ddc_setsda(void *data, int state)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
|
||||
SDA_DIR_MASK | SDA_VAL_MASK);
|
||||
i810_readl(mmio, GPIOA); /* flush posted write */
|
||||
}
|
||||
|
||||
static int i810ddc_getscl(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, SCL_DIR_MASK);
|
||||
i810_writel(mmio, GPIOA, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOA) & SCL_VAL_IN));
|
||||
}
|
||||
|
||||
static int i810ddc_getsda(void *data)
|
||||
{
|
||||
struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data;
|
||||
struct i810fb_par *par = chan->par;
|
||||
u8 *mmio = par->mmio_start_virtual;
|
||||
|
||||
i810_writel(mmio, GPIOA, SDA_DIR_MASK);
|
||||
i810_writel(mmio, GPIOA, 0);
|
||||
return (0 != (i810_readl(mmio, GPIOA) & SDA_VAL_IN));
|
||||
}
|
||||
|
||||
#define I2C_ALGO_DDC_I810 0x0e0000
|
||||
#define I2C_ALGO_I2C_I810 0x0f0000
|
||||
static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name,
|
||||
int conn)
|
||||
{
|
||||
int rc;
|
||||
|
||||
strcpy(chan->adapter.name, name);
|
||||
chan->adapter.owner = THIS_MODULE;
|
||||
chan->adapter.algo_data = &chan->algo;
|
||||
chan->adapter.dev.parent = &chan->par->dev->dev;
|
||||
switch (conn) {
|
||||
case 1:
|
||||
chan->adapter.id = I2C_ALGO_DDC_I810;
|
||||
chan->algo.setsda = i810ddc_setsda;
|
||||
chan->algo.setscl = i810ddc_setscl;
|
||||
chan->algo.getsda = i810ddc_getsda;
|
||||
chan->algo.getscl = i810ddc_getscl;
|
||||
break;
|
||||
case 2:
|
||||
chan->adapter.id = I2C_ALGO_I2C_I810;
|
||||
chan->algo.setsda = i810i2c_setsda;
|
||||
chan->algo.setscl = i810i2c_setscl;
|
||||
chan->algo.getsda = i810i2c_getsda;
|
||||
chan->algo.getscl = i810i2c_getscl;
|
||||
break;
|
||||
}
|
||||
chan->algo.udelay = 10;
|
||||
chan->algo.mdelay = 10;
|
||||
chan->algo.timeout = (HZ/2);
|
||||
chan->algo.data = chan;
|
||||
|
||||
i2c_set_adapdata(&chan->adapter, chan);
|
||||
|
||||
/* Raise SCL and SDA */
|
||||
chan->algo.setsda(chan, 1);
|
||||
chan->algo.setscl(chan, 1);
|
||||
udelay(20);
|
||||
|
||||
rc = i2c_bit_add_bus(&chan->adapter);
|
||||
if (rc == 0)
|
||||
dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
|
||||
else
|
||||
dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
|
||||
"%s.\n", name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void i810_create_i2c_busses(struct i810fb_par *par)
|
||||
{
|
||||
par->chan[0].par = par;
|
||||
par->chan[1].par = par;
|
||||
i810_setup_i2c_bus(&par->chan[0], "I810-DDC", 1);
|
||||
i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 2);
|
||||
}
|
||||
|
||||
void i810_delete_i2c_busses(struct i810fb_par *par)
|
||||
{
|
||||
if (par->chan[0].par)
|
||||
i2c_bit_del_bus(&par->chan[0].adapter);
|
||||
par->chan[0].par = NULL;
|
||||
if (par->chan[1].par)
|
||||
i2c_bit_del_bus(&par->chan[1].adapter);
|
||||
par->chan[1].par = NULL;
|
||||
}
|
||||
|
||||
static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan)
|
||||
{
|
||||
u8 start = 0x0;
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = I810_DDC,
|
||||
.len = 1,
|
||||
.buf = &start,
|
||||
}, {
|
||||
.addr = I810_DDC,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EDID_LENGTH,
|
||||
},
|
||||
};
|
||||
u8 *buf;
|
||||
|
||||
buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
DPRINTK("i810-i2c: Failed to allocate memory\n");
|
||||
return NULL;
|
||||
}
|
||||
msgs[1].buf = buf;
|
||||
|
||||
if (i2c_transfer(&chan->adapter, msgs, 2) == 2) {
|
||||
DPRINTK("i810-i2c: I2C Transfer successful\n");
|
||||
return buf;
|
||||
}
|
||||
DPRINTK("i810-i2c: Unable to read EDID block.\n");
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
|
||||
{
|
||||
struct i810fb_par *par = info->par;
|
||||
u8 *edid = NULL;
|
||||
int i;
|
||||
|
||||
DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn);
|
||||
if (conn < 3) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Do the real work */
|
||||
edid = i810_do_probe_i2c_edid(&par->chan[conn-1]);
|
||||
if (edid)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DPRINTK("i810-i2c: Getting EDID from BIOS\n");
|
||||
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (edid)
|
||||
memcpy(edid, fb_firmware_edid(info->device),
|
||||
EDID_LENGTH);
|
||||
}
|
||||
|
||||
if (out_edid)
|
||||
*out_edid = edid;
|
||||
|
||||
return (edid) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/agp_backend.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <video/vga.h>
|
||||
|
||||
/* Fence */
|
||||
@ -240,6 +243,14 @@ struct state_registers {
|
||||
u8 cr39, cr41, cr70, sr01, msr;
|
||||
};
|
||||
|
||||
struct i810fb_par;
|
||||
|
||||
struct i810fb_i2c_chan {
|
||||
struct i810fb_par *par;
|
||||
struct i2c_adapter adapter;
|
||||
struct i2c_algo_bit_data algo;
|
||||
};
|
||||
|
||||
struct i810fb_par {
|
||||
struct mode_registers regs;
|
||||
struct state_registers hw_state;
|
||||
@ -251,10 +262,12 @@ struct i810fb_par {
|
||||
struct heap_data iring;
|
||||
struct heap_data cursor_heap;
|
||||
struct vgastate state;
|
||||
struct i810fb_i2c_chan chan[2];
|
||||
atomic_t use_count;
|
||||
u32 pseudo_palette[17];
|
||||
unsigned long mmio_start_phys;
|
||||
u8 __iomem *mmio_start_virtual;
|
||||
u8 *edid;
|
||||
u32 pitch;
|
||||
u32 pixconf;
|
||||
u32 watermark;
|
||||
|
@ -92,20 +92,21 @@ static struct pci_driver i810fb_driver = {
|
||||
.resume = i810fb_resume,
|
||||
};
|
||||
|
||||
static int vram __initdata = 4;
|
||||
static int bpp __initdata = 8;
|
||||
static int mtrr __initdata = 0;
|
||||
static int accel __initdata = 0;
|
||||
static int hsync1 __initdata = 0;
|
||||
static int hsync2 __initdata = 0;
|
||||
static int vsync1 __initdata = 0;
|
||||
static int vsync2 __initdata = 0;
|
||||
static int xres __initdata = 640;
|
||||
static int yres __initdata = 480;
|
||||
static int vyres __initdata = 0;
|
||||
static int sync __initdata = 0;
|
||||
static int ext_vga __initdata = 0;
|
||||
static int dcolor __initdata = 0;
|
||||
static char *mode_option __devinitdata = NULL;
|
||||
static int vram __devinitdata = 4;
|
||||
static int bpp __devinitdata = 8;
|
||||
static int mtrr __devinitdata = 0;
|
||||
static int accel __devinitdata = 0;
|
||||
static int hsync1 __devinitdata = 0;
|
||||
static int hsync2 __devinitdata = 0;
|
||||
static int vsync1 __devinitdata = 0;
|
||||
static int vsync2 __devinitdata = 0;
|
||||
static int xres __devinitdata = 640;
|
||||
static int yres __devinitdata = 480;
|
||||
static int vyres __devinitdata = 0;
|
||||
static int sync __devinitdata = 0;
|
||||
static int ext_vga __devinitdata = 0;
|
||||
static int dcolor __devinitdata = 0;
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
@ -947,31 +948,24 @@ static int i810_check_params(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
struct i810fb_par *par = (struct i810fb_par *) info->par;
|
||||
int line_length, vidmem;
|
||||
u32 xres, yres, vxres, vyres;
|
||||
|
||||
xres = var->xres;
|
||||
yres = var->yres;
|
||||
vxres = var->xres_virtual;
|
||||
vyres = var->yres_virtual;
|
||||
|
||||
int line_length, vidmem, mode_valid = 0;
|
||||
u32 vyres = var->yres_virtual, vxres = var->xres_virtual;
|
||||
/*
|
||||
* Memory limit
|
||||
*/
|
||||
line_length = get_line_length(par, vxres,
|
||||
var->bits_per_pixel);
|
||||
|
||||
line_length = get_line_length(par, vxres, var->bits_per_pixel);
|
||||
vidmem = line_length*vyres;
|
||||
|
||||
if (vidmem > par->fb.size) {
|
||||
vyres = par->fb.size/line_length;
|
||||
if (vyres < yres) {
|
||||
if (vyres < var->yres) {
|
||||
vyres = yres;
|
||||
vxres = par->fb.size/vyres;
|
||||
vxres /= var->bits_per_pixel >> 3;
|
||||
line_length = get_line_length(par, vxres,
|
||||
var->bits_per_pixel);
|
||||
vidmem = line_length * yres;
|
||||
if (vxres < xres) {
|
||||
if (vxres < var->xres) {
|
||||
printk("i810fb: required video memory, "
|
||||
"%d bytes, for %dx%d-%d (virtual) "
|
||||
"is out of range\n",
|
||||
@ -981,6 +975,10 @@ static int i810_check_params(struct fb_var_screeninfo *var,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var->xres_virtual = vxres;
|
||||
var->yres_virtual = vyres;
|
||||
|
||||
/*
|
||||
* Monitor limit
|
||||
*/
|
||||
@ -996,25 +994,39 @@ static int i810_check_params(struct fb_var_screeninfo *var,
|
||||
info->monspecs.dclkmax = 204000000;
|
||||
break;
|
||||
}
|
||||
|
||||
info->monspecs.dclkmin = 15000000;
|
||||
|
||||
if (fb_validate_mode(var, info)) {
|
||||
if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
|
||||
int default_sync = (info->monspecs.hfmin-HFMIN)
|
||||
|(info->monspecs.hfmax-HFMAX)
|
||||
|(info->monspecs.vfmin-VFMIN)
|
||||
|(info->monspecs.vfmax-VFMAX);
|
||||
printk("i810fb: invalid video mode%s\n",
|
||||
default_sync ? "" :
|
||||
". Specifying vsyncN/hsyncN parameters may help");
|
||||
return -EINVAL;
|
||||
if (!fb_validate_mode(var, info))
|
||||
mode_valid = 1;
|
||||
|
||||
#ifdef CONFIG_FB_I810_I2C
|
||||
if (!mode_valid && info->monspecs.gtf &&
|
||||
!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
|
||||
mode_valid = 1;
|
||||
|
||||
if (!mode_valid && info->monspecs.modedb_len) {
|
||||
struct fb_videomode *mode;
|
||||
|
||||
mode = fb_find_best_mode(var, &info->modelist);
|
||||
if (mode) {
|
||||
fb_videomode_to_var(var, mode);
|
||||
mode_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var->xres = xres;
|
||||
var->yres = yres;
|
||||
var->xres_virtual = vxres;
|
||||
var->yres_virtual = vyres;
|
||||
#endif
|
||||
if (!mode_valid && info->monspecs.modedb_len == 0) {
|
||||
if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
|
||||
int default_sync = (info->monspecs.hfmin-HFMIN)
|
||||
|(info->monspecs.hfmax-HFMAX)
|
||||
|(info->monspecs.vfmin-VFMIN)
|
||||
|(info->monspecs.vfmax-VFMAX);
|
||||
printk("i810fb: invalid video mode%s\n",
|
||||
default_sync ? "" : ". Specifying "
|
||||
"vsyncN/hsyncN parameters may help");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1812,8 +1824,72 @@ i810_allocate_pci_resource(struct i810fb_par *par,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit i810fb_find_init_mode(struct fb_info *info)
|
||||
{
|
||||
struct fb_videomode mode;
|
||||
struct fb_var_screeninfo var;
|
||||
struct fb_monspecs *specs = NULL;
|
||||
int found = 0;
|
||||
#ifdef CONFIG_FB_I810_I2C
|
||||
int i;
|
||||
int err;
|
||||
struct i810fb_par *par = info->par;
|
||||
#endif
|
||||
|
||||
INIT_LIST_HEAD(&info->modelist);
|
||||
memset(&mode, 0, sizeof(struct fb_videomode));
|
||||
var = info->var;
|
||||
#ifdef CONFIG_FB_I810_I2C
|
||||
i810_create_i2c_busses(par);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = i810_probe_i2c_connector(info, &par->edid, i+1);
|
||||
if (!err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
printk("i810fb_init_pci: DDC probe successful\n");
|
||||
|
||||
fb_edid_to_monspecs(par->edid, &info->monspecs);
|
||||
|
||||
if (info->monspecs.modedb == NULL)
|
||||
printk("i810fb_init_pci: Unable to get Mode Database\n");
|
||||
|
||||
specs = &info->monspecs;
|
||||
fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
|
||||
&info->modelist);
|
||||
if (specs->modedb != NULL) {
|
||||
if (specs->misc & FB_MISC_1ST_DETAIL) {
|
||||
for (i = 0; i < specs->modedb_len; i++) {
|
||||
if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
|
||||
mode = specs->modedb[i];
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
mode = specs->modedb[0];
|
||||
found = 1;
|
||||
}
|
||||
|
||||
fb_videomode_to_var(&var, &mode);
|
||||
}
|
||||
#endif
|
||||
if (mode_option)
|
||||
fb_find_mode(&var, info, mode_option, specs->modedb,
|
||||
specs->modedb_len, (found) ? &mode : NULL,
|
||||
info->var.bits_per_pixel);
|
||||
|
||||
info->var = var;
|
||||
fb_destroy_modedb(specs->modedb);
|
||||
specs->modedb = NULL;
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
static int __init i810fb_setup(char *options)
|
||||
static int __devinit i810fb_setup(char *options)
|
||||
{
|
||||
char *this_opt, *suffix = NULL;
|
||||
|
||||
@ -1855,6 +1931,8 @@ static int __init i810fb_setup(char *options)
|
||||
vsync2 = simple_strtoul(this_opt+7, NULL, 0);
|
||||
else if (!strncmp(this_opt, "dcolor", 6))
|
||||
dcolor = 1;
|
||||
else
|
||||
mode_option = this_opt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1865,6 +1943,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
|
||||
{
|
||||
struct fb_info *info;
|
||||
struct i810fb_par *par = NULL;
|
||||
struct fb_videomode mode;
|
||||
int i, err = -1, vfreq, hfreq, pixclock;
|
||||
|
||||
i = 0;
|
||||
@ -1873,7 +1952,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
par = (struct i810fb_par *) info->par;
|
||||
par = info->par;
|
||||
par->dev = dev;
|
||||
|
||||
if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) {
|
||||
@ -1904,15 +1983,20 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
|
||||
info->fbops = &par->i810fb_ops;
|
||||
info->pseudo_palette = par->pseudo_palette;
|
||||
fb_alloc_cmap(&info->cmap, 256, 0);
|
||||
i810fb_find_init_mode(info);
|
||||
|
||||
if ((err = info->fbops->fb_check_var(&info->var, info))) {
|
||||
i810fb_release_resource(info, par);
|
||||
return err;
|
||||
}
|
||||
|
||||
fb_var_to_videomode(&mode, &info->var);
|
||||
fb_add_videomode(&mode, &info->modelist);
|
||||
encode_fix(&info->fix, info);
|
||||
|
||||
i810fb_init_ringbuffer(info);
|
||||
err = register_framebuffer(info);
|
||||
|
||||
if (err < 0) {
|
||||
i810fb_release_resource(info, par);
|
||||
printk("i810fb_init: cannot register framebuffer device\n");
|
||||
@ -1951,6 +2035,8 @@ static void i810fb_release_resource(struct fb_info *info,
|
||||
struct gtt_data *gtt = &par->i810_gtt;
|
||||
unset_mtrr(par);
|
||||
|
||||
i810_delete_i2c_busses(par);
|
||||
|
||||
if (par->i810_gtt.i810_cursor_memory)
|
||||
agp_free_memory(gtt->i810_cursor_memory);
|
||||
if (par->i810_gtt.i810_fb_memory)
|
||||
@ -1960,7 +2046,8 @@ static void i810fb_release_resource(struct fb_info *info,
|
||||
iounmap(par->mmio_start_virtual);
|
||||
if (par->aperture.virtual)
|
||||
iounmap(par->aperture.virtual);
|
||||
|
||||
if (par->edid)
|
||||
kfree(par->edid);
|
||||
if (par->res_flags & FRAMEBUFFER_REQ)
|
||||
release_mem_region(par->aperture.physical,
|
||||
par->aperture.size);
|
||||
@ -1986,7 +2073,7 @@ static void __exit i810fb_remove_pci(struct pci_dev *dev)
|
||||
}
|
||||
|
||||
#ifndef MODULE
|
||||
static int __init i810fb_init(void)
|
||||
static int __devinit i810fb_init(void)
|
||||
{
|
||||
char *option = NULL;
|
||||
|
||||
@ -2004,7 +2091,7 @@ static int __init i810fb_init(void)
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
static int __init i810fb_init(void)
|
||||
static int __devinit i810fb_init(void)
|
||||
{
|
||||
hsync1 *= 1000;
|
||||
hsync2 *= 1000;
|
||||
@ -2052,6 +2139,8 @@ MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
|
||||
module_param(dcolor, bool, 0);
|
||||
MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
|
||||
" (default = 0 = TrueColor)");
|
||||
module_param(mode_option, charp, 0);
|
||||
MODULE_PARM_DESC(mode_option, "Specify initial video mode");
|
||||
|
||||
MODULE_AUTHOR("Tony A. Daplas");
|
||||
MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"
|
||||
|
@ -83,6 +83,22 @@ extern int i810fb_sync (struct fb_info *p);
|
||||
extern void i810fb_init_ringbuffer(struct fb_info *info);
|
||||
extern void i810fb_load_front (u32 offset, struct fb_info *info);
|
||||
|
||||
#ifdef CONFIG_FB_I810_I2C
|
||||
/* I2C */
|
||||
extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
|
||||
int conn);
|
||||
extern void i810_create_i2c_busses(struct i810fb_par *par);
|
||||
extern void i810_delete_i2c_busses(struct i810fb_par *par);
|
||||
#else
|
||||
static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
|
||||
int conn)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static inline void i810_create_i2c_busses(struct i810fb_par *par) { }
|
||||
static inline void i810_delete_i2c_busses(struct i810fb_par *par) { }
|
||||
#endif
|
||||
|
||||
/* Conditionals */
|
||||
#ifdef CONFIG_X86
|
||||
inline void flush_cache(void)
|
||||
|
Loading…
Reference in New Issue
Block a user