提交 7c08c9ae 编写于 作者: P Peter Jones 提交者: Linus Torvalds

efifb/imacfb consolidation + hardware support

Remove imacfb entirely, merging its DMI table into the (otherwise very
similar) efifb driver.  This also adds hardware support for many of the
newer Intel Apple hardware.  This has been fairly well tested; we've been
shipping it in Fedora for some time.
Signed-off-by: NPeter Jones <pjones@redhat.com>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: Jaya Kumar <jayakumar.lkml@gmail.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 f928ac0a
......@@ -689,23 +689,14 @@ config FB_VESA
config FB_EFI
bool "EFI-based Framebuffer Support"
depends on (FB = y) && X86
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
This is the EFI frame buffer device driver. If the firmware on
your platform is UEFI2.0, select Y to add support for
Graphics Output Protocol for early console messages to appear.
config FB_IMAC
bool "Intel-based Macintosh Framebuffer Support"
depends on (FB = y) && X86 && EFI
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
This is the frame buffer device driver for the Intel-based Macintosh
This is the EFI frame buffer device driver. If the firmware on
your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
using the EFI framebuffer as your console.
config FB_N411
tristate "N411 Apollo/Hecuba devkit support"
......
......@@ -125,7 +125,6 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_IMAC) += imacfb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
......
......@@ -12,6 +12,7 @@
#include <linux/fb.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <linux/dmi.h>
#include <video/vga.h>
......@@ -33,6 +34,105 @@ static struct fb_fix_screeninfo efifb_fix __initdata = {
.visual = FB_VISUAL_TRUECOLOR,
};
enum {
M_I17, /* 17-Inch iMac */
M_I20, /* 20-Inch iMac */
M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
M_I24, /* 24-Inch iMac */
M_MINI, /* Mac Mini */
M_MB, /* MacBook */
M_MB_2, /* MacBook, 2nd rev. */
M_MB_3, /* MacBook, 3rd rev. */
M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
M_MBA, /* MacBook Air */
M_MBP, /* MacBook Pro */
M_MBP_2, /* MacBook Pro 2nd gen */
M_MBP_SR, /* MacBook Pro (Santa Rosa) */
M_MBP_4, /* MacBook Pro, 4th gen */
M_UNKNOWN /* placeholder */
};
static struct efifb_dmi_info {
char *optname;
unsigned long base;
int stride;
int width;
int height;
} dmi_list[] = {
[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 },
[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */
[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 },
[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 },
[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 },
[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 },
[M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */
[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 },
[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 },
[M_UNKNOWN] = { NULL, 0, 0, 0, 0 }
};
static int set_system(const struct dmi_system_id *id);
#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
{ set_system, name, { \
DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
DMI_MATCH(DMI_PRODUCT_NAME, name) }, \
&dmi_list[enumid] }
static struct dmi_system_id __initdata dmi_system_table[] = {
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
{},
};
static int set_system(const struct dmi_system_id *id)
{
struct efifb_dmi_info *info = id->driver_data;
if (info->base == 0)
return -ENODEV;
printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
"(%dx%d, stride %d)\n", id->ident,
(void *)info->base, info->width, info->height,
info->stride);
/* Trust the bootloader over the DMI tables */
if (screen_info.lfb_base == 0)
screen_info.lfb_base = info->base;
if (screen_info.lfb_linelength == 0)
screen_info.lfb_linelength = info->stride;
if (screen_info.lfb_width == 0)
screen_info.lfb_width = info->width;
if (screen_info.lfb_height == 0)
screen_info.lfb_height = info->height;
return 0;
}
static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
......@@ -67,6 +167,38 @@ static struct fb_ops efifb_ops = {
.fb_imageblit = cfb_imageblit,
};
static int __init efifb_setup(char *options)
{
char *this_opt;
int i;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
for (i = 0; i < M_UNKNOWN; i++) {
if (!strcmp(this_opt, dmi_list[i].optname) &&
dmi_list[i].base != 0) {
screen_info.lfb_base = dmi_list[i].base;
screen_info.lfb_linelength = dmi_list[i].stride;
screen_info.lfb_width = dmi_list[i].width;
screen_info.lfb_height = dmi_list[i].height;
}
}
if (!strncmp(this_opt, "base:", 5))
screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
else if (!strncmp(this_opt, "stride:", 7))
screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
else if (!strncmp(this_opt, "height:", 7))
screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
else if (!strncmp(this_opt, "width:", 6))
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
}
return 0;
}
static int __init efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
......@@ -74,6 +206,26 @@ static int __init efifb_probe(struct platform_device *dev)
unsigned int size_vmode;
unsigned int size_remap;
unsigned int size_total;
int request_succeeded = 0;
printk(KERN_INFO "efifb: probing for efifb\n");
if (!screen_info.lfb_depth)
screen_info.lfb_depth = 32;
if (!screen_info.pages)
screen_info.pages = 1;
/* just assume they're all unset if any are */
if (!screen_info.blue_size) {
screen_info.blue_size = 8;
screen_info.blue_pos = 0;
screen_info.green_size = 8;
screen_info.green_pos = 8;
screen_info.red_size = 8;
screen_info.red_pos = 16;
screen_info.rsvd_size = 8;
screen_info.rsvd_pos = 24;
}
efifb_fix.smem_start = screen_info.lfb_base;
efifb_defined.bits_per_pixel = screen_info.lfb_depth;
......@@ -98,21 +250,25 @@ static int __init efifb_probe(struct platform_device *dev)
* option to simply use size_total as that
* wastes plenty of kernel address space. */
size_remap = size_vmode * 2;
if (size_remap < size_vmode)
size_remap = size_vmode;
if (size_remap > size_total)
size_remap = size_total;
if (size_remap % PAGE_SIZE)
size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
efifb_fix.smem_len = size_remap;
if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb"))
if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
request_succeeded = 1;
} else {
/* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
printk(KERN_WARNING
"efifb: cannot reserve video memory at 0x%lx\n",
efifb_fix.smem_start);
}
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
if (!info) {
printk(KERN_ERR "efifb: cannot allocate framebuffer\n");
err = -ENOMEM;
goto err_release_mem;
}
......@@ -125,7 +281,7 @@ static int __init efifb_probe(struct platform_device *dev)
"0x%x @ 0x%lx\n",
efifb_fix.smem_len, efifb_fix.smem_start);
err = -EIO;
goto err_unmap;
goto err_release_fb;
}
printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
......@@ -178,25 +334,27 @@ static int __init efifb_probe(struct platform_device *dev)
info->fix = efifb_fix;
info->flags = FBINFO_FLAG_DEFAULT;
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
err = -ENOMEM;
if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
printk(KERN_ERR "efifb: cannot allocate colormap\n");
goto err_unmap;
}
if (register_framebuffer(info) < 0) {
err = -EINVAL;
if ((err = register_framebuffer(info)) < 0) {
printk(KERN_ERR "efifb: cannot register framebuffer\n");
goto err_fb_dealoc;
}
printk(KERN_INFO "fb%d: %s frame buffer device\n",
info->node, info->fix.id);
info->node, info->fix.id);
return 0;
err_fb_dealoc:
fb_dealloc_cmap(&info->cmap);
err_unmap:
iounmap(info->screen_base);
err_release_fb:
framebuffer_release(info);
err_release_mem:
release_mem_region(efifb_fix.smem_start, size_total);
if (request_succeeded)
release_mem_region(efifb_fix.smem_start, size_total);
return err;
}
......@@ -214,9 +372,22 @@ static struct platform_device efifb_device = {
static int __init efifb_init(void)
{
int ret;
char *option = NULL;
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
return -ENODEV;
dmi_check_system(dmi_system_table);
if (fb_get_options("efifb", &option))
return -ENODEV;
efifb_setup(option);
/* We don't get linelength from UGA Draw Protocol, only from
* EFI Graphics Protocol. So if it's not in DMI, and it's not
* passed in from the user, we really can't use the framebuffer.
*/
if (!screen_info.lfb_linelength)
return -ENODEV;
ret = platform_driver_register(&efifb_driver);
......
/*
* framebuffer driver for Intel Based Mac's
*
* (c) 2006 Edgar Hucek <gimli@dark-green.com>
* Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/dmi.h>
#include <linux/efi.h>
#include <asm/io.h>
#include <video/vga.h>
typedef enum _MAC_TYPE {
M_I17,
M_I20,
M_MINI,
M_MACBOOK,
M_UNKNOWN
} MAC_TYPE;
/* --------------------------------------------------------------------- */
static struct fb_var_screeninfo imacfb_defined __initdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.right_margin = 32,
.upper_margin = 16,
.lower_margin = 4,
.vsync_len = 4,
.vmode = FB_VMODE_NONINTERLACED,
};
static struct fb_fix_screeninfo imacfb_fix __initdata = {
.id = "IMAC VGA",
.type = FB_TYPE_PACKED_PIXELS,
.accel = FB_ACCEL_NONE,
.visual = FB_VISUAL_TRUECOLOR,
};
static int inverse;
static int model = M_UNKNOWN;
static int manual_height;
static int manual_width;
static int set_system(const struct dmi_system_id *id)
{
printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
id->ident, (long)id->driver_data);
model = (long)id->driver_data;
return 0;
}
static struct dmi_system_id __initdata dmi_system_table[] = {
{ set_system, "iMac4,1", {
DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17},
{ set_system, "MacBookPro1,1", {
DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17},
{ set_system, "MacBook1,1", {
DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK},
{ set_system, "Macmini1,1", {
DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI},
{},
};
#define DEFAULT_FB_MEM 1024*1024*16
/* --------------------------------------------------------------------- */
static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
/*
* Set a single color register. The values supplied are
* already rounded down to the hardware's capabilities
* (according to the entries in the `var' structure). Return
* != 0 for invalid regno.
*/
if (regno >= info->cmap.len)
return 1;
if (regno < 16) {
red >>= 8;
green >>= 8;
blue >>= 8;
((u32 *)(info->pseudo_palette))[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
}
return 0;
}
static struct fb_ops imacfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = imacfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int __init imacfb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
if (!strcmp(this_opt, "inverse"))
inverse = 1;
else if (!strcmp(this_opt, "i17"))
model = M_I17;
else if (!strcmp(this_opt, "i20"))
model = M_I20;
else if (!strcmp(this_opt, "mini"))
model = M_MINI;
else if (!strcmp(this_opt, "macbook"))
model = M_MACBOOK;
else if (!strncmp(this_opt, "height:", 7))
manual_height = simple_strtoul(this_opt+7, NULL, 0);
else if (!strncmp(this_opt, "width:", 6))
manual_width = simple_strtoul(this_opt+6, NULL, 0);
}
return 0;
}
static int __init imacfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int err;
unsigned int size_vmode;
unsigned int size_remap;
unsigned int size_total;
screen_info.lfb_depth = 32;
screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
screen_info.pages=1;
screen_info.blue_size = 8;
screen_info.blue_pos = 0;
screen_info.green_size = 8;
screen_info.green_pos = 8;
screen_info.red_size = 8;
screen_info.red_pos = 16;
screen_info.rsvd_size = 8;
screen_info.rsvd_pos = 24;
switch (model) {
case M_I17:
screen_info.lfb_width = 1440;
screen_info.lfb_height = 900;
screen_info.lfb_linelength = 1472 * 4;
screen_info.lfb_base = 0x80010000;
break;
case M_I20:
screen_info.lfb_width = 1680;
screen_info.lfb_height = 1050;
screen_info.lfb_linelength = 1728 * 4;
screen_info.lfb_base = 0x80010000;
break;
case M_MINI:
screen_info.lfb_width = 1024;
screen_info.lfb_height = 768;
screen_info.lfb_linelength = 2048 * 4;
screen_info.lfb_base = 0x80000000;
break;
case M_MACBOOK:
screen_info.lfb_width = 1280;
screen_info.lfb_height = 800;
screen_info.lfb_linelength = 2048 * 4;
screen_info.lfb_base = 0x80000000;
break;
}
/* if the user wants to manually specify height/width,
we will override the defaults */
/* TODO: eventually get auto-detection working */
if (manual_height > 0)
screen_info.lfb_height = manual_height;
if (manual_width > 0)
screen_info.lfb_width = manual_width;
imacfb_fix.smem_start = screen_info.lfb_base;
imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
imacfb_defined.xres = screen_info.lfb_width;
imacfb_defined.yres = screen_info.lfb_height;
imacfb_fix.line_length = screen_info.lfb_linelength;
/* size_vmode -- that is the amount of memory needed for the
* used video mode, i.e. the minimum amount of
* memory we need. */
size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
/* size_total -- all video memory we have. Used for
* entries, ressource allocation and bounds
* checking. */
size_total = screen_info.lfb_size * 65536;
if (size_total < size_vmode)
size_total = size_vmode;
/* size_remap -- the amount of video memory we are going to
* use for imacfb. With modern cards it is no
* option to simply use size_total as that
* wastes plenty of kernel address space. */
size_remap = size_vmode * 2;
if (size_remap < size_vmode)
size_remap = size_vmode;
if (size_remap > size_total)
size_remap = size_total;
imacfb_fix.smem_len = size_remap;
if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
printk(KERN_WARNING
"imacfb: cannot reserve video memory at 0x%lx\n",
imacfb_fix.smem_start);
/* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
}
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
if (!info) {
err = -ENOMEM;
goto err_release_mem;
}
info->pseudo_palette = info->par;
info->par = NULL;
info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
"0x%x @ 0x%lx\n",
imacfb_fix.smem_len, imacfb_fix.smem_start);
err = -EIO;
goto err_unmap;
}
printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
"using %dk, total %dk\n",
imacfb_fix.smem_start, info->screen_base,
size_remap/1024, size_total/1024);
printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
imacfb_defined.xres, imacfb_defined.yres,
imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
screen_info.pages);
imacfb_defined.xres_virtual = imacfb_defined.xres;
imacfb_defined.yres_virtual = imacfb_fix.smem_len /
imacfb_fix.line_length;
printk(KERN_INFO "imacfb: scrolling: redraw\n");
imacfb_defined.yres_virtual = imacfb_defined.yres;
/* some dummy values for timing to make fbset happy */
imacfb_defined.pixclock = 10000000 / imacfb_defined.xres *
1000 / imacfb_defined.yres;
imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8;
imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8;
imacfb_defined.red.offset = screen_info.red_pos;
imacfb_defined.red.length = screen_info.red_size;
imacfb_defined.green.offset = screen_info.green_pos;
imacfb_defined.green.length = screen_info.green_size;
imacfb_defined.blue.offset = screen_info.blue_pos;
imacfb_defined.blue.length = screen_info.blue_size;
imacfb_defined.transp.offset = screen_info.rsvd_pos;
imacfb_defined.transp.length = screen_info.rsvd_size;
printk(KERN_INFO "imacfb: %s: "
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
"Truecolor",
screen_info.rsvd_size,
screen_info.red_size,
screen_info.green_size,
screen_info.blue_size,
screen_info.rsvd_pos,
screen_info.red_pos,
screen_info.green_pos,
screen_info.blue_pos);
imacfb_fix.ypanstep = 0;
imacfb_fix.ywrapstep = 0;
/* request failure does not faze us, as vgacon probably has this
* region already (FIXME) */
request_region(0x3c0, 32, "imacfb");
info->fbops = &imacfb_ops;
info->var = imacfb_defined;
info->fix = imacfb_fix;
info->flags = FBINFO_FLAG_DEFAULT;
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
err = -ENOMEM;
goto err_unmap;
}
if (register_framebuffer(info)<0) {
err = -EINVAL;
goto err_fb_dealoc;
}
printk(KERN_INFO "fb%d: %s frame buffer device\n",
info->node, info->fix.id);
return 0;
err_fb_dealoc:
fb_dealloc_cmap(&info->cmap);
err_unmap:
iounmap(info->screen_base);
framebuffer_release(info);
err_release_mem:
release_mem_region(imacfb_fix.smem_start, size_total);
return err;
}
static struct platform_driver imacfb_driver = {
.probe = imacfb_probe,
.driver = {
.name = "imacfb",
},
};
static struct platform_device imacfb_device = {
.name = "imacfb",
};
static int __init imacfb_init(void)
{
int ret;
char *option = NULL;
if (!efi_enabled)
return -ENODEV;
if (!dmi_check_system(dmi_system_table))
return -ENODEV;
if (model == M_UNKNOWN)
return -ENODEV;
if (fb_get_options("imacfb", &option))
return -ENODEV;
imacfb_setup(option);
ret = platform_driver_register(&imacfb_driver);
if (!ret) {
ret = platform_device_register(&imacfb_device);
if (ret)
platform_driver_unregister(&imacfb_driver);
}
return ret;
}
module_init(imacfb_init);
MODULE_LICENSE("GPL");
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册