Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.23 1188 lines 33 kB view raw
1/* 2 * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device 3 * 4 * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. 5 * 6 * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> 7 * based on pm2fb.c 8 * 9 * Based on code written by: 10 * Sven Luther, <luther@dpt-info.u-strasbg.fr> 11 * Alan Hourihane, <alanh@fairlite.demon.co.uk> 12 * Russell King, <rmk@arm.linux.org.uk> 13 * Based on linux/drivers/video/skeletonfb.c: 14 * Copyright (C) 1997 Geert Uytterhoeven 15 * Based on linux/driver/video/pm2fb.c: 16 * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 17 * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) 18 * 19 * This file is subject to the terms and conditions of the GNU General Public 20 * License. See the file COPYING in the main directory of this archive for 21 * more details. 22 * 23 */ 24 25#include <linux/module.h> 26#include <linux/kernel.h> 27#include <linux/errno.h> 28#include <linux/string.h> 29#include <linux/mm.h> 30#include <linux/slab.h> 31#include <linux/delay.h> 32#include <linux/fb.h> 33#include <linux/init.h> 34#include <linux/pci.h> 35 36#include <video/pm3fb.h> 37 38#if !defined(CONFIG_PCI) 39#error "Only generic PCI cards supported." 40#endif 41 42#undef PM3FB_MASTER_DEBUG 43#ifdef PM3FB_MASTER_DEBUG 44#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) 45#else 46#define DPRINTK(a,b...) 47#endif 48 49/* 50 * Driver data 51 */ 52static char *mode_option __devinitdata; 53 54/* 55 * This structure defines the hardware state of the graphics card. Normally 56 * you place this in a header file in linux/include/video. This file usually 57 * also includes register information. That allows other driver subsystems 58 * and userland applications the ability to use the same header file to 59 * avoid duplicate work and easy porting of software. 60 */ 61struct pm3_par { 62 unsigned char __iomem *v_regs;/* virtual address of p_regs */ 63 u32 video; /* video flags before blanking */ 64 u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ 65 u32 palette[16]; 66}; 67 68/* 69 * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 70 * if we don't use modedb. If we do use modedb see pm3fb_init how to use it 71 * to get a fb_var_screeninfo. Otherwise define a default var as well. 72 */ 73static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { 74 .id = "Permedia3", 75 .type = FB_TYPE_PACKED_PIXELS, 76 .visual = FB_VISUAL_PSEUDOCOLOR, 77 .xpanstep = 1, 78 .ypanstep = 1, 79 .ywrapstep = 0, 80 .accel = FB_ACCEL_3DLABS_PERMEDIA3, 81}; 82 83/* 84 * Utility functions 85 */ 86 87static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) 88{ 89 return fb_readl(par->v_regs + off); 90} 91 92static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) 93{ 94 fb_writel(v, par->v_regs + off); 95} 96 97static inline void PM3_WAIT(struct pm3_par *par, u32 n) 98{ 99 while (PM3_READ_REG(par, PM3InFIFOSpace) < n); 100} 101 102static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) 103{ 104 PM3_WAIT(par, 3); 105 PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); 106 PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); 107 wmb(); 108 PM3_WRITE_REG(par, PM3RD_IndexedData, v); 109 wmb(); 110} 111 112static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, 113 unsigned char r, unsigned char g, unsigned char b) 114{ 115 PM3_WAIT(par, 4); 116 PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); 117 wmb(); 118 PM3_WRITE_REG(par, PM3RD_PaletteData, r); 119 wmb(); 120 PM3_WRITE_REG(par, PM3RD_PaletteData, g); 121 wmb(); 122 PM3_WRITE_REG(par, PM3RD_PaletteData, b); 123 wmb(); 124} 125 126static void pm3fb_clear_colormap(struct pm3_par *par, 127 unsigned char r, unsigned char g, unsigned char b) 128{ 129 int i; 130 131 for (i = 0; i < 256 ; i++) 132 pm3fb_set_color(par, i, r, g, b); 133 134} 135 136/* Calculating various clock parameter */ 137static void pm3fb_calculate_clock(unsigned long reqclock, 138 unsigned char *prescale, 139 unsigned char *feedback, 140 unsigned char *postscale) 141{ 142 int f, pre, post; 143 unsigned long freq; 144 long freqerr = 1000; 145 long currerr; 146 147 for (f = 1; f < 256; f++) { 148 for (pre = 1; pre < 256; pre++) { 149 for (post = 0; post < 5; post++) { 150 freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; 151 currerr = (reqclock > freq) 152 ? reqclock - freq 153 : freq - reqclock; 154 if (currerr < freqerr) { 155 freqerr = currerr; 156 *feedback = f; 157 *prescale = pre; 158 *postscale = post; 159 } 160 } 161 } 162 } 163} 164 165static inline int pm3fb_depth(const struct fb_var_screeninfo *var) 166{ 167 if ( var->bits_per_pixel == 16 ) 168 return var->red.length + var->green.length 169 + var->blue.length; 170 171 return var->bits_per_pixel; 172} 173 174static inline int pm3fb_shift_bpp(unsigned bpp, int v) 175{ 176 switch (bpp) { 177 case 8: 178 return (v >> 4); 179 case 16: 180 return (v >> 3); 181 case 32: 182 return (v >> 2); 183 } 184 DPRINTK("Unsupported depth %u\n", bpp); 185 return 0; 186} 187 188/* acceleration */ 189static int pm3fb_sync(struct fb_info *info) 190{ 191 struct pm3_par *par = info->par; 192 193 PM3_WAIT(par, 2); 194 PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 195 PM3_WRITE_REG(par, PM3Sync, 0); 196 mb(); 197 do { 198 while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); 199 rmb(); 200 } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); 201 202 return 0; 203} 204 205static void pm3fb_init_engine(struct fb_info *info) 206{ 207 struct pm3_par *par = info->par; 208 const u32 width = (info->var.xres_virtual + 7) & ~7; 209 210 PM3_WAIT(par, 50); 211 PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 212 PM3_WRITE_REG(par, PM3StatisticMode, 0x0); 213 PM3_WRITE_REG(par, PM3DeltaMode, 0x0); 214 PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); 215 PM3_WRITE_REG(par, PM3ScissorMode, 0x0); 216 PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); 217 PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); 218 PM3_WRITE_REG(par, PM3GIDMode, 0x0); 219 PM3_WRITE_REG(par, PM3DepthMode, 0x0); 220 PM3_WRITE_REG(par, PM3StencilMode, 0x0); 221 PM3_WRITE_REG(par, PM3StencilData, 0x0); 222 PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); 223 PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); 224 PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); 225 PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); 226 PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); 227 PM3_WRITE_REG(par, PM3LUTMode, 0x0); 228 PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); 229 PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); 230 PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); 231 PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); 232 PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); 233 PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); 234 PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); 235 PM3_WRITE_REG(par, PM3FogMode, 0x0); 236 PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); 237 PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); 238 PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); 239 PM3_WRITE_REG(par, PM3YUVMode, 0x0); 240 PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); 241 PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); 242 PM3_WRITE_REG(par, PM3DitherMode, 0x0); 243 PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); 244 PM3_WRITE_REG(par, PM3RouterMode, 0x0); 245 PM3_WRITE_REG(par, PM3Window, 0x0); 246 247 PM3_WRITE_REG(par, PM3Config2D, 0x0); 248 249 PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); 250 251 PM3_WRITE_REG(par, PM3XBias, 0x0); 252 PM3_WRITE_REG(par, PM3YBias, 0x0); 253 PM3_WRITE_REG(par, PM3DeltaControl, 0x0); 254 255 PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); 256 257 PM3_WRITE_REG(par, PM3FBDestReadEnables, 258 PM3FBDestReadEnables_E(0xff) | 259 PM3FBDestReadEnables_R(0xff) | 260 PM3FBDestReadEnables_ReferenceAlpha(0xff)); 261 PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); 262 PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); 263 PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, 264 PM3FBDestReadBufferWidth_Width(width)); 265 266 PM3_WRITE_REG(par, PM3FBDestReadMode, 267 PM3FBDestReadMode_ReadEnable | 268 PM3FBDestReadMode_Enable0); 269 PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); 270 PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); 271 PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, 272 PM3FBSourceReadBufferWidth_Width(width)); 273 PM3_WRITE_REG(par, PM3FBSourceReadMode, 274 PM3FBSourceReadMode_Blocking | 275 PM3FBSourceReadMode_ReadEnable); 276 277 PM3_WAIT(par, 2); 278 { 279 unsigned long rm = 1; 280 switch (info->var.bits_per_pixel) { 281 case 8: 282 PM3_WRITE_REG(par, PM3PixelSize, 283 PM3PixelSize_GLOBAL_8BIT); 284 break; 285 case 16: 286 PM3_WRITE_REG(par, PM3PixelSize, 287 PM3PixelSize_GLOBAL_16BIT); 288 break; 289 case 32: 290 PM3_WRITE_REG(par, PM3PixelSize, 291 PM3PixelSize_GLOBAL_32BIT); 292 break; 293 default: 294 DPRINTK(1, "Unsupported depth %d\n", 295 info->var.bits_per_pixel); 296 break; 297 } 298 PM3_WRITE_REG(par, PM3RasterizerMode, rm); 299 } 300 301 PM3_WAIT(par, 20); 302 PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); 303 PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); 304 PM3_WRITE_REG(par, PM3FBWriteMode, 305 PM3FBWriteMode_WriteEnable | 306 PM3FBWriteMode_OpaqueSpan | 307 PM3FBWriteMode_Enable0); 308 PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); 309 PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); 310 PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, 311 PM3FBWriteBufferWidth_Width(width)); 312 313 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); 314 { 315 /* size in lines of FB */ 316 unsigned long sofb = info->screen_size / 317 info->fix.line_length; 318 if (sofb > 4095) 319 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); 320 else 321 PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); 322 323 switch (info->var.bits_per_pixel) { 324 case 8: 325 PM3_WRITE_REG(par, PM3DitherMode, 326 (1 << 10) | (2 << 3)); 327 break; 328 case 16: 329 PM3_WRITE_REG(par, PM3DitherMode, 330 (1 << 10) | (1 << 3)); 331 break; 332 case 32: 333 PM3_WRITE_REG(par, PM3DitherMode, 334 (1 << 10) | (0 << 3)); 335 break; 336 default: 337 DPRINTK(1, "Unsupported depth %d\n", 338 info->current_par->depth); 339 break; 340 } 341 } 342 343 PM3_WRITE_REG(par, PM3dXDom, 0x0); 344 PM3_WRITE_REG(par, PM3dXSub, 0x0); 345 PM3_WRITE_REG(par, PM3dY, (1 << 16)); 346 PM3_WRITE_REG(par, PM3StartXDom, 0x0); 347 PM3_WRITE_REG(par, PM3StartXSub, 0x0); 348 PM3_WRITE_REG(par, PM3StartY, 0x0); 349 PM3_WRITE_REG(par, PM3Count, 0x0); 350 351/* Disable LocalBuffer. better safe than sorry */ 352 PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); 353 PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); 354 PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); 355 PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); 356 357 pm3fb_sync(info); 358} 359 360static void pm3fb_fillrect (struct fb_info *info, 361 const struct fb_fillrect *region) 362{ 363 struct pm3_par *par = info->par; 364 struct fb_fillrect modded; 365 int vxres, vyres; 366 u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 367 ((u32*)info->pseudo_palette)[region->color] : region->color; 368 369 if (info->state != FBINFO_STATE_RUNNING) 370 return; 371 if ((info->flags & FBINFO_HWACCEL_DISABLED) || 372 region->rop != ROP_COPY ) { 373 cfb_fillrect(info, region); 374 return; 375 } 376 377 vxres = info->var.xres_virtual; 378 vyres = info->var.yres_virtual; 379 380 memcpy(&modded, region, sizeof(struct fb_fillrect)); 381 382 if(!modded.width || !modded.height || 383 modded.dx >= vxres || modded.dy >= vyres) 384 return; 385 386 if(modded.dx + modded.width > vxres) 387 modded.width = vxres - modded.dx; 388 if(modded.dy + modded.height > vyres) 389 modded.height = vyres - modded.dy; 390 391 if(info->var.bits_per_pixel == 8) 392 color |= color << 8; 393 if(info->var.bits_per_pixel <= 16) 394 color |= color << 16; 395 396 PM3_WAIT(par, 4); 397 398 PM3_WRITE_REG(par, PM3Config2D, 399 PM3Config2D_UseConstantSource | 400 PM3Config2D_ForegroundROPEnable | 401 (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ 402 PM3Config2D_FBWriteEnable); 403 404 PM3_WRITE_REG(par, PM3ForegroundColor, color); 405 406 PM3_WRITE_REG(par, PM3RectanglePosition, 407 (PM3RectanglePosition_XOffset(modded.dx)) | 408 (PM3RectanglePosition_YOffset(modded.dy))); 409 410 PM3_WRITE_REG(par, PM3Render2D, 411 PM3Render2D_XPositive | 412 PM3Render2D_YPositive | 413 PM3Render2D_Operation_Normal | 414 PM3Render2D_SpanOperation | 415 (PM3Render2D_Width(modded.width)) | 416 (PM3Render2D_Height(modded.height))); 417} 418/* end of acceleration functions */ 419 420/* write the mode to registers */ 421static void pm3fb_write_mode(struct fb_info *info) 422{ 423 struct pm3_par *par = info->par; 424 char tempsync = 0x00, tempmisc = 0x00; 425 const u32 hsstart = info->var.right_margin; 426 const u32 hsend = hsstart + info->var.hsync_len; 427 const u32 hbend = hsend + info->var.left_margin; 428 const u32 xres = (info->var.xres + 31) & ~31; 429 const u32 htotal = xres + hbend; 430 const u32 vsstart = info->var.lower_margin; 431 const u32 vsend = vsstart + info->var.vsync_len; 432 const u32 vbend = vsend + info->var.upper_margin; 433 const u32 vtotal = info->var.yres + vbend; 434 const u32 width = (info->var.xres_virtual + 7) & ~7; 435 const unsigned bpp = info->var.bits_per_pixel; 436 437 PM3_WAIT(par, 20); 438 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); 439 PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); 440 PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); 441 PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); 442 443 PM3_WRITE_REG(par, PM3HTotal, 444 pm3fb_shift_bpp(bpp, htotal - 1)); 445 PM3_WRITE_REG(par, PM3HsEnd, 446 pm3fb_shift_bpp(bpp, hsend)); 447 PM3_WRITE_REG(par, PM3HsStart, 448 pm3fb_shift_bpp(bpp, hsstart)); 449 PM3_WRITE_REG(par, PM3HbEnd, 450 pm3fb_shift_bpp(bpp, hbend)); 451 PM3_WRITE_REG(par, PM3HgEnd, 452 pm3fb_shift_bpp(bpp, hbend)); 453 PM3_WRITE_REG(par, PM3ScreenStride, 454 pm3fb_shift_bpp(bpp, width)); 455 PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); 456 PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); 457 PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); 458 PM3_WRITE_REG(par, PM3VbEnd, vbend); 459 460 switch (bpp) { 461 case 8: 462 PM3_WRITE_REG(par, PM3ByAperture1Mode, 463 PM3ByApertureMode_PIXELSIZE_8BIT); 464 PM3_WRITE_REG(par, PM3ByAperture2Mode, 465 PM3ByApertureMode_PIXELSIZE_8BIT); 466 break; 467 468 case 16: 469#ifndef __BIG_ENDIAN 470 PM3_WRITE_REG(par, PM3ByAperture1Mode, 471 PM3ByApertureMode_PIXELSIZE_16BIT); 472 PM3_WRITE_REG(par, PM3ByAperture2Mode, 473 PM3ByApertureMode_PIXELSIZE_16BIT); 474#else 475 PM3_WRITE_REG(par, PM3ByAperture1Mode, 476 PM3ByApertureMode_PIXELSIZE_16BIT | 477 PM3ByApertureMode_BYTESWAP_BADC); 478 PM3_WRITE_REG(par, PM3ByAperture2Mode, 479 PM3ByApertureMode_PIXELSIZE_16BIT | 480 PM3ByApertureMode_BYTESWAP_BADC); 481#endif /* ! __BIG_ENDIAN */ 482 break; 483 484 case 32: 485#ifndef __BIG_ENDIAN 486 PM3_WRITE_REG(par, PM3ByAperture1Mode, 487 PM3ByApertureMode_PIXELSIZE_32BIT); 488 PM3_WRITE_REG(par, PM3ByAperture2Mode, 489 PM3ByApertureMode_PIXELSIZE_32BIT); 490#else 491 PM3_WRITE_REG(par, PM3ByAperture1Mode, 492 PM3ByApertureMode_PIXELSIZE_32BIT | 493 PM3ByApertureMode_BYTESWAP_DCBA); 494 PM3_WRITE_REG(par, PM3ByAperture2Mode, 495 PM3ByApertureMode_PIXELSIZE_32BIT | 496 PM3ByApertureMode_BYTESWAP_DCBA); 497#endif /* ! __BIG_ENDIAN */ 498 break; 499 500 default: 501 DPRINTK("Unsupported depth %d\n", bpp); 502 break; 503 } 504 505 /* 506 * Oxygen VX1 - it appears that setting PM3VideoControl and 507 * then PM3RD_SyncControl to the same SYNC settings undoes 508 * any net change - they seem to xor together. Only set the 509 * sync options in PM3RD_SyncControl. --rmk 510 */ 511 { 512 unsigned int video = par->video; 513 514 video &= ~(PM3VideoControl_HSYNC_MASK | 515 PM3VideoControl_VSYNC_MASK); 516 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 517 PM3VideoControl_VSYNC_ACTIVE_HIGH; 518 PM3_WRITE_REG(par, PM3VideoControl, video); 519 } 520 PM3_WRITE_REG(par, PM3VClkCtl, 521 (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); 522 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 523 PM3_WRITE_REG(par, PM3ChipConfig, 524 (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); 525 526 wmb(); 527 { 528 unsigned char uninitialized_var(m); /* ClkPreScale */ 529 unsigned char uninitialized_var(n); /* ClkFeedBackScale */ 530 unsigned char uninitialized_var(p); /* ClkPostScale */ 531 unsigned long pixclock = PICOS2KHZ(info->var.pixclock); 532 533 (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); 534 535 DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", 536 pixclock, (int) m, (int) n, (int) p); 537 538 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); 539 PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); 540 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); 541 } 542 /* 543 PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); 544 */ 545 /* 546 PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); 547 */ 548 if ((par->video & PM3VideoControl_HSYNC_MASK) == 549 PM3VideoControl_HSYNC_ACTIVE_HIGH) 550 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 551 if ((par->video & PM3VideoControl_VSYNC_MASK) == 552 PM3VideoControl_VSYNC_ACTIVE_HIGH) 553 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 554 555 PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); 556 DPRINTK("PM3RD_SyncControl: %d\n", tempsync); 557 558 PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); 559 560 switch (pm3fb_depth(&info->var)) { 561 case 8: 562 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 563 PM3RD_PixelSize_8_BIT_PIXELS); 564 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 565 PM3RD_ColorFormat_CI8_COLOR | 566 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 567 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 568 break; 569 case 12: 570 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 571 PM3RD_PixelSize_16_BIT_PIXELS); 572 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 573 PM3RD_ColorFormat_4444_COLOR | 574 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 575 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 576 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 577 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 578 break; 579 case 15: 580 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 581 PM3RD_PixelSize_16_BIT_PIXELS); 582 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 583 PM3RD_ColorFormat_5551_FRONT_COLOR | 584 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 585 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 586 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 587 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 588 break; 589 case 16: 590 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 591 PM3RD_PixelSize_16_BIT_PIXELS); 592 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 593 PM3RD_ColorFormat_565_FRONT_COLOR | 594 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 595 PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 596 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 597 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 598 break; 599 case 32: 600 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 601 PM3RD_PixelSize_32_BIT_PIXELS); 602 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 603 PM3RD_ColorFormat_8888_COLOR | 604 PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 605 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 606 PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 607 break; 608 } 609 PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); 610} 611 612/* 613 * hardware independent functions 614 */ 615static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 616{ 617 u32 lpitch; 618 unsigned bpp = var->red.length + var->green.length 619 + var->blue.length + var->transp.length; 620 621 if ( bpp != var->bits_per_pixel ) { 622 /* set predefined mode for bits_per_pixel settings */ 623 624 switch(var->bits_per_pixel) { 625 case 8: 626 var->red.length = var->green.length = var->blue.length = 8; 627 var->red.offset = var->green.offset = var->blue.offset = 0; 628 var->transp.offset = 0; 629 var->transp.length = 0; 630 break; 631 case 16: 632 var->red.length = var->blue.length = 5; 633 var->green.length = 6; 634 var->transp.length = 0; 635 break; 636 case 32: 637 var->red.length = var->green.length = var->blue.length = 8; 638 var->transp.length = 8; 639 break; 640 default: 641 DPRINTK("depth not supported: %u\n", var->bits_per_pixel); 642 return -EINVAL; 643 } 644 } 645 /* it is assumed BGRA order */ 646 if (var->bits_per_pixel > 8 ) 647 { 648 var->blue.offset = 0; 649 var->green.offset = var->blue.length; 650 var->red.offset = var->green.offset + var->green.length; 651 var->transp.offset = var->red.offset + var->red.length; 652 } 653 var->height = var->width = -1; 654 655 if (var->xres != var->xres_virtual) { 656 DPRINTK("virtual x resolution != physical x resolution not supported\n"); 657 return -EINVAL; 658 } 659 660 if (var->yres > var->yres_virtual) { 661 DPRINTK("virtual y resolution < physical y resolution not possible\n"); 662 return -EINVAL; 663 } 664 665 if (var->xoffset) { 666 DPRINTK("xoffset not supported\n"); 667 return -EINVAL; 668 } 669 670 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 671 DPRINTK("interlace not supported\n"); 672 return -EINVAL; 673 } 674 675 var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ 676 lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); 677 678 if (var->xres < 200 || var->xres > 2048) { 679 DPRINTK("width not supported: %u\n", var->xres); 680 return -EINVAL; 681 } 682 683 if (var->yres < 200 || var->yres > 4095) { 684 DPRINTK("height not supported: %u\n", var->yres); 685 return -EINVAL; 686 } 687 688 if (lpitch * var->yres_virtual > info->fix.smem_len) { 689 DPRINTK("no memory for screen (%ux%ux%u)\n", 690 var->xres, var->yres_virtual, var->bits_per_pixel); 691 return -EINVAL; 692 } 693 694 if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { 695 DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); 696 return -EINVAL; 697 } 698 699 var->accel_flags = 0; /* Can't mmap if this is on */ 700 701 DPRINTK("Checking graphics mode at %dx%d depth %d\n", 702 var->xres, var->yres, var->bits_per_pixel); 703 return 0; 704} 705 706static int pm3fb_set_par(struct fb_info *info) 707{ 708 struct pm3_par *par = info->par; 709 const u32 xres = (info->var.xres + 31) & ~31; 710 const unsigned bpp = info->var.bits_per_pixel; 711 712 par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) 713 + info->var.xoffset); 714 par->video = 0; 715 716 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 717 par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 718 else 719 par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 720 721 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 722 par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 723 else 724 par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 725 726 if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 727 par->video |= PM3VideoControl_LINE_DOUBLE_ON; 728 else 729 par->video |= PM3VideoControl_LINE_DOUBLE_OFF; 730 731 if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 732 par->video |= PM3VideoControl_ENABLE; 733 else { 734 par->video |= PM3VideoControl_DISABLE; 735 DPRINTK("PM3Video disabled\n"); 736 } 737 switch (bpp) { 738 case 8: 739 par->video |= PM3VideoControl_PIXELSIZE_8BIT; 740 break; 741 case 16: 742 par->video |= PM3VideoControl_PIXELSIZE_16BIT; 743 break; 744 case 32: 745 par->video |= PM3VideoControl_PIXELSIZE_32BIT; 746 break; 747 default: 748 DPRINTK("Unsupported depth\n"); 749 break; 750 } 751 752 info->fix.visual = 753 (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 754 info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) 755 * bpp / 8; 756 757/* pm3fb_clear_memory(info, 0);*/ 758 pm3fb_clear_colormap(par, 0, 0, 0); 759 PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 760 PM3RD_CursorMode_CURSOR_DISABLE); 761 pm3fb_init_engine(info); 762 pm3fb_write_mode(info); 763 return 0; 764} 765 766static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 767 unsigned blue, unsigned transp, 768 struct fb_info *info) 769{ 770 struct pm3_par *par = info->par; 771 772 if (regno >= 256) /* no. of hw registers */ 773 return -EINVAL; 774 775 /* grayscale works only partially under directcolor */ 776 if (info->var.grayscale) { 777 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 778 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 779 } 780 781 /* Directcolor: 782 * var->{color}.offset contains start of bitfield 783 * var->{color}.length contains length of bitfield 784 * {hardwarespecific} contains width of DAC 785 * pseudo_palette[X] is programmed to (X << red.offset) | 786 * (X << green.offset) | 787 * (X << blue.offset) 788 * RAMDAC[X] is programmed to (red, green, blue) 789 * color depth = SUM(var->{color}.length) 790 * 791 * Pseudocolor: 792 * var->{color}.offset is 0 793 * var->{color}.length contains width of DAC or the number of unique 794 * colors available (color depth) 795 * pseudo_palette is not used 796 * RAMDAC[X] is programmed to (red, green, blue) 797 * color depth = var->{color}.length 798 */ 799 800 /* 801 * This is the point where the color is converted to something that 802 * is acceptable by the hardware. 803 */ 804#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 805 red = CNVT_TOHW(red, info->var.red.length); 806 green = CNVT_TOHW(green, info->var.green.length); 807 blue = CNVT_TOHW(blue, info->var.blue.length); 808 transp = CNVT_TOHW(transp, info->var.transp.length); 809#undef CNVT_TOHW 810 811 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 812 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 813 u32 v; 814 815 if (regno >= 16) 816 return -EINVAL; 817 818 v = (red << info->var.red.offset) | 819 (green << info->var.green.offset) | 820 (blue << info->var.blue.offset) | 821 (transp << info->var.transp.offset); 822 823 switch (info->var.bits_per_pixel) { 824 case 8: 825 break; 826 case 16: 827 case 32: 828 ((u32*)(info->pseudo_palette))[regno] = v; 829 break; 830 } 831 return 0; 832 } 833 else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 834 pm3fb_set_color(par, regno, red, green, blue); 835 836 return 0; 837} 838 839static int pm3fb_pan_display(struct fb_var_screeninfo *var, 840 struct fb_info *info) 841{ 842 struct pm3_par *par = info->par; 843 const u32 xres = (var->xres + 31) & ~31; 844 845 par->base = pm3fb_shift_bpp(var->bits_per_pixel, 846 (var->yoffset * xres) 847 + var->xoffset); 848 PM3_WAIT(par, 1); 849 PM3_WRITE_REG(par, PM3ScreenBase, par->base); 850 return 0; 851} 852 853static int pm3fb_blank(int blank_mode, struct fb_info *info) 854{ 855 struct pm3_par *par = info->par; 856 u32 video = par->video; 857 858 /* 859 * Oxygen VX1 - it appears that setting PM3VideoControl and 860 * then PM3RD_SyncControl to the same SYNC settings undoes 861 * any net change - they seem to xor together. Only set the 862 * sync options in PM3RD_SyncControl. --rmk 863 */ 864 video &= ~(PM3VideoControl_HSYNC_MASK | 865 PM3VideoControl_VSYNC_MASK); 866 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 867 PM3VideoControl_VSYNC_ACTIVE_HIGH; 868 869 switch (blank_mode) { 870 case FB_BLANK_UNBLANK: 871 video |= PM3VideoControl_ENABLE; 872 break; 873 case FB_BLANK_NORMAL: 874 video &= ~(PM3VideoControl_ENABLE); 875 break; 876 case FB_BLANK_HSYNC_SUSPEND: 877 video &= ~(PM3VideoControl_HSYNC_MASK | 878 PM3VideoControl_BLANK_ACTIVE_LOW); 879 break; 880 case FB_BLANK_VSYNC_SUSPEND: 881 video &= ~(PM3VideoControl_VSYNC_MASK | 882 PM3VideoControl_BLANK_ACTIVE_LOW); 883 break; 884 case FB_BLANK_POWERDOWN: 885 video &= ~(PM3VideoControl_HSYNC_MASK | 886 PM3VideoControl_VSYNC_MASK | 887 PM3VideoControl_BLANK_ACTIVE_LOW); 888 break; 889 default: 890 DPRINTK("Unsupported blanking %d\n", blank_mode); 891 return 1; 892 } 893 894 PM3_WAIT(par, 1); 895 PM3_WRITE_REG(par,PM3VideoControl, video); 896 return 0; 897} 898 899 /* 900 * Frame buffer operations 901 */ 902 903static struct fb_ops pm3fb_ops = { 904 .owner = THIS_MODULE, 905 .fb_check_var = pm3fb_check_var, 906 .fb_set_par = pm3fb_set_par, 907 .fb_setcolreg = pm3fb_setcolreg, 908 .fb_pan_display = pm3fb_pan_display, 909 .fb_fillrect = pm3fb_fillrect, 910 .fb_copyarea = cfb_copyarea, 911 .fb_imageblit = cfb_imageblit, 912 .fb_blank = pm3fb_blank, 913 .fb_sync = pm3fb_sync, 914}; 915 916/* ------------------------------------------------------------------------- */ 917 918 /* 919 * Initialization 920 */ 921 922/* mmio register are already mapped when this function is called */ 923/* the pm3fb_fix.smem_start is also set */ 924static unsigned long pm3fb_size_memory(struct pm3_par *par) 925{ 926 unsigned long memsize = 0, tempBypass, i, temp1, temp2; 927 unsigned char __iomem *screen_mem; 928 929 pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ 930 /* Linear frame buffer - request region and map it. */ 931 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 932 "pm3fb smem")) { 933 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 934 return 0; 935 } 936 screen_mem = 937 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 938 if (!screen_mem) { 939 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 940 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 941 return 0; 942 } 943 944 /* TODO: card-specific stuff, *before* accessing *any* FB memory */ 945 /* For Appian Jeronimo 2000 board second head */ 946 947 tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); 948 949 DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 950 951 PM3_WAIT(par, 1); 952 PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); 953 954 /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ 955 for (i = 0; i < 32; i++) { 956 fb_writel(i * 0x00345678, 957 (screen_mem + (i * 1048576))); 958 mb(); 959 temp1 = fb_readl((screen_mem + (i * 1048576))); 960 961 /* Let's check for wrapover, write will fail at 16MB boundary */ 962 if (temp1 == (i * 0x00345678)) 963 memsize = i; 964 else 965 break; 966 } 967 968 DPRINTK("First detect pass already got %ld MB\n", memsize + 1); 969 970 if (memsize + 1 == i) { 971 for (i = 0; i < 32; i++) { 972 /* Clear first 32MB ; 0 is 0, no need to byteswap */ 973 writel(0x0000000, (screen_mem + (i * 1048576))); 974 } 975 wmb(); 976 977 for (i = 32; i < 64; i++) { 978 fb_writel(i * 0x00345678, 979 (screen_mem + (i * 1048576))); 980 mb(); 981 temp1 = 982 fb_readl((screen_mem + (i * 1048576))); 983 temp2 = 984 fb_readl((screen_mem + ((i - 32) * 1048576))); 985 /* different value, different RAM... */ 986 if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) 987 memsize = i; 988 else 989 break; 990 } 991 } 992 DPRINTK("Second detect pass got %ld MB\n", memsize + 1); 993 994 PM3_WAIT(par, 1); 995 PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); 996 997 iounmap(screen_mem); 998 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 999 memsize = 1048576 * (memsize + 1); 1000 1001 DPRINTK("Returning 0x%08lx bytes\n", memsize); 1002 1003 return memsize; 1004} 1005 1006static int __devinit pm3fb_probe(struct pci_dev *dev, 1007 const struct pci_device_id *ent) 1008{ 1009 struct fb_info *info; 1010 struct pm3_par *par; 1011 struct device* device = &dev->dev; /* for pci drivers */ 1012 int err, retval = -ENXIO; 1013 1014 err = pci_enable_device(dev); 1015 if (err) { 1016 printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); 1017 return err; 1018 } 1019 /* 1020 * Dynamically allocate info and par 1021 */ 1022 info = framebuffer_alloc(sizeof(struct pm3_par), device); 1023 1024 if (!info) 1025 return -ENOMEM; 1026 par = info->par; 1027 1028 /* 1029 * Here we set the screen_base to the virtual memory address 1030 * for the framebuffer. 1031 */ 1032 pm3fb_fix.mmio_start = pci_resource_start(dev, 0); 1033 pm3fb_fix.mmio_len = PM3_REGS_SIZE; 1034 1035 /* Registers - request region and map it. */ 1036 if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, 1037 "pm3fb regbase")) { 1038 printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); 1039 goto err_exit_neither; 1040 } 1041 par->v_regs = 1042 ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1043 if (!par->v_regs) { 1044 printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", 1045 pm3fb_fix.id); 1046 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1047 goto err_exit_neither; 1048 } 1049 1050#if defined(__BIG_ENDIAN) 1051 pm3fb_fix.mmio_start += PM3_REGS_SIZE; 1052 DPRINTK("Adjusting register base for big-endian.\n"); 1053#endif 1054 /* Linear frame buffer - request region and map it. */ 1055 pm3fb_fix.smem_start = pci_resource_start(dev, 1); 1056 pm3fb_fix.smem_len = pm3fb_size_memory(par); 1057 if (!pm3fb_fix.smem_len) 1058 { 1059 printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); 1060 goto err_exit_mmio; 1061 } 1062 if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 1063 "pm3fb smem")) { 1064 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 1065 goto err_exit_mmio; 1066 } 1067 info->screen_base = 1068 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1069 if (!info->screen_base) { 1070 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 1071 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1072 goto err_exit_mmio; 1073 } 1074 info->screen_size = pm3fb_fix.smem_len; 1075 1076 info->fbops = &pm3fb_ops; 1077 1078 par->video = PM3_READ_REG(par, PM3VideoControl); 1079 1080 info->fix = pm3fb_fix; 1081 info->pseudo_palette = par->palette; 1082 info->flags = FBINFO_DEFAULT | 1083 FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ 1084 1085 /* 1086 * This should give a reasonable default video mode. The following is 1087 * done when we can set a video mode. 1088 */ 1089 if (!mode_option) 1090 mode_option = "640x480@60"; 1091 1092 retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 1093 1094 if (!retval || retval == 4) { 1095 retval = -EINVAL; 1096 goto err_exit_both; 1097 } 1098 1099 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 1100 retval = -ENOMEM; 1101 goto err_exit_both; 1102 } 1103 1104 /* 1105 * For drivers that can... 1106 */ 1107 pm3fb_check_var(&info->var, info); 1108 1109 if (register_framebuffer(info) < 0) { 1110 retval = -EINVAL; 1111 goto err_exit_all; 1112 } 1113 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, 1114 info->fix.id); 1115 pci_set_drvdata(dev, info); 1116 return 0; 1117 1118 err_exit_all: 1119 fb_dealloc_cmap(&info->cmap); 1120 err_exit_both: 1121 iounmap(info->screen_base); 1122 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 1123 err_exit_mmio: 1124 iounmap(par->v_regs); 1125 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 1126 err_exit_neither: 1127 framebuffer_release(info); 1128 return retval; 1129} 1130 1131 /* 1132 * Cleanup 1133 */ 1134static void __devexit pm3fb_remove(struct pci_dev *dev) 1135{ 1136 struct fb_info *info = pci_get_drvdata(dev); 1137 1138 if (info) { 1139 struct fb_fix_screeninfo *fix = &info->fix; 1140 struct pm3_par *par = info->par; 1141 1142 unregister_framebuffer(info); 1143 fb_dealloc_cmap(&info->cmap); 1144 1145 iounmap(info->screen_base); 1146 release_mem_region(fix->smem_start, fix->smem_len); 1147 iounmap(par->v_regs); 1148 release_mem_region(fix->mmio_start, fix->mmio_len); 1149 1150 pci_set_drvdata(dev, NULL); 1151 framebuffer_release(info); 1152 } 1153} 1154 1155static struct pci_device_id pm3fb_id_table[] = { 1156 { PCI_VENDOR_ID_3DLABS, 0x0a, 1157 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 1158 { 0, } 1159}; 1160 1161/* For PCI drivers */ 1162static struct pci_driver pm3fb_driver = { 1163 .name = "pm3fb", 1164 .id_table = pm3fb_id_table, 1165 .probe = pm3fb_probe, 1166 .remove = __devexit_p(pm3fb_remove), 1167}; 1168 1169MODULE_DEVICE_TABLE(pci, pm3fb_id_table); 1170 1171static int __init pm3fb_init(void) 1172{ 1173#ifndef MODULE 1174 if (fb_get_options("pm3fb", NULL)) 1175 return -ENODEV; 1176#endif 1177 return pci_register_driver(&pm3fb_driver); 1178} 1179 1180static void __exit pm3fb_exit(void) 1181{ 1182 pci_unregister_driver(&pm3fb_driver); 1183} 1184 1185module_init(pm3fb_init); 1186module_exit(pm3fb_exit); 1187 1188MODULE_LICENSE("GPL");