ALT Linux Bugzilla
– Attachment 2161 Details for
Bug 12618
uvesafb
New bug
|
Search
|
[?]
|
Help
Register
|
Log In
[x]
|
Forgot Password
Login:
[x]
|
EN
|
RU
[patch]
uvesafb-0.1-rc3-2.6.18.patch
uvesafb-0.1-rc3-2.6.18.patch (text/plain), 69.01 KB, created by
led
on 2007-08-23 16:46:28 MSD
(
hide
)
Description:
uvesafb-0.1-rc3-2.6.18.patch
Filename:
MIME Type:
Creator:
led
Created:
2007-08-23 16:46:28 MSD
Size:
69.01 KB
patch
obsolete
>diff -urN kernel-source-2.6.18.orig/Documentation/fb/uvesafb.txt kernel-source-2.6.18/Documentation/fb/uvesafb.txt >--- kernel-source-2.6.18.orig/Documentation/fb/uvesafb.txt 1970-01-01 03:00:00 +0300 >+++ kernel-source-2.6.18/Documentation/fb/uvesafb.txt 2007-08-22 23:57:58 +0300 >@@ -0,0 +1,188 @@ >+ >+uvesafb - A Generic Driver for VBE2+ compliant video cards >+========================================================== >+ >+1. Requirements >+--------------- >+ >+uvesafb should work with any video card that has a Video BIOS compliant >+with the VBE 2.0 standard. >+ >+Unlike other drivers, uvesafb makes use of a userspace helper called >+v86d. v86d is used to run the x86 Video BIOS code in a simulated and >+controlled environment. This allows uvesafb to function on arches other >+than x86. Check the v86d documentation for a list of currently supported >+arches. >+ >+v86d source code can be downloaded from the following website: >+ http://dev.gentoo.org/~spock/projects/uvesafb >+ >+Please refer to the v86d documentation for detailed configuration and >+installation instructions. >+ >+Note that the v86d userspace helper has to be available at all times in >+order for uvesafb to work properly. If you want to use uvesafb during >+early boot, you will have to include v86d into an initramfs image, and >+either compile it into the kernel or use it as an initrd. >+ >+2. Caveats and limitations >+-------------------------- >+ >+uvesafb is a _generic_ driver which supports a wide variety of video >+cards, but which is ultimately limited by the Video BIOS interface. >+The most important limitations are: >+ >+- Lack of any type of acceleration. >+- A strict and limited set of supported video modes. Often the native >+ or most optimal resolution/refresh rate for your setup will not work >+ with uvesafb, simply because the Video BIOS doesn't support the >+ video mode you want to use. This can be especially painful with >+ widescreen panels, where native video modes don't have the 4:3 aspect >+ ratio, which is what most BIOS-es are limited to. >+- Adjusting the refresh rate is only possible with a VBE 3.0 compliant >+ Video BIOS. Note that many nVidia Video BIOS-es claim to be VBE 3.0 >+ compliant, while they simply ignore any refresh rate settings. >+ >+3. Configuration >+---------------- >+ >+uvesafb can be compiled either as a module, or directly into the kernel. >+In both cases it supports the same set of configuration options, which >+are either given on the kernel command line or as module parameters, e.g.: >+ >+ video=uvesafb:1024x768-32,mtrr:3,ywrap (compiled into the kernel) >+ >+ # modprobe uvesafb mode=1024x768-32 mtrr=3 scroll=ywrap (module) >+ >+Accepted options: >+ >+ypan Enable display panning using the VESA protected mode >+ interface. The visible screen is just a window of the >+ video memory, console scrolling is done by changing the >+ start of the window. Available on x86 only. >+ >+ywrap Same as ypan, but assumes your gfx board can wrap-around >+ the video memory (i.e. starts reading from top if it >+ reaches the end of video memory). Faster than ypan. >+ Available on x86 only. >+ >+redraw Scroll by redrawing the affected part of the screen, this >+ is the safe (and slow) default. >+ >+(If you're using uvesafb as a module, the above three options are >+ used a parameter of the scroll option, e.g. scroll=ypan.) >+ >+vgapal Use the standard VGA registers for palette changes. >+ >+pmipal Use the protected mode interface for palette changes. >+ This is the default if the protected mode interface is >+ available. Available on x86 only. >+ >+mtrr:n Setup memory type range registers for the framebuffer >+ where n: >+ 0 - disabled (equivalent to nomtrr) (default) >+ 1 - uncachable >+ 2 - write-back >+ 3 - write-combining >+ 4 - write-through >+ >+ If you see the following in dmesg, choose the type that matches >+ the old one. In this example, use "mtrr:2". >+... >+mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining >+... >+ >+nomtrr Do not use memory type range registers. >+ >+vremap:n >+ Remap 'n' MiB of video RAM. If 0 or not specified, remap memory >+ according to video mode. >+ >+vtotal:n >+ If the video BIOS of your card incorrectly determines the total >+ amount of video RAM, use this option to override the BIOS (in MiB). >+ >+<mode> The mode you want to set, in the standard modedb format. Refer to >+ modedb.txt for a detailed description. When uvesafb is compiled as >+ a module, the mode string should be provided as a value of the >+ 'mode' option. >+ >+vbemode:x >+ Force the use of VBE mode x. The mode will only be set if it's >+ found in the VBE-provided list of supported modes. >+ NOTE: The mode number 'x' should be specified in VESA mode number >+ notation, not the Linux kernel one (eg. 257 instead of 769). >+ HINT: If you use this option because normal <mode> parameter does >+ not work for you and you use a X server, you'll probably want to >+ set the 'nocrtc' option to ensure that the video mode is properly >+ restored after console <-> X switches. >+ >+nocrtc Do not use CRTC timings while setting the video mode. This option >+ has any effect only if the Video BIOS is VBE 3.0 compliant. Use it >+ if you have problems with modes set the standard way. Note that >+ using this option implies that any refresh rate adjustments will >+ be ignored and the refresh rate will stay at your BIOS default (60 Hz). >+ >+noedid Do not try to fetch and use EDID-provided modes. >+ >+noblank Disable hardware blanking. >+ >+v86d:path >+ Set path to the v86d executable. This option is only available as >+ a module parameter, and not as a part of the video= string. If you >+ need to use it and have uvesafb built into the kernel, use >+ uvesafb.v86d="path". >+ >+Additionally, the following parameters may be provided. They all override the >+EDID-provided values and BIOS defaults. Refer to your monitor's specs to get >+the correct values for maxhf, maxvf and maxclk for your hardware. >+ >+maxhf:n Maximum horizontal frequency (in kHz). >+maxvf:n Maximum vertical frequency (in Hz). >+maxclk:n Maximum pixel clock (in MHz). >+ >+4. The sysfs interface >+---------------------- >+ >+uvesafb provides several sysfs nodes for configurable parameters and >+additional information. >+ >+Driver attributes: >+ >+/sys/bus/platform/drivers/uvesafb >+ - v86d (default: /sbin/v86d) >+ Path to the v86d executable. v86d is started by uvesafb >+ if an instance of the daemon isn't already running. >+ >+Device attributes: >+ >+/sys/bus/platform/drivers/uvesafb/uvesafb.0 >+ - nocrtc >+ Use the default refresh rate (60 Hz) if set to 1. >+ >+ - oem_product_name >+ - oem_product_rev >+ - oem_string >+ - oem_vendor >+ Information about the card and its maker. >+ >+ - vbe_modes >+ A list of video modes supported by the Video BIOS along with their >+ VBE mode numbers in hex. >+ >+ - vbe_version >+ A BCD value indicating the implemented VBE standard. >+ >+5. Miscellaneous >+---------------- >+ >+Uvesafb will set a video mode with the default refresh rate and timings >+from the Video BIOS if you set pixclock to 0 in fb_var_screeninfo. >+ >+ >+-- >+ Michal Januszewski <spock@gentoo.org> >+ Last updated: 2007-06-16 >+ >+ Documentation of the uvesafb options is loosely based on vesafb.txt. >+ >diff -urN kernel-source-2.6.18.orig/drivers/video/Kconfig kernel-source-2.6.18/drivers/video/Kconfig >--- kernel-source-2.6.18.orig/drivers/video/Kconfig 2006-09-20 06:42:06 +0300 >+++ kernel-source-2.6.18/drivers/video/Kconfig 2007-08-22 23:57:58 +0300 >@@ -540,6 +540,24 @@ > This is the frame buffer device driver for generic TGA graphic > cards. Say Y if you have one of those. > >+config FB_UVESA >+ tristate "Userspace VESA VGA graphics support" >+ depends on FB && CONNECTOR >+ select FB_CFB_FILLRECT >+ select FB_CFB_COPYAREA >+ select FB_CFB_IMAGEBLIT >+ select FB_MODE_HELPERS >+ help >+ This is the frame buffer driver for generic VBE 2.0 compliant >+ graphic cards. It can also take advantage of VBE 3.0 features, >+ such as refresh rate adjustment. >+ >+ This driver generally provides more features than vesafb but >+ requires a userspace helper application called 'v86d'. See >+ <file:Documentation/fb/uvesafb.txt> for more information. >+ >+ If unsure, say N. >+ > config FB_VESA > bool "VESA VGA graphics support" > depends on (FB = y) && X86 >diff -urN kernel-source-2.6.18.orig/drivers/video/Makefile kernel-source-2.6.18/drivers/video/Makefile >--- kernel-source-2.6.18.orig/drivers/video/Makefile 2006-09-20 06:42:06 +0300 >+++ kernel-source-2.6.18/drivers/video/Makefile 2007-08-22 23:57:58 +0300 >@@ -100,6 +100,7 @@ > obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ > > # 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_VGA16) += vga16fb.o vgastate.o >diff -urN kernel-source-2.6.18.orig/drivers/video/modedb.c kernel-source-2.6.18/drivers/video/modedb.c >--- kernel-source-2.6.18.orig/drivers/video/modedb.c 2006-09-20 06:42:06 +0300 >+++ kernel-source-2.6.18/drivers/video/modedb.c 2007-08-22 23:57:58 +0300 >@@ -607,28 +607,25 @@ > DPRINTK("Trying specified video mode%s %ix%i\n", > refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); > >- diff = refresh; >+ diff = (refresh_specified) ? refresh : 0; > best = -1; > for (i = 0; i < dbsize; i++) { >- if ((name_matches(db[i], name, namelen) && >- !fb_try_mode(var, info, &db[i], bpp))) >- return 1; >- if (res_specified && res_matches(db[i], xres, yres)) { >- if(!fb_try_mode(var, info, &db[i], bpp)) { >- if(!refresh_specified || db[i].refresh == refresh) >- return 1; >- else { >- if(diff > abs(db[i].refresh - refresh)) { >- diff = abs(db[i].refresh - refresh); >- best = i; >- } >+ if ((name_matches(db[i], name, namelen) || >+ (res_specified && res_matches(db[i], xres, yres))) && >+ !fb_try_mode(var, info, &db[i], bpp)) { >+ if (refresh_specified && db[i].refresh == refresh) { >+ return 1; >+ } else { >+ if (diff < db[i].refresh) { >+ diff = db[i].refresh; >+ best = i; > } > } > } > } > if (best != -1) { > fb_try_mode(var, info, &db[best], bpp); >- return 2; >+ return (refresh_specified) ? 2 : 1; > } > > diff = xres + yres; >@@ -936,6 +933,7 @@ > kfree(pos); > } > } >+EXPORT_SYMBOL_GPL(fb_destroy_modelist); > > /** > * fb_videomode_to_modelist: convert mode array to mode list >diff -urN kernel-source-2.6.18.orig/drivers/video/uvesafb.c kernel-source-2.6.18/drivers/video/uvesafb.c >--- kernel-source-2.6.18.orig/drivers/video/uvesafb.c 1970-01-01 03:00:00 +0300 >+++ kernel-source-2.6.18/drivers/video/uvesafb.c 2007-08-23 00:05:37 +0300 >@@ -0,0 +1,2076 @@ >+/* >+ * A framebuffer driver for VBE 2.0+ compliant video cards >+ * >+ * (c) 2007 Michal Januszewski <spock@gentoo.org> >+ * Loosely based upon the vesafb driver. >+ * >+ */ >+#include <linux/init.h> >+#include <linux/module.h> >+#include <linux/moduleparam.h> >+#include <linux/skbuff.h> >+#include <linux/timer.h> >+#include <linux/completion.h> >+#include <linux/connector.h> >+#include <linux/random.h> >+#include <linux/platform_device.h> >+#include <linux/limits.h> >+#include <linux/fb.h> >+#include <linux/io.h> >+#include <linux/mutex.h> >+#include <video/edid.h> >+#include <video/vga.h> >+#include <video/uvesafb.h> >+#ifdef CONFIG_MTRR >+#include <asm/mtrr.h> >+#endif >+#include "edid.h" >+#include <linux/percpu.h> >+ >+struct rnd_state {u32 s1, s2, s3;}; >+ >+static DEFINE_PER_CPU(struct rnd_state, net_rand_state); >+ >+#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b) >+ >+static u32 random32(void) >+{ >+ struct rnd_state *state = &get_cpu_var(net_rand_state); >+ >+ state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12); >+ state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4); >+ state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17); >+ put_cpu_var(state); >+ return (state->s1 ^ state->s2 ^ state->s3); >+} >+ >+static struct cb_id uvesafb_cn_id = { >+ .idx = CN_IDX_V86D, >+ .val = CN_VAL_V86D_UVESAFB >+}; >+static char v86d_path[PATH_MAX] = "/sbin/v86d"; >+static char v86d_started; /* has v86d been started by uvesafb? */ >+ >+static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { >+ .id = "VESA VGA", >+ .type = FB_TYPE_PACKED_PIXELS, >+ .accel = FB_ACCEL_NONE, >+ .visual = FB_VISUAL_TRUECOLOR, >+}; >+ >+static int mtrr __devinitdata = 3; /* enable mtrr by default */ >+static int blank __devinitdata = 1; /* enable blanking by default */ >+static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */ >+static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */ >+static int nocrtc __devinitdata; /* ignore CRTC settings */ >+static int noedid __devinitdata; /* don't try DDC transfers */ >+static int vram_remap __devinitdata; /* set amt. of memory to be used */ >+static int vram_total __devinitdata; /* set total amount of memory */ >+static u16 maxclk __devinitdata; /* maximum pixel clock */ >+static u16 maxvf __devinitdata; /* maximum vertical frequency */ >+static u16 maxhf __devinitdata; /* maximum horizontal frequency */ >+static u16 vbemode __devinitdata; /* force use of a specific VBE mode */ >+static char *mode_option __devinitdata; >+ >+static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX]; >+static DEFINE_MUTEX(uvfb_lock); >+ >+/* >+ * A handler for replies from userspace. >+ * >+ * Make sure each message passes consistency checks and if it does, >+ * find the kernel part of the task struct, copy the registers and >+ * the buffer contents and then complete the task. >+ */ >+static void uvesafb_cn_callback(void *data) >+{ >+ struct cn_msg *msg = data; >+ struct uvesafb_task *utask; >+ struct uvesafb_ktask *task; >+ >+ if (msg->seq >= UVESAFB_TASKS_MAX) >+ return; >+ >+ mutex_lock(&uvfb_lock); >+ task = uvfb_tasks[msg->seq]; >+ >+ if (!task || msg->ack != task->ack) { >+ mutex_unlock(&uvfb_lock); >+ return; >+ } >+ >+ utask = (struct uvesafb_task *)msg->data; >+ >+ /* Sanity checks for the buffer length. */ >+ if (task->t.buf_len < utask->buf_len || >+ utask->buf_len > msg->len - sizeof(*utask)) { >+ mutex_unlock(&uvfb_lock); >+ return; >+ } >+ >+ uvfb_tasks[msg->seq] = NULL; >+ mutex_unlock(&uvfb_lock); >+ >+ memcpy(&task->t, utask, sizeof(*utask)); >+ >+ if (task->t.buf_len && task->buf) >+ memcpy(task->buf, utask + 1, task->t.buf_len); >+ >+ complete(task->done); >+ return; >+} >+ >+static int uvesafb_helper_start(void) >+{ >+ char *envp[] = { >+ "HOME=/", >+ "PATH=/sbin:/bin", >+ NULL, >+ }; >+ >+ char *argv[] = { >+ v86d_path, >+ NULL, >+ }; >+ >+ return call_usermodehelper(v86d_path, argv, envp, 1); >+} >+ >+/* >+ * Execute a uvesafb task. >+ * >+ * Returns 0 if the task is executed successfully. >+ * >+ * A message sent to the userspace consists of the uvesafb_task >+ * struct and (optionally) a buffer. The uvesafb_task struct is >+ * a simplified version of uvesafb_ktask (its kernel counterpart) >+ * containing only the register values, flags and the length of >+ * the buffer. >+ * >+ * Each message is assigned a sequence number (increased linearly) >+ * and a random ack number. The sequence number is used as a key >+ * for the uvfb_tasks array which holds pointers to uvesafb_ktask >+ * structs for all requests. >+ */ >+static int uvesafb_exec(struct uvesafb_ktask *task) >+{ >+ static int seq; >+ struct cn_msg *m; >+ int err; >+ int len = sizeof(task->t) + task->t.buf_len; >+ >+ /* >+ * Check whether the message isn't longer than the maximum >+ * allowed by connector. >+ */ >+ if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) { >+ printk(KERN_WARNING "uvesafb: message too long (%d), " >+ "can't execute task\n", (int)(sizeof(*m) + len)); >+ return -E2BIG; >+ } >+ >+ m = kzalloc(sizeof(*m) + len, GFP_KERNEL); >+ if (!m) >+ return -ENOMEM; >+ >+ init_completion(task->done); >+ >+ memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id)); >+ m->seq = seq; >+ m->len = len; >+ m->ack = random32(); >+ >+ /* uvesafb_task structure */ >+ memcpy(m + 1, &task->t, sizeof(task->t)); >+ >+ /* Buffer */ >+ memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len); >+ >+ /* >+ * Save the message ack number so that we can find the kernel >+ * part of this task when a reply is received from userspace. >+ */ >+ task->ack = m->ack; >+ >+ mutex_lock(&uvfb_lock); >+ >+ /* If all slots are taken -- bail out. */ >+ if (uvfb_tasks[seq]) { >+ mutex_unlock(&uvfb_lock); >+ return -EBUSY; >+ } >+ >+ /* Save a pointer to the kernel part of the task struct. */ >+ uvfb_tasks[seq] = task; >+ mutex_unlock(&uvfb_lock); >+ >+ err = cn_netlink_send(m, 0, gfp_any()); >+ if (err == -ESRCH) { >+ /* >+ * Try to start the userspace helper if sending >+ * the request failed the first time. >+ */ >+ err = uvesafb_helper_start(); >+ if (err) { >+ printk(KERN_ERR "uvesafb: failed to execute %s\n", >+ v86d_path); >+ printk(KERN_ERR "uvesafb: make sure that the v86d " >+ "helper is installed and executable\n"); >+ } else { >+ v86d_started = 1; >+ err = cn_netlink_send(m, 0, gfp_any()); >+ } >+ } >+ kfree(m); >+ >+ if (!err && !(task->t.flags & TF_EXIT)) >+ err = !wait_for_completion_timeout(task->done, >+ msecs_to_jiffies(UVESAFB_TIMEOUT)); >+ >+ mutex_lock(&uvfb_lock); >+ uvfb_tasks[seq] = NULL; >+ mutex_unlock(&uvfb_lock); >+ >+ seq++; >+ if (seq >= UVESAFB_TASKS_MAX) >+ seq = 0; >+ >+ return err; >+} >+ >+/* >+ * Free a uvesafb_ktask struct. >+ */ >+static void uvesafb_free(struct uvesafb_ktask *task) >+{ >+ if (task) { >+ if (task->done) >+ kfree(task->done); >+ kfree(task); >+ } >+} >+ >+/* >+ * Prepare a uvesafb_ktask struct to be used again. >+ */ >+static void uvesafb_reset(struct uvesafb_ktask *task) >+{ >+ struct completion *cpl = task->done; >+ >+ memset(task, 0, sizeof(*task)); >+ task->done = cpl; >+} >+ >+/* >+ * Allocate and prepare a uvesafb_ktask struct. >+ */ >+static struct uvesafb_ktask *uvesafb_prep(void) >+{ >+ struct uvesafb_ktask *task; >+ >+ task = kzalloc(sizeof(*task), GFP_KERNEL); >+ if (task) { >+ task->done = kzalloc(sizeof(*task->done), GFP_KERNEL); >+ if (!task->done) { >+ kfree(task); >+ task = NULL; >+ } >+ } >+ return task; >+} >+ >+static void uvesafb_setup_var(struct fb_var_screeninfo *var, >+ struct fb_info *info, struct vbe_mode_ib *mode) >+{ >+ struct uvesafb_par *par = info->par; >+ >+ var->vmode = FB_VMODE_NONINTERLACED; >+ var->sync = FB_SYNC_VERT_HIGH_ACT; >+ >+ var->xres = mode->x_res; >+ var->yres = mode->y_res; >+ var->xres_virtual = mode->x_res; >+ var->yres_virtual = (par->ypan) ? >+ info->fix.smem_len / mode->bytes_per_scan_line : >+ mode->y_res; >+ var->xoffset = 0; >+ var->yoffset = 0; >+ var->bits_per_pixel = mode->bits_per_pixel; >+ >+ if (var->bits_per_pixel == 15) >+ var->bits_per_pixel = 16; >+ >+ if (var->bits_per_pixel > 8) { >+ var->red.offset = mode->red_off; >+ var->red.length = mode->red_len; >+ var->green.offset = mode->green_off; >+ var->green.length = mode->green_len; >+ var->blue.offset = mode->blue_off; >+ var->blue.length = mode->blue_len; >+ var->transp.offset = mode->rsvd_off; >+ var->transp.length = mode->rsvd_len; >+ } else { >+ var->red.offset = 0; >+ var->green.offset = 0; >+ var->blue.offset = 0; >+ var->transp.offset = 0; >+ >+ /* >+ * We're assuming that we can switch the DAC to 8 bits. If >+ * this proves to be incorrect, we'll update the fields >+ * later in set_par(). >+ */ >+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) { >+ var->red.length = 8; >+ var->green.length = 8; >+ var->blue.length = 8; >+ var->transp.length = 0; >+ } else { >+ var->red.length = 6; >+ var->green.length = 6; >+ var->blue.length = 6; >+ var->transp.length = 0; >+ } >+ } >+} >+ >+static int uvesafb_vbe_find_mode(struct uvesafb_par *par, >+ int xres, int yres, int depth, unsigned char flags) >+{ >+ int i, match = -1, h = 0, d = 0x7fffffff; >+ >+ for (i = 0; i < par->vbe_modes_cnt; i++) { >+ h = abs(par->vbe_modes[i].x_res - xres) + >+ abs(par->vbe_modes[i].y_res - yres) + >+ abs(depth - par->vbe_modes[i].depth); >+ >+ /* >+ * We have an exact match in terms of resolution >+ * and depth. >+ */ >+ if (h == 0) >+ return i; >+ >+ if (h < d || (h == d && par->vbe_modes[i].depth > depth)) { >+ d = h; >+ match = i; >+ } >+ } >+ i = 1; >+ >+ if (flags & UVESAFB_EXACT_DEPTH && >+ par->vbe_modes[match].depth != depth) >+ i = 0; >+ >+ if (flags & UVESAFB_EXACT_RES && d > 24) >+ i = 0; >+ >+ if (i != 0) >+ return match; >+ else >+ return -1; >+} >+ >+static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par) >+{ >+ struct uvesafb_ktask *task; >+ u8 *state; >+ int err; >+ >+ if (!par->vbe_state_size) >+ return NULL; >+ >+ state = kmalloc(par->vbe_state_size, GFP_KERNEL); >+ if (!state) >+ return NULL; >+ >+ task = uvesafb_prep(); >+ if (!task) { >+ kfree(state); >+ return NULL; >+ } >+ >+ task->t.regs.eax = 0x4f04; >+ task->t.regs.ecx = 0x000f; >+ task->t.regs.edx = 0x0001; >+ task->t.flags = TF_BUF_RET | TF_BUF_ESBX; >+ task->t.buf_len = par->vbe_state_size; >+ task->buf = state; >+ err = uvesafb_exec(task); >+ >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) { >+ printk(KERN_WARNING "uvesafb: VBE get state call " >+ "failed (eax=0x%x, err=%d)\n", >+ task->t.regs.eax, err); >+ kfree(state); >+ state = NULL; >+ } >+ >+ uvesafb_free(task); >+ return state; >+} >+ >+static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf) >+{ >+ struct uvesafb_ktask *task; >+ int err; >+ >+ if (!state_buf) >+ return; >+ >+ task = uvesafb_prep(); >+ if (!task) >+ return; >+ >+ task->t.regs.eax = 0x4f04; >+ task->t.regs.ecx = 0x000f; >+ task->t.regs.edx = 0x0002; >+ task->t.buf_len = par->vbe_state_size; >+ task->t.flags = TF_BUF_ESBX; >+ task->buf = state_buf; >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) >+ printk(KERN_WARNING "uvesafb: VBE state restore call " >+ "failed (eax=0x%x, err=%d)\n", >+ task->t.regs.eax, err); >+ >+ uvesafb_free(task); >+} >+ >+static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task, >+ struct uvesafb_par *par) >+{ >+ int err; >+ >+ task->t.regs.eax = 0x4f00; >+ task->t.flags = TF_VBEIB; >+ task->t.buf_len = sizeof(struct vbe_ib); >+ task->buf = &par->vbe_ib; >+ strncpy(par->vbe_ib.vbe_signature, "VBE2", 4); >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) { >+ printk(KERN_ERR "uvesafb: Getting VBE info block failed " >+ "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax, >+ err); >+ return -EINVAL; >+ } >+ >+ if (par->vbe_ib.vbe_version < 0x0200) { >+ printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are " >+ "not supported.\n"); >+ return -EINVAL; >+ } >+ >+ if (!par->vbe_ib.mode_list_ptr) { >+ printk(KERN_ERR "uvesafb: Missing mode list!\n"); >+ return -EINVAL; >+ } >+ >+ printk(KERN_INFO "uvesafb: "); >+ >+ /* >+ * Convert string pointers and the mode list pointer into >+ * usable addresses. Print informational messages about the >+ * video adapter and its vendor. >+ */ >+ if (par->vbe_ib.oem_vendor_name_ptr) >+ printk("%s, ", >+ ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr); >+ >+ if (par->vbe_ib.oem_product_name_ptr) >+ printk("%s, ", >+ ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr); >+ >+ if (par->vbe_ib.oem_product_rev_ptr) >+ printk("%s, ", >+ ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr); >+ >+ if (par->vbe_ib.oem_string_ptr) >+ printk("OEM: %s, ", >+ ((char *)task->buf) + par->vbe_ib.oem_string_ptr); >+ >+ printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8), >+ par->vbe_ib.vbe_version & 0xff); >+ >+ return 0; >+} >+ >+static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task, >+ struct uvesafb_par *par) >+{ >+ int off = 0, err; >+ u16 *mode; >+ >+ par->vbe_modes_cnt = 0; >+ >+ /* Count available modes. */ >+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); >+ while (*mode != 0xffff) { >+ par->vbe_modes_cnt++; >+ mode++; >+ } >+ >+ par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) * >+ par->vbe_modes_cnt, GFP_KERNEL); >+ if (!par->vbe_modes) >+ return -ENOMEM; >+ >+ /* Get info about all available modes. */ >+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr); >+ while (*mode != 0xffff) { >+ struct vbe_mode_ib *mib; >+ >+ uvesafb_reset(task); >+ task->t.regs.eax = 0x4f01; >+ task->t.regs.ecx = (u32) *mode; >+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI; >+ task->t.buf_len = sizeof(struct vbe_mode_ib); >+ task->buf = par->vbe_modes + off; >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) { >+ printk(KERN_ERR "uvesafb: Getting mode info block " >+ "for mode 0x%x failed (eax=0x%x, err=%d)\n", >+ *mode, (u32)task->t.regs.eax, err); >+ return -EINVAL; >+ } >+ >+ mib = task->buf; >+ mib->mode_id = *mode; >+ >+ /* >+ * We only want modes that are supported with the current >+ * hardware configuration, color, graphics and that have >+ * support for the LFB. >+ */ >+ if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK && >+ mib->bits_per_pixel >= 8) >+ off++; >+ else >+ par->vbe_modes_cnt--; >+ >+ mode++; >+ mib->depth = mib->red_len + mib->green_len + mib->blue_len; >+ >+ /* >+ * Handle 8bpp modes and modes with broken color component >+ * lengths. >+ */ >+ if (mib->depth == 0 || (mib->depth == 24 && >+ mib->bits_per_pixel == 32)) >+ mib->depth = mib->bits_per_pixel; >+ } >+ >+ return 0; >+} >+ >+/* >+ * The Protected Mode Interface is 32-bit x86 code, so we only run it on >+ * x86 and not x86_64. >+ */ >+#ifdef CONFIG_X86_32 >+static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task, >+ struct uvesafb_par *par) >+{ >+ int i, err; >+ >+ uvesafb_reset(task); >+ task->t.regs.eax = 0x4f0a; >+ task->t.regs.ebx = 0x0; >+ err = uvesafb_exec(task); >+ >+ if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) { >+ par->pmi_setpal = par->ypan = 0; >+ } else { >+ par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4) >+ + task->t.regs.edi); >+ par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1]; >+ par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2]; >+ printk(KERN_INFO "uvesafb: protected mode interface info at " >+ "%04x:%04x\n", >+ (u16)task->t.regs.es, (u16)task->t.regs.edi); >+ printk(KERN_INFO "uvesafb: pmi: set display start = %p, " >+ "set palette = %p\n", par->pmi_start, >+ par->pmi_pal); >+ >+ if (par->pmi_base[3]) { >+ printk(KERN_INFO "uvesafb: pmi: ports = "); >+ for (i = par->pmi_base[3]/2; >+ par->pmi_base[i] != 0xffff; i++) >+ printk("%x ", par->pmi_base[i]); >+ printk("\n"); >+ >+ if (par->pmi_base[i] != 0xffff) { >+ printk(KERN_INFO "uvesafb: can't handle memory" >+ " requests, pmi disabled\n"); >+ par->ypan = par->pmi_setpal = 0; >+ } >+ } >+ } >+ return 0; >+} >+#endif /* CONFIG_X86_32 */ >+ >+/* >+ * Check whether a video mode is supported by the Video BIOS and is >+ * compatible with the monitor limits. >+ */ >+static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode, >+ struct fb_info *info) >+{ >+ if (info->monspecs.gtf) { >+ fb_videomode_to_var(&info->var, mode); >+ if (fb_validate_mode(&info->var, info)) >+ return 0; >+ } >+ >+ if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8, >+ UVESAFB_EXACT_RES) == -1) >+ return 0; >+ >+ return 1; >+} >+ >+static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, >+ struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ int err = 0; >+ >+ if (noedid || par->vbe_ib.vbe_version < 0x0300) >+ return -EINVAL; >+ >+ task->t.regs.eax = 0x4f15; >+ task->t.regs.ebx = 0; >+ task->t.regs.ecx = 0; >+ task->t.buf_len = 0; >+ task->t.flags = 0; >+ >+ err = uvesafb_exec(task); >+ >+ if ((task->t.regs.eax & 0xffff) != 0x004f || err) >+ return -EINVAL; >+ >+ if ((task->t.regs.ebx & 0x3) == 3) { >+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports both " >+ "DDC1 and DDC2 transfers\n"); >+ } else if ((task->t.regs.ebx & 0x3) == 2) { >+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 " >+ "transfers\n"); >+ } else if ((task->t.regs.ebx & 0x3) == 1) { >+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 " >+ "transfers\n"); >+ } else { >+ printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support " >+ "DDC transfers\n"); >+ return -EINVAL; >+ } >+ >+ task->t.regs.eax = 0x4f15; >+ task->t.regs.ebx = 1; >+ task->t.regs.ecx = task->t.regs.edx = 0; >+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI; >+ task->t.buf_len = EDID_LENGTH; >+ task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); >+ >+ err = uvesafb_exec(task); >+ >+ if ((task->t.regs.eax & 0xffff) == 0x004f && !err) { >+ fb_edid_to_monspecs(task->buf, &info->monspecs); >+ >+ if (info->monspecs.vfmax && info->monspecs.hfmax) { >+ /* >+ * If the maximum pixel clock wasn't specified in >+ * the EDID block, set it to 300 MHz. >+ */ >+ if (info->monspecs.dclkmax == 0) >+ info->monspecs.dclkmax = 300 * 1000000; >+ info->monspecs.gtf = 1; >+ } >+ } else { >+ err = -EINVAL; >+ } >+ >+ kfree(task->buf); >+ return err; >+} >+ >+static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task, >+ struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ int i; >+ >+ memset(&info->monspecs, 0, sizeof(info->monspecs)); >+ >+ /* >+ * If we don't get all necessary data from the EDID block, >+ * mark it as incompatible with the GTF and set nocrtc so >+ * that we always use the default BIOS refresh rate. >+ */ >+ if (uvesafb_vbe_getedid(task, info)) { >+ info->monspecs.gtf = 0; >+ par->nocrtc = 1; >+ } >+ >+ /* Kernel command line overrides. */ >+ if (maxclk) >+ info->monspecs.dclkmax = maxclk * 1000000; >+ if (maxvf) >+ info->monspecs.vfmax = maxvf; >+ if (maxhf) >+ info->monspecs.hfmax = maxhf * 1000; >+ >+ /* >+ * In case DDC transfers are not supported, the user can provide >+ * monitor limits manually. Lower limits are set to "safe" values. >+ */ >+ if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) { >+ info->monspecs.dclkmin = 0; >+ info->monspecs.vfmin = 60; >+ info->monspecs.hfmin = 29000; >+ info->monspecs.gtf = 1; >+ par->nocrtc = 0; >+ } >+ >+ if (info->monspecs.gtf) >+ printk(KERN_INFO >+ "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, " >+ "clk = %d MHz\n", info->monspecs.vfmax, >+ (int)(info->monspecs.hfmax / 1000), >+ (int)(info->monspecs.dclkmax / 1000000)); >+ else >+ printk(KERN_INFO "uvesafb: no monitor limits have been set, " >+ "default refresh rate will be used\n"); >+ >+ /* Add VBE modes to the modelist. */ >+ for (i = 0; i < par->vbe_modes_cnt; i++) { >+ struct fb_var_screeninfo var; >+ struct vbe_mode_ib *mode; >+ struct fb_videomode vmode; >+ >+ mode = &par->vbe_modes[i]; >+ memset(&var, 0, sizeof(var)); >+ >+ var.xres = mode->x_res; >+ var.yres = mode->y_res; >+ >+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info); >+ fb_var_to_videomode(&vmode, &var); >+ fb_add_videomode(&vmode, &info->modelist); >+ } >+ >+ /* Add valid VESA modes to our modelist. */ >+ for (i = 0; i < VESA_MODEDB_SIZE; i++) { >+ if (uvesafb_is_valid_mode((struct fb_videomode *) >+ &vesa_modes[i], info)) >+ fb_add_videomode(&vesa_modes[i], &info->modelist); >+ } >+ >+ for (i = 0; i < info->monspecs.modedb_len; i++) { >+ if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info)) >+ fb_add_videomode(&info->monspecs.modedb[i], >+ &info->modelist); >+ } >+ >+ return; >+} >+ >+static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task, >+ struct uvesafb_par *par) >+{ >+ int err; >+ >+ uvesafb_reset(task); >+ >+ /* >+ * Get the VBE state buffer size. We want all available >+ * hardware state data (CL = 0x0f). >+ */ >+ task->t.regs.eax = 0x4f04; >+ task->t.regs.ecx = 0x000f; >+ task->t.regs.edx = 0x0000; >+ task->t.flags = 0; >+ >+ err = uvesafb_exec(task); >+ >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) { >+ printk(KERN_WARNING "uvesafb: VBE state buffer size " >+ "cannot be determined (eax=0x%x, err=%d)\n", >+ task->t.regs.eax, err); >+ par->vbe_state_size = 0; >+ return; >+ } >+ >+ par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff); >+} >+ >+static int __devinit uvesafb_vbe_init(struct fb_info *info) >+{ >+ struct uvesafb_ktask *task = NULL; >+ struct uvesafb_par *par = info->par; >+ int err; >+ >+ task = uvesafb_prep(); >+ if (!task) >+ return -ENOMEM; >+ >+ err = uvesafb_vbe_getinfo(task, par); >+ if (err) >+ goto out; >+ >+ err = uvesafb_vbe_getmodes(task, par); >+ if (err) >+ goto out; >+ >+ par->nocrtc = nocrtc; >+#ifdef CONFIG_X86_32 >+ par->pmi_setpal = pmi_setpal; >+ par->ypan = ypan; >+ >+ if (par->pmi_setpal || par->ypan) >+ uvesafb_vbe_getpmi(task, par); >+#else >+ /* The protected mode interface is not available on non-x86. */ >+ par->pmi_setpal = par->ypan = 0; >+#endif >+ >+ INIT_LIST_HEAD(&info->modelist); >+ uvesafb_vbe_getmonspecs(task, info); >+ uvesafb_vbe_getstatesize(task, par); >+ >+out: uvesafb_free(task); >+ return err; >+} >+ >+static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) >+{ >+ struct list_head *pos; >+ struct fb_modelist *modelist; >+ struct fb_videomode *mode; >+ struct uvesafb_par *par = info->par; >+ int i, modeid; >+ >+ /* Has the user requested a specific VESA mode? */ >+ if (vbemode) { >+ for (i = 0; i < par->vbe_modes_cnt; i++) { >+ if (par->vbe_modes[i].mode_id == vbemode) { >+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, >+ &info->var, info); >+ /* >+ * With pixclock set to 0, the default BIOS >+ * timings will be used in set_par(). >+ */ >+ info->var.pixclock = 0; >+ modeid = i; >+ goto gotmode; >+ } >+ } >+ printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is " >+ "unavailable\n", vbemode); >+ vbemode = 0; >+ } >+ >+ /* Count the modes in the modelist */ >+ i = 0; >+ list_for_each(pos, &info->modelist) >+ i++; >+ >+ /* >+ * Convert the modelist into a modedb so that we can use it with >+ * fb_find_mode(). >+ */ >+ mode = kzalloc(i * sizeof(*mode), GFP_KERNEL); >+ if (mode) { >+ i = 0; >+ list_for_each(pos, &info->modelist) { >+ modelist = list_entry(pos, struct fb_modelist, list); >+ mode[i] = modelist->mode; >+ i++; >+ } >+ >+ if (!mode_option) >+ mode_option = UVESAFB_DEFAULT_MODE; >+ >+ i = fb_find_mode(&info->var, info, mode_option, mode, i, >+ NULL, 8); >+ >+ kfree(mode); >+ } >+ >+ /* fb_find_mode() failed */ >+ if (i == 0 || i >= 3) { >+ info->var.xres = 640; >+ info->var.yres = 480; >+ mode = (struct fb_videomode *) >+ fb_find_best_mode(&info->var, &info->modelist); >+ >+ if (mode) { >+ fb_videomode_to_var(&info->var, mode); >+ } else { >+ modeid = par->vbe_modes[0].mode_id; >+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, >+ &info->var, info); >+ goto gotmode; >+ } >+ } >+ >+ /* Look for a matching VBE mode. */ >+ modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, >+ info->var.bits_per_pixel, UVESAFB_EXACT_RES); >+ >+ if (modeid == -1) >+ return -EINVAL; >+ >+gotmode: >+ uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]); >+ >+ /* >+ * If we are not VBE3.0+ compliant, we're done -- the BIOS will >+ * ignore our timings anyway. >+ */ >+ if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc) >+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, >+ &info->var, info); >+ >+ return modeid; >+} >+ >+static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count, >+ int start, struct fb_info *info) >+{ >+ struct uvesafb_ktask *task; >+ struct uvesafb_par *par = info->par; >+ int i = par->mode_idx; >+ int err = 0; >+ >+ /* >+ * We support palette modifications for 8 bpp modes only, so >+ * there can never be more than 256 entries. >+ */ >+ if (start + count > 256) >+ return -EINVAL; >+ >+ /* Use VGA registers if mode is VGA-compatible. */ >+ if (i >= 0 && i < par->vbe_modes_cnt && >+ par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) { >+ for (i = 0; i < count; i++) { >+ outb_p(start + i, dac_reg); >+ outb_p(entries[i].red, dac_val); >+ outb_p(entries[i].green, dac_val); >+ outb_p(entries[i].blue, dac_val); >+ } >+ } >+#ifdef CONFIG_X86_32 >+ else if (par->pmi_setpal) { >+ __asm__ __volatile__( >+ "call *(%%esi)" >+ : /* no return value */ >+ : "a" (0x4f09), /* EAX */ >+ "b" (0), /* EBX */ >+ "c" (count), /* ECX */ >+ "d" (start), /* EDX */ >+ "D" (entries), /* EDI */ >+ "S" (&par->pmi_pal)); /* ESI */ >+ } >+#endif >+ else { >+ task = uvesafb_prep(); >+ if (!task) >+ return -ENOMEM; >+ >+ task->t.regs.eax = 0x4f09; >+ task->t.regs.ebx = 0x0; >+ task->t.regs.ecx = count; >+ task->t.regs.edx = start; >+ task->t.flags = TF_BUF_ESDI; >+ task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count; >+ task->buf = entries; >+ >+ err = uvesafb_exec(task); >+ if ((task->t.regs.eax & 0xffff) != 0x004f) >+ err = 1; >+ >+ uvesafb_free(task); >+ } >+ return err; >+} >+ >+static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green, >+ unsigned blue, unsigned transp, >+ struct fb_info *info) >+{ >+ struct uvesafb_pal_entry entry; >+ int shift = 16 - info->var.green.length; >+ int err = 0; >+ >+ if (regno >= info->cmap.len) >+ return -EINVAL; >+ >+ if (info->var.bits_per_pixel == 8) { >+ entry.red = red >> shift; >+ entry.green = green >> shift; >+ entry.blue = blue >> shift; >+ entry.pad = 0; >+ >+ err = uvesafb_setpalette(&entry, 1, regno, info); >+ } else if (regno < 16) { >+ switch (info->var.bits_per_pixel) { >+ case 16: >+ if (info->var.red.offset == 10) { >+ /* 1:5:5:5 */ >+ ((u32 *) (info->pseudo_palette))[regno] = >+ ((red & 0xf800) >> 1) | >+ ((green & 0xf800) >> 6) | >+ ((blue & 0xf800) >> 11); >+ } else { >+ /* 0:5:6:5 */ >+ ((u32 *) (info->pseudo_palette))[regno] = >+ ((red & 0xf800) ) | >+ ((green & 0xfc00) >> 5) | >+ ((blue & 0xf800) >> 11); >+ } >+ break; >+ >+ case 24: >+ case 32: >+ 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); >+ break; >+ } >+ } >+ return err; >+} >+ >+static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) >+{ >+ struct uvesafb_pal_entry *entries; >+ int shift = 16 - info->var.green.length; >+ int i, err = 0; >+ >+ if (info->var.bits_per_pixel == 8) { >+ if (cmap->start + cmap->len > info->cmap.start + >+ info->cmap.len || cmap->start < info->cmap.start) >+ return -EINVAL; >+ >+ entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); >+ if (!entries) >+ return -ENOMEM; >+ >+ for (i = 0; i < cmap->len; i++) { >+ entries[i].red = cmap->red[i] >> shift; >+ entries[i].green = cmap->green[i] >> shift; >+ entries[i].blue = cmap->blue[i] >> shift; >+ entries[i].pad = 0; >+ } >+ err = uvesafb_setpalette(entries, cmap->len, cmap->start, info); >+ kfree(entries); >+ } else { >+ /* >+ * For modes with bpp > 8, we only set the pseudo palette in >+ * the fb_info struct. We rely on uvesafb_setcolreg to do all >+ * sanity checking. >+ */ >+ for (i = 0; i < cmap->len; i++) { >+ err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i], >+ cmap->green[i], cmap->blue[i], >+ 0, info); >+ } >+ } >+ return err; >+} >+ >+static int uvesafb_pan_display(struct fb_var_screeninfo *var, >+ struct fb_info *info) >+{ >+#ifdef CONFIG_X86_32 >+ int offset; >+ struct uvesafb_par *par = info->par; >+ >+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; >+ >+ /* >+ * It turns out it's not the best idea to do panning via vm86, >+ * so we only allow it if we have a PMI. >+ */ >+ if (par->pmi_start) { >+ __asm__ __volatile__( >+ "call *(%%edi)" >+ : /* no return value */ >+ : "a" (0x4f07), /* EAX */ >+ "b" (0), /* EBX */ >+ "c" (offset), /* ECX */ >+ "d" (offset >> 16), /* EDX */ >+ "D" (&par->pmi_start)); /* EDI */ >+ } >+#endif >+ return 0; >+} >+ >+static int uvesafb_blank(int blank, struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ struct uvesafb_ktask *task; >+ int err = 1; >+ >+ if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) { >+ int loop = 10000; >+ u8 seq = 0, crtc17 = 0; >+ >+ if (blank == FB_BLANK_POWERDOWN) { >+ seq = 0x20; >+ crtc17 = 0x00; >+ err = 0; >+ } else { >+ seq = 0x00; >+ crtc17 = 0x80; >+ err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL; >+ } >+ >+ vga_wseq(NULL, 0x00, 0x01); >+ seq |= vga_rseq(NULL, 0x01) & ~0x20; >+ vga_wseq(NULL, 0x00, seq); >+ >+ crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80; >+ while (loop--); >+ vga_wcrt(NULL, 0x17, crtc17); >+ vga_wseq(NULL, 0x00, 0x03); >+ } else { >+ task = uvesafb_prep(); >+ if (!task) >+ return -ENOMEM; >+ >+ task->t.regs.eax = 0x4f10; >+ switch (blank) { >+ case FB_BLANK_UNBLANK: >+ task->t.regs.ebx = 0x0001; >+ break; >+ case FB_BLANK_NORMAL: >+ task->t.regs.ebx = 0x0101; /* standby */ >+ break; >+ case FB_BLANK_POWERDOWN: >+ task->t.regs.ebx = 0x0401; /* powerdown */ >+ break; >+ default: >+ goto out; >+ } >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) >+ err = 1; >+out: uvesafb_free(task); >+ } >+ return err; >+} >+ >+static int uvesafb_open(struct fb_info *info, int user) >+{ >+ struct uvesafb_par *par = info->par; >+ int cnt = atomic_read(&par->ref_count); >+ >+ if (!cnt && par->vbe_state_size) >+ par->vbe_state_orig = uvesafb_vbe_state_save(par); >+ >+ atomic_inc(&par->ref_count); >+ return 0; >+} >+ >+static int uvesafb_release(struct fb_info *info, int user) >+{ >+ struct uvesafb_ktask *task = NULL; >+ struct uvesafb_par *par = info->par; >+ int cnt = atomic_read(&par->ref_count); >+ >+ if (!cnt) >+ return -EINVAL; >+ >+ if (cnt != 1) >+ goto out; >+ >+ task = uvesafb_prep(); >+ if (!task) >+ goto out; >+ >+ /* First, try to set the standard 80x25 text mode. */ >+ task->t.regs.eax = 0x0003; >+ uvesafb_exec(task); >+ >+ /* >+ * Now try to restore whatever hardware state we might have >+ * saved when the fb device was first opened. >+ */ >+ uvesafb_vbe_state_restore(par, par->vbe_state_orig); >+out: >+ atomic_dec(&par->ref_count); >+ if (task) >+ uvesafb_free(task); >+ return 0; >+} >+ >+static int uvesafb_set_par(struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ struct uvesafb_ktask *task = NULL; >+ struct vbe_crtc_ib *crtc = NULL; >+ struct vbe_mode_ib *mode = NULL; >+ int i, err = 0, depth = info->var.bits_per_pixel; >+ >+ if (depth > 8 && depth != 32) >+ depth = info->var.red.length + info->var.green.length + >+ info->var.blue.length; >+ >+ i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth, >+ UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH); >+ if (i >= 0) >+ mode = &par->vbe_modes[i]; >+ else >+ return -EINVAL; >+ >+ task = uvesafb_prep(); >+ if (!task) >+ return -ENOMEM; >+setmode: >+ task->t.regs.eax = 0x4f02; >+ task->t.regs.ebx = mode->mode_id | 0x4000; /* use LFB */ >+ >+ if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc && >+ info->var.pixclock != 0) { >+ task->t.regs.ebx |= 0x0800; /* use CRTC data */ >+ task->t.flags = TF_BUF_ESDI; >+ crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL); >+ if (!crtc) { >+ err = -ENOMEM; >+ goto out; >+ } >+ crtc->horiz_start = info->var.xres + info->var.right_margin; >+ crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; >+ crtc->horiz_total = crtc->horiz_end + info->var.left_margin; >+ >+ crtc->vert_start = info->var.yres + info->var.lower_margin; >+ crtc->vert_end = crtc->vert_start + info->var.vsync_len; >+ crtc->vert_total = crtc->vert_end + info->var.upper_margin; >+ >+ crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000; >+ crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock / >+ (crtc->vert_total * crtc->horiz_total))); >+ >+ if (info->var.vmode & FB_VMODE_DOUBLE) >+ crtc->flags |= 0x1; >+ if (info->var.vmode & FB_VMODE_INTERLACED) >+ crtc->flags |= 0x2; >+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) >+ crtc->flags |= 0x4; >+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) >+ crtc->flags |= 0x8; >+ memcpy(&par->crtc, crtc, sizeof(*crtc)); >+ } else { >+ memset(&par->crtc, 0, sizeof(*crtc)); >+ } >+ >+ task->t.buf_len = sizeof(struct vbe_crtc_ib); >+ task->buf = &par->crtc; >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) { >+ /* >+ * The mode switch might have failed because we tried to >+ * use our own timings. Try again with the default timings. >+ */ >+ if (crtc != NULL) { >+ printk(KERN_WARNING "uvesafb: mode switch failed " >+ "(eax=0x%x, err=%d). Trying again with " >+ "default timings.\n", task->t.regs.eax, err); >+ uvesafb_reset(task); >+ kfree(crtc); >+ crtc = NULL; >+ info->var.pixclock = 0; >+ goto setmode; >+ } else { >+ printk(KERN_ERR "uvesafb: mode switch failed (eax=" >+ "0x%x, err=%d)\n", task->t.regs.eax, err); >+ err = -EINVAL; >+ goto out; >+ } >+ } >+ par->mode_idx = i; >+ >+ /* For 8bpp modes, always try to set the DAC to 8 bits. */ >+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC && >+ mode->bits_per_pixel <= 8) { >+ uvesafb_reset(task); >+ task->t.regs.eax = 0x4f08; >+ task->t.regs.ebx = 0x0800; >+ >+ err = uvesafb_exec(task); >+ if (err || (task->t.regs.eax & 0xffff) != 0x004f || >+ ((task->t.regs.ebx & 0xff00) >> 8) != 8) { >+ /* >+ * We've failed to set the DAC palette format - >+ * time to correct var. >+ */ >+ info->var.red.length = 6; >+ info->var.green.length = 6; >+ info->var.blue.length = 6; >+ } >+ } >+ >+ info->fix.visual = (info->var.bits_per_pixel == 8) ? >+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; >+ info->fix.line_length = mode->bytes_per_scan_line; >+ >+out: if (crtc != NULL) >+ kfree(crtc); >+ uvesafb_free(task); >+ >+ return err; >+} >+ >+static void uvesafb_check_limits(struct fb_var_screeninfo *var, >+ struct fb_info *info) >+{ >+ const struct fb_videomode *mode; >+ struct uvesafb_par *par = info->par; >+ >+ /* >+ * If pixclock is set to 0, then we're using default BIOS timings >+ * and thus don't have to perform any checks here. >+ */ >+ if (!var->pixclock) >+ return; >+ >+ if (par->vbe_ib.vbe_version < 0x0300) { >+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info); >+ return; >+ } >+ >+ if (!fb_validate_mode(var, info)) >+ return; >+ >+ mode = fb_find_best_mode(var, &info->modelist); >+ if (mode) { >+ if (mode->xres == var->xres && mode->yres == var->yres && >+ !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) { >+ fb_videomode_to_var(var, mode); >+ return; >+ } >+ } >+ >+ if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) >+ return; >+ /* Use default refresh rate */ >+ var->pixclock = 0; >+} >+ >+static int uvesafb_check_var(struct fb_var_screeninfo *var, >+ struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ struct vbe_mode_ib *mode = NULL; >+ int match = -1; >+ int depth = var->red.length + var->green.length + var->blue.length; >+ >+ /* >+ * Various apps will use bits_per_pixel to set the color depth, >+ * which is theoretically incorrect, but which we'll try to handle >+ * here. >+ */ >+ if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8) >+ depth = var->bits_per_pixel; >+ >+ match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth, >+ UVESAFB_EXACT_RES); >+ if (match == -1) >+ return -EINVAL; >+ >+ mode = &par->vbe_modes[match]; >+ uvesafb_setup_var(var, info, mode); >+ >+ /* >+ * Check whether we have remapped enough memory for this mode. >+ * We might be called at an early stage, when we haven't remapped >+ * any memory yet, in which case we simply skip the check. >+ */ >+ if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len >+ && info->fix.smem_len) >+ return -EINVAL; >+ >+ if ((var->vmode & FB_VMODE_DOUBLE) && >+ !(par->vbe_modes[match].mode_attr & 0x100)) >+ var->vmode &= ~FB_VMODE_DOUBLE; >+ >+ if ((var->vmode & FB_VMODE_INTERLACED) && >+ !(par->vbe_modes[match].mode_attr & 0x200)) >+ var->vmode &= ~FB_VMODE_INTERLACED; >+ >+ uvesafb_check_limits(var, info); >+ >+ var->xres_virtual = var->xres; >+ var->yres_virtual = (par->ypan) ? >+ info->fix.smem_len / mode->bytes_per_scan_line : >+ var->yres; >+ return 0; >+} >+ >+static void uvesafb_save_state(struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ >+ if (par->vbe_state_saved) >+ kfree(par->vbe_state_saved); >+ >+ par->vbe_state_saved = uvesafb_vbe_state_save(par); >+} >+ >+static void uvesafb_restore_state(struct fb_info *info) >+{ >+ struct uvesafb_par *par = info->par; >+ >+ uvesafb_vbe_state_restore(par, par->vbe_state_saved); >+} >+ >+static struct fb_ops uvesafb_ops = { >+ .owner = THIS_MODULE, >+ .fb_open = uvesafb_open, >+ .fb_release = uvesafb_release, >+ .fb_setcolreg = uvesafb_setcolreg, >+ .fb_setcmap = uvesafb_setcmap, >+ .fb_pan_display = uvesafb_pan_display, >+ .fb_blank = uvesafb_blank, >+ .fb_fillrect = cfb_fillrect, >+ .fb_copyarea = cfb_copyarea, >+ .fb_imageblit = cfb_imageblit, >+ .fb_check_var = uvesafb_check_var, >+ .fb_set_par = uvesafb_set_par, >+ .fb_save_state = uvesafb_save_state, >+ .fb_restore_state = uvesafb_restore_state, >+}; >+ >+static void __devinit uvesafb_init_info(struct fb_info *info, >+ struct vbe_mode_ib *mode) >+{ >+ unsigned int size_vmode; >+ unsigned int size_remap; >+ unsigned int size_total; >+ struct uvesafb_par *par = info->par; >+ int i, h; >+ >+ info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par)); >+ info->fix = uvesafb_fix; >+ info->fix.ypanstep = par->ypan ? 1 : 0; >+ info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0; >+ >+ /* >+ * If we were unable to get the state buffer size, disable >+ * functions for saving and restoring the hardware state. >+ */ >+ if (par->vbe_state_size == 0) { >+ info->fbops->fb_save_state = NULL; >+ info->fbops->fb_restore_state = NULL; >+ } >+ >+ /* Disable blanking if the user requested so. */ >+ if (!blank) >+ info->fbops->fb_blank = NULL; >+ >+ /* >+ * Find out how much IO memory is required for the mode with >+ * the highest resolution. >+ */ >+ size_remap = 0; >+ for (i = 0; i < par->vbe_modes_cnt; i++) { >+ h = par->vbe_modes[i].bytes_per_scan_line * >+ par->vbe_modes[i].y_res; >+ if (h > size_remap) >+ size_remap = h; >+ } >+ size_remap *= 2; >+ >+ /* >+ * size_vmode -- that is the amount of memory needed for the >+ * used video mode, i.e. the minimum amount of >+ * memory we need. >+ */ >+ if (mode != NULL) { >+ size_vmode = info->var.yres * mode->bytes_per_scan_line; >+ } else { >+ size_vmode = info->var.yres * info->var.xres * >+ ((info->var.bits_per_pixel + 7) >> 3); >+ } >+ >+ /* >+ * size_total -- all video memory we have. Used for mtrr >+ * entries, resource allocation and bounds >+ * checking. >+ */ >+ size_total = par->vbe_ib.total_memory * 65536; >+ if (vram_total) >+ size_total = vram_total * 1024 * 1024; >+ if (size_total < size_vmode) >+ size_total = size_vmode; >+ >+ /* >+ * size_remap -- the amount of video memory we are going to >+ * use for vesafb. With modern cards it is no >+ * option to simply use size_total as th >+ * wastes plenty of kernel address space. >+ */ >+ if (vram_remap) >+ size_remap = vram_remap * 1024 * 1024; >+ if (size_remap < size_vmode) >+ size_remap = size_vmode; >+ if (size_remap > size_total) >+ size_remap = size_total; >+ >+ info->fix.smem_len = size_remap; >+ info->fix.smem_start = mode->phys_base_ptr; >+ >+ /* >+ * We have to set yres_virtual here because when setup_var() was >+ * called, smem_len wasn't defined yet. >+ */ >+ info->var.yres_virtual = info->fix.smem_len / >+ mode->bytes_per_scan_line; >+ >+ if (par->ypan && info->var.yres_virtual > info->var.yres) { >+ printk(KERN_INFO "uvesafb: scrolling: %s " >+ "using protected mode interface, " >+ "yres_virtual=%d\n", >+ (par->ypan > 1) ? "ywrap" : "ypan", >+ info->var.yres_virtual); >+ } else { >+ printk(KERN_INFO "uvesafb: scrolling: redraw\n"); >+ info->var.yres_virtual = info->var.yres; >+ par->ypan = 0; >+ } >+ >+ info->flags = FBINFO_FLAG_DEFAULT | >+ (par->ypan) ? FBINFO_HWACCEL_YPAN : 0; >+ >+ if (!par->ypan) >+ info->fbops->fb_pan_display = NULL; >+} >+ >+static void uvesafb_init_mtrr(struct fb_info *info) >+{ >+#ifdef CONFIG_MTRR >+ if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) { >+ int temp_size = info->fix.smem_len; >+ unsigned int type = 0; >+ >+ switch (mtrr) { >+ case 1: >+ type = MTRR_TYPE_UNCACHABLE; >+ break; >+ case 2: >+ type = MTRR_TYPE_WRBACK; >+ break; >+ case 3: >+ type = MTRR_TYPE_WRCOMB; >+ break; >+ case 4: >+ type = MTRR_TYPE_WRTHROUGH; >+ break; >+ default: >+ type = 0; >+ break; >+ } >+ >+ if (type) { >+ int rc; >+ >+ /* Find the largest power-of-two */ >+ while (temp_size & (temp_size - 1)) >+ temp_size &= (temp_size - 1); >+ >+ /* Try and find a power of two to add */ >+ do { >+ rc = mtrr_add(info->fix.smem_start, >+ temp_size, type, 1); >+ temp_size >>= 1; >+ } while (temp_size >= PAGE_SIZE && rc == -EINVAL); >+ } >+ } >+#endif /* CONFIG_MTRR */ >+} >+ >+ >+static ssize_t uvesafb_show_vbe_ver(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version); >+} >+ >+static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL); >+ >+static ssize_t uvesafb_show_vbe_modes(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ int ret = 0, i; >+ >+ for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) { >+ ret += snprintf(buf + ret, PAGE_SIZE - ret, >+ "%dx%d-%d, 0x%.4x\n", >+ par->vbe_modes[i].x_res, par->vbe_modes[i].y_res, >+ par->vbe_modes[i].depth, par->vbe_modes[i].mode_id); >+ } >+ >+ return ret; >+} >+ >+static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL); >+ >+static ssize_t uvesafb_show_vendor(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ if (par->vbe_ib.oem_vendor_name_ptr) >+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *) >+ (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr); >+ else >+ return 0; >+} >+ >+static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL); >+ >+static ssize_t uvesafb_show_product_name(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ if (par->vbe_ib.oem_product_name_ptr) >+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *) >+ (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr); >+ else >+ return 0; >+} >+ >+static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL); >+ >+static ssize_t uvesafb_show_product_rev(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ if (par->vbe_ib.oem_product_rev_ptr) >+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *) >+ (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr); >+ else >+ return 0; >+} >+ >+static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL); >+ >+static ssize_t uvesafb_show_oem_string(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ if (par->vbe_ib.oem_string_ptr) >+ return snprintf(buf, PAGE_SIZE, "%s\n", >+ (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr); >+ else >+ return 0; >+} >+ >+static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL); >+ >+static ssize_t uvesafb_show_nocrtc(struct device *dev, >+ struct device_attribute *attr, char *buf) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc); >+} >+ >+static ssize_t uvesafb_store_nocrtc(struct device *dev, >+ struct device_attribute *attr, const char *buf, size_t count) >+{ >+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev)); >+ struct uvesafb_par *par = info->par; >+ >+ if (count > 0) { >+ if (buf[0] == '0') >+ par->nocrtc = 0; >+ else >+ par->nocrtc = 1; >+ } >+ return count; >+} >+ >+static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc, >+ uvesafb_store_nocrtc); >+ >+static struct attribute *uvesafb_dev_attrs[] = { >+ &dev_attr_vbe_version.attr, >+ &dev_attr_vbe_modes.attr, >+ &dev_attr_oem_vendor.attr, >+ &dev_attr_oem_product_name.attr, >+ &dev_attr_oem_product_rev.attr, >+ &dev_attr_oem_string.attr, >+ &dev_attr_nocrtc.attr, >+ NULL, >+}; >+ >+static struct attribute_group uvesafb_dev_attgrp = { >+ .name = NULL, >+ .attrs = uvesafb_dev_attrs, >+}; >+ >+static int __devinit uvesafb_probe(struct platform_device *dev) >+{ >+ struct fb_info *info; >+ struct vbe_mode_ib *mode = NULL; >+ struct uvesafb_par *par; >+ int err = 0, i; >+ >+ info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev); >+ if (!info) >+ return -ENOMEM; >+ >+ par = info->par; >+ >+ err = uvesafb_vbe_init(info); >+ if (err) { >+ printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err); >+ goto out; >+ } >+ >+ info->fbops = &uvesafb_ops; >+ >+ i = uvesafb_vbe_init_mode(info); >+ if (i < 0) { >+ err = -EINVAL; >+ goto out; >+ } else { >+ mode = &par->vbe_modes[i]; >+ } >+ >+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { >+ err = -ENXIO; >+ goto out; >+ } >+ >+ uvesafb_init_info(info, mode); >+ >+ if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, >+ "uvesafb")) { >+ printk(KERN_ERR "uvesafb: cannot reserve video memory at " >+ "0x%lx\n", info->fix.smem_start); >+ err = -EIO; >+ goto out_mode; >+ } >+ >+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); >+ >+ if (!info->screen_base) { >+ printk(KERN_ERR >+ "uvesafb: abort, cannot ioremap 0x%x bytes of video " >+ "memory at 0x%lx\n", >+ info->fix.smem_len, info->fix.smem_start); >+ err = -EIO; >+ goto out_mem; >+ } >+ >+ if (!request_region(0x3c0, 32, "uvesafb")) { >+ printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n"); >+ err = -EIO; >+ goto out_unmap; >+ } >+ >+ uvesafb_init_mtrr(info); >+ platform_set_drvdata(dev, info); >+ >+ if (register_framebuffer(info) < 0) { >+ printk(KERN_ERR >+ "uvesafb: failed to register framebuffer device\n"); >+ err = -EINVAL; >+ goto out_reg; >+ } >+ >+ printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, " >+ "using %dk, total %dk\n", info->fix.smem_start, >+ info->screen_base, info->fix.smem_len/1024, >+ par->vbe_ib.total_memory * 64); >+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, >+ info->fix.id); >+ >+ err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp); >+ if (err != 0) >+ printk(KERN_WARNING "fb%d: failed to register attributes\n", >+ info->node); >+ >+ return 0; >+ >+out_reg: >+ release_region(0x3c0, 32); >+out_unmap: >+ iounmap(info->screen_base); >+out_mem: >+ release_mem_region(info->fix.smem_start, info->fix.smem_len); >+out_mode: >+ if (!list_empty(&info->modelist)) >+ fb_destroy_modelist(&info->modelist); >+ fb_destroy_modedb(info->monspecs.modedb); >+ fb_dealloc_cmap(&info->cmap); >+out: >+ if (par->vbe_modes) >+ kfree(par->vbe_modes); >+ >+ framebuffer_release(info); >+ return err; >+} >+ >+static int uvesafb_remove(struct platform_device *dev) >+{ >+ struct fb_info *info = platform_get_drvdata(dev); >+ >+ if (info) { >+ struct uvesafb_par *par = info->par; >+ >+ sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp); >+ unregister_framebuffer(info); >+ release_region(0x3c0, 32); >+ iounmap(info->screen_base); >+ release_mem_region(info->fix.smem_start, info->fix.smem_len); >+ fb_destroy_modedb(info->monspecs.modedb); >+ fb_dealloc_cmap(&info->cmap); >+ >+ if (par) { >+ if (par->vbe_modes) >+ kfree(par->vbe_modes); >+ if (par->vbe_state_orig) >+ kfree(par->vbe_state_orig); >+ if (par->vbe_state_saved) >+ kfree(par->vbe_state_saved); >+ } >+ >+ framebuffer_release(info); >+ } >+ return 0; >+} >+ >+static struct platform_driver uvesafb_driver = { >+ .probe = uvesafb_probe, >+ .remove = uvesafb_remove, >+ .driver = { >+ .name = "uvesafb", >+ }, >+}; >+ >+static struct platform_device *uvesafb_device; >+ >+#ifndef MODULE >+static int __devinit uvesafb_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, "redraw")) >+ ypan = 0; >+ else if (!strcmp(this_opt, "ypan")) >+ ypan = 1; >+ else if (!strcmp(this_opt, "ywrap")) >+ ypan = 2; >+ else if (!strcmp(this_opt, "vgapal")) >+ pmi_setpal = 0; >+ else if (!strcmp(this_opt, "pmipal")) >+ pmi_setpal = 1; >+ else if (!strncmp(this_opt, "mtrr:", 5)) >+ mtrr = simple_strtoul(this_opt+5, NULL, 0); >+ else if (!strcmp(this_opt, "nomtrr")) >+ mtrr = 0; >+ else if (!strcmp(this_opt, "nocrtc")) >+ nocrtc = 1; >+ else if (!strcmp(this_opt, "noedid")) >+ noedid = 1; >+ else if (!strcmp(this_opt, "noblank")) >+ blank = 0; >+ else if (!strncmp(this_opt, "vtotal:", 7)) >+ vram_total = simple_strtoul(this_opt + 7, NULL, 0); >+ else if (!strncmp(this_opt, "vremap:", 7)) >+ vram_remap = simple_strtoul(this_opt + 7, NULL, 0); >+ else if (!strncmp(this_opt, "maxhf:", 6)) >+ maxhf = simple_strtoul(this_opt + 6, NULL, 0); >+ else if (!strncmp(this_opt, "maxvf:", 6)) >+ maxvf = simple_strtoul(this_opt + 6, NULL, 0); >+ else if (!strncmp(this_opt, "maxclk:", 7)) >+ maxclk = simple_strtoul(this_opt + 7, NULL, 0); >+ else if (!strncmp(this_opt, "vbemode:", 8)) >+ vbemode = simple_strtoul(this_opt + 8, NULL, 0); >+ else if (this_opt[0] >= '0' && this_opt[0] <= '9') { >+ mode_option = this_opt; >+ } else { >+ printk(KERN_WARNING >+ "uvesafb: unrecognized option %s\n", this_opt); >+ } >+ } >+ >+ return 0; >+} >+#endif /* !MODULE */ >+ >+static ssize_t show_v86d(struct device_driver *dev, char *buf) >+{ >+ return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path); >+} >+ >+static ssize_t store_v86d(struct device_driver *dev, const char *buf, >+ size_t count) >+{ >+ strncpy(v86d_path, buf, PATH_MAX); >+ return count; >+} >+ >+static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d); >+ >+static int __devinit uvesafb_init(void) >+{ >+ int err; >+ >+#ifndef MODULE >+ char *option = NULL; >+ >+ if (fb_get_options("uvesafb", &option)) >+ return -ENODEV; >+ uvesafb_setup(option); >+#endif >+ err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback); >+ if (err) >+ return err; >+ >+ err = platform_driver_register(&uvesafb_driver); >+ >+ if (!err) { >+ uvesafb_device = platform_device_alloc("uvesafb", 0); >+ if (uvesafb_device) >+ err = platform_device_add(uvesafb_device); >+ else >+ err = -ENOMEM; >+ >+ if (err) { >+ platform_device_put(uvesafb_device); >+ platform_driver_unregister(&uvesafb_driver); >+ cn_del_callback(&uvesafb_cn_id); >+ return err; >+ } >+ >+ err = driver_create_file(&uvesafb_driver.driver, >+ &driver_attr_v86d); >+ if (err) { >+ printk(KERN_WARNING "uvesafb: failed to register " >+ "attributes\n"); >+ err = 0; >+ } >+ } >+ return err; >+} >+ >+module_init(uvesafb_init); >+ >+static void __devexit uvesafb_exit(void) >+{ >+ struct uvesafb_ktask *task; >+ >+ if (v86d_started) { >+ task = uvesafb_prep(); >+ if (task) { >+ task->t.flags = TF_EXIT; >+ uvesafb_exec(task); >+ uvesafb_free(task); >+ } >+ } >+ >+ cn_del_callback(&uvesafb_cn_id); >+ driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d); >+ platform_device_unregister(uvesafb_device); >+ platform_driver_unregister(&uvesafb_driver); >+} >+ >+module_exit(uvesafb_exit); >+ >+static inline int param_get_scroll(char *buffer, struct kernel_param *kp) >+{ >+ return 0; >+} >+ >+static inline int param_set_scroll(const char *val, struct kernel_param *kp) >+{ >+ ypan = 0; >+ >+ if (!strcmp(val, "redraw")) >+ ypan = 0; >+ else if (!strcmp(val, "ypan")) >+ ypan = 1; >+ else if (!strcmp(val, "ywrap")) >+ ypan = 2; >+ >+ return 0; >+} >+ >+#define param_check_scroll(name, p) __param_check(name, p, void); >+ >+module_param_named(scroll, ypan, scroll, 0); >+MODULE_PARM_DESC(scroll, >+ "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'"); >+module_param_named(vgapal, pmi_setpal, invbool, 0); >+MODULE_PARM_DESC(vgapal, "Set palette using VGA registers"); >+module_param_named(pmipal, pmi_setpal, bool, 0); >+MODULE_PARM_DESC(pmipal, "Set palette using PMI calls"); >+module_param(mtrr, uint, 0); >+MODULE_PARM_DESC(mtrr, >+ "Memory Type Range Registers setting. Use 0 to disable."); >+module_param(blank, bool, 0); >+MODULE_PARM_DESC(blank, "Enable hardware blanking"); >+module_param(nocrtc, bool, 0); >+MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes"); >+module_param(noedid, bool, 0); >+MODULE_PARM_DESC(noedid, >+ "Ignore EDID-provided monitor limits when setting modes"); >+module_param(vram_remap, uint, 0); >+MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]"); >+module_param(vram_total, uint, 0); >+MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]"); >+module_param(maxclk, ushort, 0); >+MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data"); >+module_param(maxhf, ushort, 0); >+MODULE_PARM_DESC(maxhf, >+ "Maximum horizontal frequency [kHz], overrides EDID data"); >+module_param(maxvf, ushort, 0); >+MODULE_PARM_DESC(maxvf, >+ "Maximum vertical frequency [Hz], overrides EDID data"); >+module_param_named(mode, mode_option, charp, 0); >+MODULE_PARM_DESC(mode, >+ "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); >+module_param(vbemode, ushort, 0); >+MODULE_PARM_DESC(vbemode, >+ "VBE mode number to set, overrides the 'mode' option"); >+module_param_string(v86d, v86d_path, PATH_MAX, 0660); >+MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper."); >+ >+MODULE_LICENSE("GPL"); >+MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>"); >+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards"); >+ >diff -urN kernel-source-2.6.18.orig/include/linux/connector.h kernel-source-2.6.18/include/linux/connector.h >--- kernel-source-2.6.18.orig/include/linux/connector.h 2006-09-20 06:42:06 +0300 >+++ kernel-source-2.6.18/include/linux/connector.h 2007-08-22 23:57:58 +0300 >@@ -36,14 +36,15 @@ > #define CN_VAL_CIFS 0x1 > #define CN_W1_IDX 0x3 /* w1 communication */ > #define CN_W1_VAL 0x1 >+#define CN_IDX_V86D 0x4 >+#define CN_VAL_V86D_UVESAFB 0x1 > >- >-#define CN_NETLINK_USERS 4 >+#define CN_NETLINK_USERS 5 > > /* > * Maximum connector's message size. > */ >-#define CONNECTOR_MAX_MSG_SIZE 1024 >+#define CONNECTOR_MAX_MSG_SIZE 16384 > > /* > * idx and val are unique identifiers which >diff -urN kernel-source-2.6.18.orig/include/video/Kbuild kernel-source-2.6.18/include/video/Kbuild >--- kernel-source-2.6.18.orig/include/video/Kbuild 2006-09-20 06:42:06 +0300 >+++ kernel-source-2.6.18/include/video/Kbuild 2007-08-22 23:58:21 +0300 >@@ -1 +1 @@ >-unifdef-y += sisfb.h >+unifdef-y += sisfb.h uvesafb.h >diff -urN kernel-source-2.6.18.orig/include/video/uvesafb.h kernel-source-2.6.18/include/video/uvesafb.h >--- kernel-source-2.6.18.orig/include/video/uvesafb.h 1970-01-01 03:00:00 +0300 >+++ kernel-source-2.6.18/include/video/uvesafb.h 2007-08-22 23:57:58 +0300 >@@ -0,0 +1,193 @@ >+#ifndef _UVESAFB_H >+#define _UVESAFB_H >+ >+struct v86_regs { >+ __u32 ebx; >+ __u32 ecx; >+ __u32 edx; >+ __u32 esi; >+ __u32 edi; >+ __u32 ebp; >+ __u32 eax; >+ __u32 eip; >+ __u32 eflags; >+ __u32 esp; >+ __u16 cs; >+ __u16 ss; >+ __u16 es; >+ __u16 ds; >+ __u16 fs; >+ __u16 gs; >+}; >+ >+/* Task flags */ >+#define TF_VBEIB 0x01 >+#define TF_BUF_ESDI 0x02 >+#define TF_BUF_ESBX 0x04 >+#define TF_BUF_RET 0x08 >+#define TF_EXIT 0x10 >+ >+struct uvesafb_task { >+ __u8 flags; >+ int buf_len; >+ struct v86_regs regs; >+}; >+ >+/* Constants for the capabilities field >+ * in vbe_ib */ >+#define VBE_CAP_CAN_SWITCH_DAC 0x01 >+#define VBE_CAP_VGACOMPAT 0x02 >+ >+/* The VBE Info Block */ >+struct vbe_ib { >+ char vbe_signature[4]; >+ __u16 vbe_version; >+ __u32 oem_string_ptr; >+ __u32 capabilities; >+ __u32 mode_list_ptr; >+ __u16 total_memory; >+ __u16 oem_software_rev; >+ __u32 oem_vendor_name_ptr; >+ __u32 oem_product_name_ptr; >+ __u32 oem_product_rev_ptr; >+ __u8 reserved[222]; >+ char oem_data[256]; >+ char misc_data[512]; >+} __attribute__ ((packed)); >+ >+#ifdef __KERNEL__ >+ >+/* VBE CRTC Info Block */ >+struct vbe_crtc_ib { >+ u16 horiz_total; >+ u16 horiz_start; >+ u16 horiz_end; >+ u16 vert_total; >+ u16 vert_start; >+ u16 vert_end; >+ u8 flags; >+ u32 pixel_clock; >+ u16 refresh_rate; >+ u8 reserved[40]; >+} __attribute__ ((packed)); >+ >+#define VBE_MODE_VGACOMPAT 0x20 >+#define VBE_MODE_COLOR 0x08 >+#define VBE_MODE_SUPPORTEDHW 0x01 >+#define VBE_MODE_GRAPHICS 0x10 >+#define VBE_MODE_LFB 0x80 >+ >+#define VBE_MODE_MASK (VBE_MODE_COLOR | VBE_MODE_SUPPORTEDHW | \ >+ VBE_MODE_GRAPHICS | VBE_MODE_LFB) >+ >+/* VBE Mode Info Block */ >+struct vbe_mode_ib { >+ /* for all VBE revisions */ >+ u16 mode_attr; >+ u8 winA_attr; >+ u8 winB_attr; >+ u16 win_granularity; >+ u16 win_size; >+ u16 winA_seg; >+ u16 winB_seg; >+ u32 win_func_ptr; >+ u16 bytes_per_scan_line; >+ >+ /* for VBE 1.2+ */ >+ u16 x_res; >+ u16 y_res; >+ u8 x_char_size; >+ u8 y_char_size; >+ u8 planes; >+ u8 bits_per_pixel; >+ u8 banks; >+ u8 memory_model; >+ u8 bank_size; >+ u8 image_pages; >+ u8 reserved1; >+ >+ /* Direct color fields for direct/6 and YUV/7 memory models. */ >+ /* Offsets are bit positions of lsb in the mask. */ >+ u8 red_len; >+ u8 red_off; >+ u8 green_len; >+ u8 green_off; >+ u8 blue_len; >+ u8 blue_off; >+ u8 rsvd_len; >+ u8 rsvd_off; >+ u8 direct_color_info; /* direct color mode attributes */ >+ >+ /* for VBE 2.0+ */ >+ u32 phys_base_ptr; >+ u8 reserved2[6]; >+ >+ /* for VBE 3.0+ */ >+ u16 lin_bytes_per_scan_line; >+ u8 bnk_image_pages; >+ u8 lin_image_pages; >+ u8 lin_red_len; >+ u8 lin_red_off; >+ u8 lin_green_len; >+ u8 lin_green_off; >+ u8 lin_blue_len; >+ u8 lin_blue_off; >+ u8 lin_rsvd_len; >+ u8 lin_rsvd_off; >+ u32 max_pixel_clock; >+ u16 mode_id; >+ u8 depth; >+} __attribute__ ((packed)); >+ >+#define UVESAFB_DEFAULT_MODE "640x480-16" >+ >+/* How long to wait for a reply from userspace [ms] */ >+#define UVESAFB_TIMEOUT 5000 >+ >+/* Max number of concurrent tasks */ >+#define UVESAFB_TASKS_MAX 16 >+ >+#define dac_reg (0x3c8) >+#define dac_val (0x3c9) >+ >+struct uvesafb_pal_entry { >+ u_char blue, green, red, pad; >+} __attribute__ ((packed)); >+ >+struct uvesafb_ktask { >+ struct uvesafb_task t; >+ void *buf; >+ struct completion *done; >+ u32 ack; >+}; >+ >+static int uvesafb_exec(struct uvesafb_ktask *tsk); >+ >+#define UVESAFB_EXACT_RES 1 >+#define UVESAFB_EXACT_DEPTH 2 >+ >+struct uvesafb_par { >+ struct vbe_ib vbe_ib; /* VBE Info Block */ >+ struct vbe_mode_ib *vbe_modes; /* list of supported VBE modes */ >+ int vbe_modes_cnt; >+ >+ u8 nocrtc; >+ u8 ypan; /* 0 - nothing, 1 - ypan, 2 - ywrap */ >+ u8 pmi_setpal; /* PMI for palette changes */ >+ u16 *pmi_base; /* protected mode interface location */ >+ void *pmi_start; >+ void *pmi_pal; >+ u8 *vbe_state_orig; /* >+ * original hardware state, before the >+ * driver was loaded >+ */ >+ u8 *vbe_state_saved; /* state saved by fb_save_state */ >+ int vbe_state_size; >+ atomic_t ref_count; >+ >+ int mode_idx; >+ struct vbe_crtc_ib crtc; >+}; >+ >+#endif /* __KERNEL__ */ >+#endif /* _UVESAFB_H */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 12618
: 2161