|
Lines 33-38
Link Here
|
| 33 |
#define dac_reg (0x3c8) |
33 |
#define dac_reg (0x3c8) |
| 34 |
#define dac_val (0x3c9) |
34 |
#define dac_val (0x3c9) |
| 35 |
|
35 |
|
|
|
36 |
#define VESAFB_NEED_EXACT_RES 1 |
| 37 |
#define VESAFB_NEED_EXACT_DEPTH 2 |
| 38 |
|
| 36 |
/* --------------------------------------------------------------------- */ |
39 |
/* --------------------------------------------------------------------- */ |
| 37 |
|
40 |
|
| 38 |
static struct fb_var_screeninfo vesafb_defined __initdata = { |
41 |
static struct fb_var_screeninfo vesafb_defined __initdata = { |
|
Lines 75-81
Link Here
|
| 75 |
static unsigned short maxhf __initdata = 0; /* maximum horizontal frequency */ |
78 |
static unsigned short maxhf __initdata = 0; /* maximum horizontal frequency */ |
| 76 |
static int gtf __initdata = 0; /* forces use of the GTF */ |
79 |
static int gtf __initdata = 0; /* forces use of the GTF */ |
| 77 |
static char *mode_option __initdata = NULL; |
80 |
static char *mode_option __initdata = NULL; |
| 78 |
static unsigned short vbemode __initdata = 0; |
81 |
static unsigned short vbemode = 0; |
| 79 |
|
82 |
|
| 80 |
extern int vesafb_pid; /* PID of the vesafb service thread */ |
83 |
extern int vesafb_pid; /* PID of the vesafb service thread */ |
| 81 |
|
84 |
|
|
Lines 87-92
Link Here
|
| 87 |
#define vesafb_wait_for_task(task) { while (task->done == 0) { schedule(); } } |
90 |
#define vesafb_wait_for_task(task) { while (task->done == 0) { schedule(); } } |
| 88 |
|
91 |
|
| 89 |
extern void vesafb_queue_task(struct vesafb_task *task); |
92 |
extern void vesafb_queue_task(struct vesafb_task *task); |
|
|
93 |
static int vesafb_find_vbe_mode(int xres, int yres, int bpp, unsigned char flags); |
| 90 |
|
94 |
|
| 91 |
/* --------------------------------------------------------------------- */ |
95 |
/* --------------------------------------------------------------------- */ |
| 92 |
|
96 |
|
|
Lines 221-247
Link Here
|
| 221 |
struct vesafb_par *par = (struct vesafb_par *) info->par; |
225 |
struct vesafb_par *par = (struct vesafb_par *) info->par; |
| 222 |
struct vesafb_task *mytask; |
226 |
struct vesafb_task *mytask; |
| 223 |
struct vesafb_crtc_info_block *crtc = NULL; |
227 |
struct vesafb_crtc_info_block *crtc = NULL; |
| 224 |
struct vesafb_mode_info_block *mode = (void*)info->var.reserved[1]; |
228 |
struct vesafb_mode_info_block *mode = NULL; |
| 225 |
int err = 0; |
229 |
int err = 0, i; |
| 226 |
|
|
|
| 227 |
/* sanity check */ |
| 228 |
if (info->var.reserved[0] == 0xffff) |
| 229 |
return -EINVAL; |
| 230 |
|
230 |
|
|
|
231 |
/* has the VBE mode number been specified? */ |
| 232 |
if (vbemode > 0) { |
| 233 |
for (i = 0; i < vbe_modes_cnt; i++) { |
| 234 |
if (vbe_modes[i].mode_id == vbemode) { |
| 235 |
mode = &vbe_modes[i]; |
| 236 |
break; |
| 237 |
} |
| 238 |
} |
| 239 |
} else { |
| 240 |
i = vesafb_find_vbe_mode(info->var.xres, info->var.yres, |
| 241 |
info->var.bits_per_pixel, VESAFB_NEED_EXACT_RES | VESAFB_NEED_EXACT_DEPTH); |
| 242 |
if (i > 0) |
| 243 |
mode = &vbe_modes[i]; |
| 244 |
} |
| 245 |
|
| 246 |
if (mode == NULL) |
| 247 |
return -EINVAL; |
| 248 |
|
| 231 |
vesafb_create_task (mytask); |
249 |
vesafb_create_task (mytask); |
| 232 |
|
250 |
|
| 233 |
mytask->regs.eax = 0x4f02; |
251 |
mytask->regs.eax = 0x4f02; |
| 234 |
mytask->regs.ebx = (u16)info->var.reserved[0] | 0x4000; /* use LFB */ |
252 |
mytask->regs.ebx = mode->mode_id | 0x4000; /* use LFB */ |
| 235 |
|
253 |
|
| 236 |
if (vbe_ib.vbe_version >= 0x0300 && !nocrtc && |
254 |
if (vbe_ib.vbe_version >= 0x0300 && !nocrtc && !vbemode) { |
| 237 |
info->var.reserved[2] != 0xdeadbeef) { |
|
|
| 238 |
|
255 |
|
| 239 |
mytask->regs.ebx |= 0x0800; /* use CRTC data */ |
256 |
mytask->regs.ebx |= 0x0800; /* use CRTC data */ |
| 240 |
crtc = kmalloc(sizeof(struct vesafb_crtc_info_block), GFP_KERNEL); |
257 |
crtc = kmalloc(sizeof(struct vesafb_crtc_info_block), GFP_KERNEL); |
| 241 |
|
258 |
|
| 242 |
if (!crtc) { |
259 |
if (!crtc) { |
| 243 |
err = -ENOMEM; |
260 |
err = -ENOMEM; |
| 244 |
goto sp_end; |
261 |
goto out; |
| 245 |
} |
262 |
} |
| 246 |
crtc->horiz_start = info->var.xres + info->var.right_margin; |
263 |
crtc->horiz_start = info->var.xres + info->var.right_margin; |
| 247 |
crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; |
264 |
crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; |
|
Lines 277-287
Link Here
|
| 277 |
vesafb_queue_task (mytask); |
294 |
vesafb_queue_task (mytask); |
| 278 |
vesafb_wait_for_task(mytask); |
295 |
vesafb_wait_for_task(mytask); |
| 279 |
|
296 |
|
| 280 |
if (mytask->regs.eax != 0x004f) { |
297 |
if ((mytask->regs.eax & 0xffff) != 0x004f) { |
| 281 |
printk(KERN_ERR "vesafb: mode switch failed (eax: 0x%lx)\n", mytask->regs.eax); |
298 |
printk(KERN_ERR "vesafb: mode switch failed (eax: 0x%lx)\n", mytask->regs.eax); |
| 282 |
err = -EINVAL; |
299 |
err = -EINVAL; |
| 283 |
goto sp_end; |
300 |
goto out; |
| 284 |
} |
301 |
} |
|
|
302 |
|
| 303 |
/* the VBE mode number is valid only the first time the mode is set */ |
| 304 |
if (vbemode) |
| 305 |
vbemode = 0; |
| 285 |
|
306 |
|
| 286 |
if (vbe_ib.capabilities & VESAFB_CAP_CAN_SWITCH_DAC && mode->bits_per_pixel <= 8) { |
307 |
if (vbe_ib.capabilities & VESAFB_CAP_CAN_SWITCH_DAC && mode->bits_per_pixel <= 8) { |
| 287 |
mytask->done = 0; |
308 |
mytask->done = 0; |
|
Lines 304-323
Link Here
|
| 304 |
|
325 |
|
| 305 |
info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
326 |
info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
| 306 |
info->fix.line_length = mode->bytes_per_scan_line; |
327 |
info->fix.line_length = mode->bytes_per_scan_line; |
| 307 |
par->vbe_mode = info->var.reserved[0]; |
328 |
par->vbe_mode = mode->mode_id; |
| 308 |
|
329 |
|
| 309 |
DPRINTK("set new mode %dx%d-%d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); |
330 |
DPRINTK("set new mode %dx%d-%d (0x%x)\n", info->var.xres, info->var.yres, info->var.bits_per_pixel, mode->mode_id); |
| 310 |
|
331 |
|
| 311 |
sp_end: |
332 |
out: if (crtc != NULL) |
| 312 |
if (crtc != NULL) |
|
|
| 313 |
kfree(crtc); |
333 |
kfree(crtc); |
| 314 |
kfree(mytask); |
334 |
kfree(mytask); |
| 315 |
|
335 |
|
| 316 |
return err; |
336 |
return err; |
| 317 |
} |
337 |
} |
| 318 |
|
338 |
|
| 319 |
void vesafb_setup_var(struct fb_var_screeninfo *var, struct vesafb_mode_info_block *mode) |
339 |
static void vesafb_setup_var(struct fb_var_screeninfo *var, struct fb_info *info, |
|
|
340 |
struct vesafb_mode_info_block *mode) |
| 320 |
{ |
341 |
{ |
|
|
342 |
var->xres = mode->x_res; |
| 343 |
var->yres = mode->y_res; |
| 344 |
var->xres_virtual = mode->x_res; |
| 345 |
var->yres_virtual = info->fix.smem_len / mode->bytes_per_scan_line; |
| 346 |
var->xoffset = 0; |
| 347 |
var->yoffset = 0; |
| 348 |
var->bits_per_pixel = mode->bits_per_pixel; |
| 349 |
|
| 321 |
if (var->bits_per_pixel == 15) |
350 |
if (var->bits_per_pixel == 15) |
| 322 |
var->bits_per_pixel = 16; |
351 |
var->bits_per_pixel = 16; |
| 323 |
|
352 |
|
|
Lines 362-368
Link Here
|
| 362 |
} |
391 |
} |
| 363 |
} |
392 |
} |
| 364 |
|
393 |
|
| 365 |
int inline vesafb_check_limits(struct fb_var_screeninfo *var, struct fb_info *info) |
394 |
static int inline vesafb_check_limits(struct fb_var_screeninfo *var, struct fb_info *info) |
| 366 |
{ |
395 |
{ |
| 367 |
if (mon_limits) |
396 |
if (mon_limits) |
| 368 |
return fb_validate_mode(var, info); |
397 |
return fb_validate_mode(var, info); |
|
Lines 370-428
Link Here
|
| 370 |
return 0; |
399 |
return 0; |
| 371 |
} |
400 |
} |
| 372 |
|
401 |
|
| 373 |
int vesafb_find_vbe_mode(int xres, int yres, int bpp, unsigned char flags) |
402 |
static int vesafb_find_vbe_mode(int xres, int yres, int bpp, unsigned char flags) |
| 374 |
{ |
403 |
{ |
| 375 |
int match = -1; |
404 |
int i, match = -1, h = 0, d = 0x7fffffff; |
| 376 |
int i; |
|
|
| 377 |
|
405 |
|
| 378 |
DPRINTK("looking for mode: %dx%d-%d\n", xres, yres, bpp); |
|
|
| 379 |
|
| 380 |
/* first try to find the exact mode the user wants to set.. */ |
| 381 |
for (i = 0; i < vbe_modes_cnt; i++) { |
406 |
for (i = 0; i < vbe_modes_cnt; i++) { |
| 382 |
|
407 |
|
| 383 |
if (vbe_modes[i].x_res == xres && vbe_modes[i].y_res == yres) { |
408 |
h = abs(vbe_modes[i].x_res - xres) + abs(vbe_modes[i].y_res - yres) + |
| 384 |
|
409 |
(bpp - vbe_modes[i].bits_per_pixel); |
| 385 |
int h = bpp - vbe_modes[i].bits_per_pixel; |
|
|
| 386 |
|
| 387 |
/* ok, we've got an exact match */ |
| 388 |
if (h == 0) |
| 389 |
return i; |
| 390 |
|
| 391 |
if (match == -1 || (bpp - vbe_modes[match].bits_per_pixel) > h) |
| 392 |
match = i; |
| 393 |
} |
| 394 |
} |
| 395 |
|
| 396 |
/* .. and if this fails look for similar modes */ |
| 397 |
if (match == -1 && flags) { |
| 398 |
|
| 399 |
unsigned int min = 0xffffffff; /* just a big number */ |
| 400 |
unsigned int d; |
| 401 |
|
| 402 |
DPRINTK("mode not found (1st pass)\n"); |
| 403 |
|
| 404 |
for (i = 0; i < vbe_modes_cnt; i++) { |
| 405 |
|
410 |
|
| 406 |
if (vbe_modes[i].y_res < yres || vbe_modes[i].x_res < xres) |
411 |
if (h == 0) |
| 407 |
continue; |
412 |
return i; |
| 408 |
|
413 |
|
| 409 |
d = vbe_modes[i].y_res - yres + vbe_modes[i].x_res - xres; |
414 |
if (h < d) { |
| 410 |
|
415 |
d = h; |
| 411 |
if (d < min) { |
416 |
match = i; |
| 412 |
min = d; |
|
|
| 413 |
match = i; |
| 414 |
} |
| 415 |
|
| 416 |
if (d == min && (bpp - vbe_modes[match].bits_per_pixel) > |
| 417 |
(bpp - vbe_modes[i].bits_per_pixel)) |
| 418 |
match = i; |
| 419 |
} |
417 |
} |
| 420 |
} |
418 |
} |
| 421 |
|
419 |
|
|
|
420 |
if (!(flags & VESAFB_NEED_EXACT_DEPTH) && d <= 24) |
| 421 |
return match; |
| 422 |
|
| 423 |
if (flags & VESAFB_NEED_EXACT_RES) |
| 424 |
return -1; |
| 425 |
|
| 422 |
return match; |
426 |
return match; |
| 423 |
} |
427 |
} |
| 424 |
|
428 |
|
| 425 |
int vesafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
429 |
static int vesafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
| 426 |
{ |
430 |
{ |
| 427 |
int match = -1; |
431 |
int match = -1; |
| 428 |
|
432 |
|
|
Lines 433-453
Link Here
|
| 433 |
if (var->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE)) |
437 |
if (var->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE)) |
| 434 |
return -EINVAL; |
438 |
return -EINVAL; |
| 435 |
|
439 |
|
| 436 |
match = vesafb_find_vbe_mode(var->xres, var->yres, var->bits_per_pixel, (vbe_ib.vbe_version >= 0x300) ? 1 : 0); |
440 |
match = vesafb_find_vbe_mode(var->xres, var->yres, var->bits_per_pixel, VESAFB_NEED_EXACT_RES); |
| 437 |
|
441 |
|
| 438 |
if (match == -1) { |
442 |
if (match == -1) { |
| 439 |
printk(KERN_ERR "vesafb: mode %dx%d-%d@%d not found\n", var->xres, var->yres, var->bits_per_pixel, |
443 |
printk(KERN_ERR "vesafb: mode %dx%d-%d@%d not found\n", var->xres, var->yres, var->bits_per_pixel, |
| 440 |
(int)(PICOS2KHZ(info->var.pixclock) / |
444 |
(int)(PICOS2KHZ(info->var.pixclock) / |
| 441 |
((info->var.xres + info->var.right_margin + info->var.hsync_len + info->var.left_margin) * |
445 |
((info->var.xres + info->var.right_margin + info->var.hsync_len + info->var.left_margin) * |
| 442 |
(info->var.yres + info->var.lower_margin + info->var.vsync_len + info->var.upper_margin))) * 1000); |
446 |
(info->var.yres + info->var.lower_margin + info->var.vsync_len + info->var.upper_margin))) * 1000); |
| 443 |
var->reserved[0] = 0xffff; |
|
|
| 444 |
return -EINVAL; |
447 |
return -EINVAL; |
| 445 |
} else { |
448 |
} else { |
| 446 |
var->bits_per_pixel = vbe_modes[match].bits_per_pixel; |
449 |
var->bits_per_pixel = vbe_modes[match].bits_per_pixel; |
| 447 |
var->reserved[0] = (u32)vbe_modes[match].mode_id; |
450 |
vesafb_setup_var(var, info, &vbe_modes[match]); |
| 448 |
var->reserved[1] = (u32)(&vbe_modes[match]); |
|
|
| 449 |
var->reserved[2] = 0x0; |
| 450 |
vesafb_setup_var(var, &vbe_modes[match]); |
| 451 |
|
451 |
|
| 452 |
DPRINTK("found mode 0x%x (%dx%d-%dbpp)\n", |
452 |
DPRINTK("found mode 0x%x (%dx%d-%dbpp)\n", |
| 453 |
vbe_modes[match].mode_id, vbe_modes[match].x_res, vbe_modes[match].y_res, |
453 |
vbe_modes[match].mode_id, vbe_modes[match].x_res, vbe_modes[match].y_res, |
|
Lines 589-597
Link Here
|
| 589 |
{ |
589 |
{ |
| 590 |
struct vesafb_task *mytask; |
590 |
struct vesafb_task *mytask; |
| 591 |
u16 *mode = 0; |
591 |
u16 *mode = 0; |
| 592 |
int off = 0; |
592 |
int i, off = 0; |
| 593 |
int i; |
593 |
|
| 594 |
|
|
|
| 595 |
vesafb_create_task (mytask); |
594 |
vesafb_create_task (mytask); |
| 596 |
mytask->regs.eax = 0x4f00; |
595 |
mytask->regs.eax = 0x4f00; |
| 597 |
mytask->type = VESAFB_TASK_GETVBE_IB; |
596 |
mytask->type = VESAFB_TASK_GETVBE_IB; |
|
Lines 605-611
Link Here
|
| 605 |
return 1; |
604 |
return 1; |
| 606 |
} |
605 |
} |
| 607 |
|
606 |
|
| 608 |
if (mytask->regs.eax != 0x004F) { |
607 |
if ((mytask->regs.eax & 0xffff) != 0x004f) { |
| 609 |
printk(KERN_ERR "vesafb: Getting mode info block failed (eax=0x%x)\n",(u32)mytask->regs.eax); |
608 |
printk(KERN_ERR "vesafb: Getting mode info block failed (eax=0x%x)\n",(u32)mytask->regs.eax); |
| 610 |
kfree(mytask); |
609 |
kfree(mytask); |
| 611 |
return 1; |
610 |
return 1; |
|
Lines 660-666
Link Here
|
| 660 |
vesafb_queue_task(mytask); |
659 |
vesafb_queue_task(mytask); |
| 661 |
vesafb_wait_for_task(mytask); |
660 |
vesafb_wait_for_task(mytask); |
| 662 |
|
661 |
|
| 663 |
if (mytask->regs.eax != 0x004f || mytask->regs.es < 0xc000) { |
662 |
if ((mytask->regs.eax & 0xffff) != 0x004f || mytask->regs.es < 0xc000) { |
| 664 |
pmi_setpal = ypan = 0; |
663 |
pmi_setpal = ypan = 0; |
| 665 |
} else { |
664 |
} else { |
| 666 |
printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", (u16)mytask->regs.es, (u16)mytask->regs.edi); |
665 |
printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", (u16)mytask->regs.es, (u16)mytask->regs.edi); |
|
Lines 689-695
Link Here
|
| 689 |
} |
688 |
} |
| 690 |
|
689 |
|
| 691 |
if (noedid || vbe_ib.vbe_version < 0x0300) |
690 |
if (noedid || vbe_ib.vbe_version < 0x0300) |
| 692 |
goto vi_1; |
691 |
goto set_monspecs; |
| 693 |
|
692 |
|
| 694 |
mytask->regs.eax = 0x4f15; |
693 |
mytask->regs.eax = 0x4f15; |
| 695 |
mytask->regs.ebx = 0; |
694 |
mytask->regs.ebx = 0; |
|
Lines 699-706
Link Here
|
| 699 |
vesafb_queue_task(mytask); |
698 |
vesafb_queue_task(mytask); |
| 700 |
vesafb_wait_for_task(mytask); |
699 |
vesafb_wait_for_task(mytask); |
| 701 |
|
700 |
|
| 702 |
if (mytask->regs.eax != 0x004f) |
701 |
if ((mytask->regs.eax & 0xffff) != 0x004f) |
| 703 |
goto vi_1; |
702 |
goto set_monspecs; |
| 704 |
|
703 |
|
| 705 |
if ((mytask->regs.ebx & 0x3) == 3) { |
704 |
if ((mytask->regs.ebx & 0x3) == 3) { |
| 706 |
printk(KERN_INFO "vesafb: hardware supports both DCC1 and DCC2 transfers\n"); |
705 |
printk(KERN_INFO "vesafb: hardware supports both DCC1 and DCC2 transfers\n"); |
|
Lines 710-716
Link Here
|
| 710 |
printk(KERN_INFO "vesafb: hardware supports DCC1 transfers\n"); |
709 |
printk(KERN_INFO "vesafb: hardware supports DCC1 transfers\n"); |
| 711 |
} else { |
710 |
} else { |
| 712 |
printk(KERN_INFO "vesafb: hardware doesn't support DCC transfers\n"); |
711 |
printk(KERN_INFO "vesafb: hardware doesn't support DCC transfers\n"); |
| 713 |
goto vi_1; |
712 |
goto set_monspecs; |
| 714 |
} |
713 |
} |
| 715 |
|
714 |
|
| 716 |
mytask->regs.eax = 0x4f15; |
715 |
mytask->regs.eax = 0x4f15; |
|
Lines 722-728
Link Here
|
| 722 |
vesafb_queue_task(mytask); |
721 |
vesafb_queue_task(mytask); |
| 723 |
vesafb_wait_for_task(mytask); |
722 |
vesafb_wait_for_task(mytask); |
| 724 |
|
723 |
|
| 725 |
if (mytask->regs.eax == 0x004F) { |
724 |
if ((mytask->regs.eax & 0xffff) == 0x004f) { |
| 726 |
|
725 |
|
| 727 |
mon_limits = !fb_get_monitor_limits(mytask->res, &info->monspecs); |
726 |
mon_limits = !fb_get_monitor_limits(mytask->res, &info->monspecs); |
| 728 |
|
727 |
|
|
Lines 735-741
Link Here
|
| 735 |
} |
734 |
} |
| 736 |
kfree(mytask->res); |
735 |
kfree(mytask->res); |
| 737 |
|
736 |
|
| 738 |
vi_1: |
737 |
set_monspecs: |
| 739 |
if (maxclk) |
738 |
if (maxclk) |
| 740 |
info->monspecs.dclkmax = maxclk * 1000000; |
739 |
info->monspecs.dclkmax = maxclk * 1000000; |
| 741 |
|
740 |
|
|
Lines 761-773
Link Here
|
| 761 |
return 0; |
760 |
return 0; |
| 762 |
} |
761 |
} |
| 763 |
|
762 |
|
|
|
763 |
static int __init decode_mode(u32 *xres, u32 *yres, u32 *bpp, u32 *refresh) |
| 764 |
{ |
| 765 |
int len = strlen(mode_option), i, err = 0; |
| 766 |
u8 res_specified = 0, bpp_specified = 0, refresh_specified = 0, |
| 767 |
yres_specified = 0; |
| 768 |
|
| 769 |
for (i = len-1; i >= 0; i--) { |
| 770 |
switch (mode_option[i]) { |
| 771 |
case '@': |
| 772 |
len = i; |
| 773 |
if (!refresh_specified && !bpp_specified && |
| 774 |
!yres_specified) { |
| 775 |
*refresh = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 776 |
refresh_specified = 1; |
| 777 |
} else |
| 778 |
goto out; |
| 779 |
break; |
| 780 |
case '-': |
| 781 |
len = i; |
| 782 |
if (!bpp_specified && !yres_specified) { |
| 783 |
*bpp = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 784 |
bpp_specified = 1; |
| 785 |
} else |
| 786 |
goto out; |
| 787 |
break; |
| 788 |
case 'x': |
| 789 |
if (!yres_specified) { |
| 790 |
*yres = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 791 |
yres_specified = 1; |
| 792 |
} else |
| 793 |
goto out; |
| 794 |
break; |
| 795 |
case '0'...'9': |
| 796 |
break; |
| 797 |
default: |
| 798 |
goto out; |
| 799 |
} |
| 800 |
} |
| 801 |
|
| 802 |
if (i < 0 && yres_specified) { |
| 803 |
*xres = simple_strtoul(mode_option, NULL, 0); |
| 804 |
res_specified = 1; |
| 805 |
} |
| 806 |
|
| 807 |
out: if (!res_specified || !yres_specified) { |
| 808 |
printk(KERN_ERR "vesafb: invalid resolution, %s not specified\n", |
| 809 |
(!res_specified) ? "width" : "height"); |
| 810 |
err = -EINVAL; |
| 811 |
} |
| 812 |
|
| 813 |
return err; |
| 814 |
} |
| 815 |
|
| 816 |
static int __init vesafb_init_set_mode(struct fb_info *info) |
| 817 |
{ |
| 818 |
char buf[32]; |
| 819 |
int i, modeid, refresh = 0; |
| 820 |
u8 refresh_specified = 0; |
| 821 |
|
| 822 |
if (!mode_option) |
| 823 |
mode_option = CONFIG_FB_VESA_DEFAULT_MODE; |
| 824 |
|
| 825 |
if (vbemode > 0) { |
| 826 |
for (i = 0; i < vbe_modes_cnt; i++) { |
| 827 |
if (vbe_modes[i].mode_id == vbemode) { |
| 828 |
info->var.vmode = FB_VMODE_NONINTERLACED; |
| 829 |
info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 830 |
vesafb_setup_var(&info->var, info, &vbe_modes[i]); |
| 831 |
fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &info->var, info); |
| 832 |
return i; |
| 833 |
} |
| 834 |
} |
| 835 |
|
| 836 |
printk(KERN_INFO "specified VBE mode %d not found\n",vbemode); |
| 837 |
} |
| 838 |
|
| 839 |
if (decode_mode(&info->var.xres, &info->var.yres, |
| 840 |
&info->var.bits_per_pixel, &refresh)) |
| 841 |
return -EINVAL; |
| 842 |
|
| 843 |
if (refresh) |
| 844 |
refresh_specified = 1; |
| 845 |
else |
| 846 |
refresh = 60; |
| 847 |
|
| 848 |
modeid = vesafb_find_vbe_mode(info->var.xres, info->var.yres, info->var.bits_per_pixel, 0); |
| 849 |
|
| 850 |
if (modeid == -1) { |
| 851 |
return -EINVAL; |
| 852 |
} else { |
| 853 |
info->var.vmode = FB_VMODE_NONINTERLACED; |
| 854 |
info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 855 |
vesafb_setup_var(&info->var, info, &vbe_modes[modeid]); |
| 856 |
} |
| 857 |
|
| 858 |
if (gtf) |
| 859 |
goto timings_gtf; |
| 860 |
|
| 861 |
sprintf(buf, "%dx%d-%d@%d", info->var.xres, info->var.yres, info->var.bits_per_pixel, refresh); |
| 862 |
i = fb_find_mode(&info->var, info, buf, vesa_modes, VESA_MODEDB_SIZE, NULL, 0); |
| 863 |
DPRINTK("fb_find_mode returned %d\n", i); |
| 864 |
|
| 865 |
if (i == 1 || (i == 2 && vbe_ib.vbe_version < 0x0300)) |
| 866 |
return modeid; |
| 867 |
|
| 868 |
if (edid_modes != NULL && !gtf) { |
| 869 |
DPRINTK("looking for EDID modes\n"); |
| 870 |
|
| 871 |
for (i = 0; i < edid_modes_cnt; i++) { |
| 872 |
|
| 873 |
if (edid_modes[i].xres == info->var.xres && |
| 874 |
edid_modes[i].yres == info->var.yres && |
| 875 |
abs(edid_modes[i].refresh - refresh) < 5) { |
| 876 |
|
| 877 |
info->var.pixclock = edid_modes[i].pixclock; |
| 878 |
info->var.left_margin = edid_modes[i].left_margin; |
| 879 |
info->var.right_margin = edid_modes[i].right_margin; |
| 880 |
info->var.upper_margin = edid_modes[i].upper_margin; |
| 881 |
info->var.lower_margin = edid_modes[i].lower_margin; |
| 882 |
info->var.hsync_len = edid_modes[i].hsync_len; |
| 883 |
info->var.vsync_len = edid_modes[i].vsync_len; |
| 884 |
info->var.sync = edid_modes[i].sync; |
| 885 |
info->var.vmode = edid_modes[i].vmode; |
| 886 |
DPRINTK("using EDID-provided mode\n"); |
| 887 |
return modeid; |
| 888 |
} |
| 889 |
} |
| 890 |
} |
| 891 |
|
| 892 |
timings_gtf: |
| 893 |
if (refresh_specified) |
| 894 |
i = FB_VSYNCTIMINGS; |
| 895 |
else |
| 896 |
i = FB_MAXTIMINGS; |
| 897 |
|
| 898 |
if (vbe_ib.vbe_version < 0x0300) { |
| 899 |
i = FB_VSYNCTIMINGS | FB_IGNOREMON; |
| 900 |
refresh = 60; |
| 901 |
} |
| 902 |
|
| 903 |
if (!mon_limits) |
| 904 |
i |= FB_IGNOREMON; |
| 905 |
|
| 906 |
if (!fb_get_mode(i, refresh, &info->var, info)) |
| 907 |
return modeid; |
| 908 |
|
| 909 |
printk(KERN_WARNING "vesafb: trying maximum allowed refresh rate\n"); |
| 910 |
|
| 911 |
if (i & FB_VSYNCTIMINGS && refresh > 60 && mon_limits) { |
| 912 |
if (!fb_get_mode(FB_MAXTIMINGS, refresh, &info->var, info)) |
| 913 |
return modeid; |
| 914 |
} |
| 915 |
|
| 916 |
printk(KERN_WARNING "vesafb: using default BIOS refresh rate\n"); |
| 917 |
vbemode = vbe_modes[modeid].mode_id; |
| 918 |
|
| 919 |
return modeid; |
| 920 |
} |
| 921 |
|
| 764 |
static int __init vesafb_probe(struct device *device) |
922 |
static int __init vesafb_probe(struct device *device) |
| 765 |
{ |
923 |
{ |
| 766 |
char entry[16]; |
924 |
char entry[16]; |
| 767 |
struct platform_device *dev = to_platform_device(device); |
925 |
struct platform_device *dev = to_platform_device(device); |
| 768 |
struct fb_info *info; |
926 |
struct fb_info *info; |
| 769 |
int err = 0, i; |
927 |
int err = 0, i; |
| 770 |
|
928 |
|
| 771 |
vesafb_info = info = framebuffer_alloc(sizeof(struct vesafb_par) + sizeof(u32) * 256, &dev->dev); |
929 |
vesafb_info = info = framebuffer_alloc(sizeof(struct vesafb_par) + sizeof(u32) * 256, &dev->dev); |
| 772 |
|
930 |
|
| 773 |
if (!info) |
931 |
if (!info) |
|
Lines 776-793
Link Here
|
| 776 |
if (vesafb_pid) |
934 |
if (vesafb_pid) |
| 777 |
vesafb_serv_thread = find_task_by_pid(vesafb_pid); |
935 |
vesafb_serv_thread = find_task_by_pid(vesafb_pid); |
| 778 |
else { |
936 |
else { |
| 779 |
printk(KERN_ERR "vesafb: vesafb thread not running - returning..\n"); |
937 |
printk(KERN_ERR "vesafb: vesafb thread not running\n"); |
| 780 |
framebuffer_release(info); |
938 |
framebuffer_release(info); |
| 781 |
return -EINVAL; |
939 |
return -EINVAL; |
| 782 |
} |
940 |
} |
| 783 |
|
941 |
|
| 784 |
if (vesafb_vbe_init(info)) { |
942 |
if (vesafb_vbe_init(info)) { |
| 785 |
printk(KERN_ERR "vesafb: vbe_init failed - returning..\n"); |
943 |
printk(KERN_ERR "vesafb: vbe_init failed\n"); |
| 786 |
err = -EINVAL; |
944 |
err = -EINVAL; |
| 787 |
goto pr_err; |
945 |
goto out; |
| 788 |
} |
946 |
} |
| 789 |
|
947 |
|
| 790 |
vesafb_fix.smem_len = vbe_ib.total_memory * 65536; |
948 |
vesafb_fix.smem_len = vbe_ib.total_memory * 65536; |
| 791 |
vesafb_fix.ypanstep = ypan ? 1 : 0; |
949 |
vesafb_fix.ypanstep = ypan ? 1 : 0; |
| 792 |
vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; |
950 |
vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; |
| 793 |
|
951 |
|
|
Lines 811-972
Link Here
|
| 811 |
|
969 |
|
| 812 |
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
970 |
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
| 813 |
err = -ENXIO; |
971 |
err = -ENXIO; |
| 814 |
goto pr_err; |
972 |
goto out; |
| 815 |
} |
973 |
} |
| 816 |
|
974 |
|
| 817 |
if (!mode_option) |
975 |
i = vesafb_init_set_mode(info); |
| 818 |
mode_option = CONFIG_FB_VESA_DEFAULT_MODE; |
976 |
if (i < 0) |
| 819 |
|
977 |
goto out_cmap; |
| 820 |
if (vbemode > 0) { |
|
|
| 821 |
for (i = 0; i < vbe_modes_cnt; i++) { |
| 822 |
if (vbe_modes[i].mode_id == vbemode) { |
| 823 |
info->var.xres = vbe_modes[i].x_res; |
| 824 |
info->var.yres = vbe_modes[i].y_res; |
| 825 |
info->var.xres_virtual = vbe_modes[i].x_res; |
| 826 |
info->var.xoffset = 0; |
| 827 |
info->var.yoffset = 0; |
| 828 |
info->var.bits_per_pixel = vbe_modes[i].bits_per_pixel; |
| 829 |
info->var.reserved[0] = (u32)vbe_modes[i].mode_id; |
| 830 |
info->var.reserved[1] = (u32)(&vbe_modes[i]); |
| 831 |
info->var.reserved[2] = 0xdeadbeef; |
| 832 |
info->var.vmode = FB_VMODE_NONINTERLACED; |
| 833 |
info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 834 |
vesafb_setup_var(&info->var, &vbe_modes[i]); |
| 835 |
fb_get_mode(FB_MAXTIMINGS, 60, &info->var, info); |
| 836 |
goto pr_end; |
| 837 |
} |
| 838 |
} |
| 839 |
|
978 |
|
| 840 |
printk(KERN_INFO "specified VBE mode %d not found\n",vbemode); |
979 |
info->fix.smem_start = vbe_modes[i].phys_base_ptr; |
| 841 |
} |
|
|
| 842 |
|
| 843 |
if (gtf) |
| 844 |
goto pr_manual; |
| 845 |
|
| 846 |
i = fb_find_mode(&info->var, info, mode_option, vesa_modes, 33, NULL, 0); |
| 847 |
|
| 848 |
DPRINTK("fb_find_mode returned %d\n", i); |
| 849 |
|
| 850 |
if (i == 0 || i >= 3) |
| 851 |
pr_manual: |
| 852 |
{ |
| 853 |
int match = -1; |
| 854 |
unsigned int len = strlen(mode_option); |
| 855 |
unsigned int xres = 0, yres = 0, bpp = 8, refresh = 60; |
| 856 |
unsigned char res_specified = 0, bpp_specified = 0, refresh_specified = 0, yres_specified = 0; |
| 857 |
|
| 858 |
for (i = len-1; i >= 0; i--) { |
| 859 |
switch (mode_option[i]) { |
| 860 |
case '@': |
| 861 |
len = i; |
| 862 |
if (!refresh_specified && !bpp_specified && |
| 863 |
!yres_specified) { |
| 864 |
refresh = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 865 |
refresh_specified = 1; |
| 866 |
} else |
| 867 |
goto pr_modedone; |
| 868 |
break; |
| 869 |
case '-': |
| 870 |
len = i; |
| 871 |
if (!bpp_specified && !yres_specified) { |
| 872 |
bpp = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 873 |
bpp_specified = 1; |
| 874 |
} else |
| 875 |
goto pr_modedone; |
| 876 |
break; |
| 877 |
case 'x': |
| 878 |
if (!yres_specified) { |
| 879 |
yres = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 880 |
yres_specified = 1; |
| 881 |
} else |
| 882 |
goto pr_modedone; |
| 883 |
break; |
| 884 |
case '0'...'9': |
| 885 |
break; |
| 886 |
default: |
| 887 |
goto pr_modedone; |
| 888 |
} |
| 889 |
} |
| 890 |
|
| 891 |
if (i < 0 && yres_specified) { |
| 892 |
xres = simple_strtoul(mode_option, NULL, 0); |
| 893 |
res_specified = 1; |
| 894 |
} |
| 895 |
|
| 896 |
pr_modedone: if (!res_specified || !yres_specified) { |
| 897 |
printk(KERN_ERR "vesafb: invalid resolution, %s not specified\n", |
| 898 |
(!res_specified) ? "width" : "height"); |
| 899 |
err = -EINVAL; |
| 900 |
goto pr_err1; |
| 901 |
} |
| 902 |
|
| 903 |
match = vesafb_find_vbe_mode(xres, yres, bpp, (vbe_ib.vbe_version >= 0x300) ? 1 : 0); |
| 904 |
|
| 905 |
if (match == -1) { |
| 906 |
printk(KERN_ERR "vesafb: no matching VBE mode found\n"); |
| 907 |
err = -EINVAL; |
| 908 |
goto pr_err1; |
| 909 |
} |
| 910 |
|
| 911 |
info->var.xres = xres; |
| 912 |
info->var.yres = yres; |
| 913 |
info->var.xres_virtual = xres; |
| 914 |
info->var.xoffset = 0; |
| 915 |
info->var.yoffset = 0; |
| 916 |
info->var.bits_per_pixel = vbe_modes[match].bits_per_pixel; |
| 917 |
info->var.reserved[0] = (u32)vbe_modes[match].mode_id; |
| 918 |
info->var.reserved[1] = (u32)(&vbe_modes[match]); |
| 919 |
info->var.reserved[2] = 0x0; |
| 920 |
info->var.vmode = FB_VMODE_NONINTERLACED; |
| 921 |
info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 922 |
vesafb_setup_var(&info->var, &vbe_modes[match]); |
| 923 |
|
| 924 |
if (edid_modes != NULL && !gtf) { |
| 925 |
|
| 926 |
DPRINTK("looking for EDID modes\n"); |
| 927 |
|
| 928 |
for (i = 0; i < edid_modes_cnt; i++) { |
| 929 |
|
| 930 |
if (edid_modes[i].xres == xres && edid_modes[i].yres == yres && |
| 931 |
edid_modes[i].refresh - refresh < 5 && edid_modes[i].refresh - refresh > -5) { |
| 932 |
|
| 933 |
info->var.pixclock = edid_modes[i].pixclock; |
| 934 |
info->var.left_margin = edid_modes[i].left_margin; |
| 935 |
info->var.right_margin = edid_modes[i].right_margin; |
| 936 |
info->var.upper_margin = edid_modes[i].upper_margin; |
| 937 |
info->var.lower_margin = edid_modes[i].lower_margin; |
| 938 |
info->var.hsync_len = edid_modes[i].hsync_len; |
| 939 |
info->var.vsync_len = edid_modes[i].vsync_len; |
| 940 |
info->var.sync = edid_modes[i].sync; |
| 941 |
info->var.vmode = edid_modes[i].vmode; |
| 942 |
DPRINTK("using EDID-provided mode\n"); |
| 943 |
goto pr_end; |
| 944 |
} |
| 945 |
} |
| 946 |
} |
| 947 |
|
| 948 |
if (refresh_specified) |
| 949 |
i = FB_VSYNCTIMINGS; |
| 950 |
else |
| 951 |
i = FB_MAXTIMINGS; |
| 952 |
|
| 953 |
if (vbe_ib.vbe_version < 0x0300) { |
| 954 |
i = FB_VSYNCTIMINGS | FB_IGNOREMON; |
| 955 |
refresh = 60; |
| 956 |
} |
| 957 |
|
| 958 |
if (!mon_limits) |
| 959 |
i |= FB_IGNOREMON; |
| 960 |
|
| 961 |
if (fb_get_mode(i, refresh, &info->var, info) != 0) { |
| 962 |
printk(KERN_ERR "vesafb: fb_get_mode failed, try a different refresh rate.\n"); |
| 963 |
err = -EINVAL; |
| 964 |
goto pr_err1; |
| 965 |
} |
| 966 |
} |
| 967 |
pr_end: |
| 968 |
info->var.yres_virtual = info->fix.smem_len / ((struct vesafb_mode_info_block*)info->var.reserved[1])->bytes_per_scan_line; |
| 969 |
info->fix.smem_start = ((struct vesafb_mode_info_block*)info->var.reserved[1])->phys_base_ptr; |
| 970 |
|
980 |
|
| 971 |
if (ypan && info->var.yres_virtual > info->var.yres) { |
981 |
if (ypan && info->var.yres_virtual > info->var.yres) { |
| 972 |
printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", |
982 |
printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", |
|
Lines 993-999
Link Here
|
| 993 |
"vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", |
1003 |
"vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", |
| 994 |
info->fix.smem_len, info->fix.smem_start); |
1004 |
info->fix.smem_len, info->fix.smem_start); |
| 995 |
err = -EIO; |
1005 |
err = -EIO; |
| 996 |
goto pr_err2; |
1006 |
goto out_mem; |
| 997 |
} |
1007 |
} |
| 998 |
|
1008 |
|
| 999 |
/* request failure does not faze us, as vgacon probably has this |
1009 |
/* request failure does not faze us, as vgacon probably has this |
|
Lines 1016-1022
Link Here
|
| 1016 |
if (register_framebuffer(info) < 0) { |
1026 |
if (register_framebuffer(info) < 0) { |
| 1017 |
printk(KERN_ERR "vesafb: failed to register framebuffer device\n"); |
1027 |
printk(KERN_ERR "vesafb: failed to register framebuffer device\n"); |
| 1018 |
err = -EINVAL; |
1028 |
err = -EINVAL; |
| 1019 |
goto pr_err2; |
1029 |
goto out_mem; |
| 1020 |
} |
1030 |
} |
| 1021 |
|
1031 |
|
| 1022 |
printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", |
1032 |
printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", |
|
Lines 1035-1045
Link Here
|
| 1035 |
fb_destroy_modedb(edid_modes); |
1045 |
fb_destroy_modedb(edid_modes); |
| 1036 |
return 0; |
1046 |
return 0; |
| 1037 |
|
1047 |
|
| 1038 |
pr_err2: |
1048 |
out_mem: |
| 1039 |
release_mem_region(info->fix.smem_start, info->fix.smem_len); |
1049 |
release_mem_region(info->fix.smem_start, info->fix.smem_len); |
| 1040 |
pr_err1: |
1050 |
out_cmap: |
| 1041 |
fb_dealloc_cmap(&info->cmap); |
1051 |
fb_dealloc_cmap(&info->cmap); |
| 1042 |
pr_err: |
1052 |
out: |
| 1043 |
framebuffer_release(info); |
1053 |
framebuffer_release(info); |
| 1044 |
vesafb_info = NULL; |
1054 |
vesafb_info = NULL; |
| 1045 |
|
1055 |
|
|
Lines 1145-1149
Link Here
|
| 1145 |
#endif /* MODULE */ |
1155 |
#endif /* MODULE */ |
| 1146 |
|
1156 |
|
| 1147 |
MODULE_LICENSE("GPL"); |
1157 |
MODULE_LICENSE("GPL"); |
| 1148 |
MODULE_AUTHOR("Micha³ Januszewski"); |
1158 |
MODULE_AUTHOR("Michal Januszewski"); |
| 1149 |
MODULE_DESCRIPTION("Framebuffer driver for VBE2.0-compliant graphic boards"); |
1159 |
MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphic boards"); |