diff options
| author | Antonino A. Daplas <adaplas@gmail.com> | 2006-01-09 23:53:34 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-10 11:01:49 -0500 |
| commit | d911233fe6632981086942a6b66e7ae5dabaaadc (patch) | |
| tree | 6608709b71f04173beb0263c76a66bc1b7b2d4a9 | |
| parent | c549dc6422e4b720fed6702d70fddd8cee0f5c9a (diff) | |
[PATCH] skeletonfb: Documentation update
Update skeletonfb so it reflects recent (and somewhat old) changes of the
framebuffer layer.
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/video/skeletonfb.c | 482 |
1 files changed, 383 insertions, 99 deletions
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index a01e7ecc15ed..9b707771d757 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
| @@ -115,7 +115,8 @@ static struct fb_fix_screeninfo xxxfb_fix __initdata = { | |||
| 115 | /* | 115 | /* |
| 116 | * If your driver supports multiple boards or it supports multiple | 116 | * If your driver supports multiple boards or it supports multiple |
| 117 | * framebuffers, you should make these arrays, or allocate them | 117 | * framebuffers, you should make these arrays, or allocate them |
| 118 | * dynamically (using kmalloc()). | 118 | * dynamically using framebuffer_alloc() and free them with |
| 119 | * framebuffer_release(). | ||
| 119 | */ | 120 | */ |
| 120 | static struct fb_info info; | 121 | static struct fb_info info; |
| 121 | 122 | ||
| @@ -179,18 +180,31 @@ static int xxxfb_release(const struct fb_info *info, int user) | |||
| 179 | * intent to only test a mode and not actually set it. The stuff in | 180 | * intent to only test a mode and not actually set it. The stuff in |
| 180 | * modedb.c is a example of this. If the var passed in is slightly | 181 | * modedb.c is a example of this. If the var passed in is slightly |
| 181 | * off by what the hardware can support then we alter the var PASSED in | 182 | * off by what the hardware can support then we alter the var PASSED in |
| 182 | * to what we can do. If the hardware doesn't support mode change | 183 | * to what we can do. |
| 183 | * a -EINVAL will be returned by the upper layers. You don't need to | 184 | * |
| 184 | * implement this function then. If you hardware doesn't support | 185 | * For values that are off, this function must round them _up_ to the |
| 185 | * changing the resolution then this function is not needed. In this | 186 | * next value that is supported by the hardware. If the value is |
| 186 | * case the driver woudl just provide a var that represents the static | 187 | * greater than the highest value supported by the hardware, then this |
| 187 | * state the screen is in. | 188 | * function must return -EINVAL. |
| 189 | * | ||
| 190 | * Exception to the above rule: Some drivers have a fixed mode, ie, | ||
| 191 | * the hardware is already set at boot up, and cannot be changed. In | ||
| 192 | * this case, it is more acceptable that this function just return | ||
| 193 | * a copy of the currently working var (info->var). Better is to not | ||
| 194 | * implement this function, as the upper layer will do the copying | ||
| 195 | * of the current var for you. | ||
| 196 | * | ||
| 197 | * Note: This is the only function where the contents of var can be | ||
| 198 | * freely adjusted after the driver has been registered. If you find | ||
| 199 | * that you have code outside of this function that alters the content | ||
| 200 | * of var, then you are doing something wrong. Note also that the | ||
| 201 | * contents of info->var must be left untouched at all times after | ||
| 202 | * driver registration. | ||
| 188 | * | 203 | * |
| 189 | * Returns negative errno on error, or zero on success. | 204 | * Returns negative errno on error, or zero on success. |
| 190 | */ | 205 | */ |
| 191 | static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 206 | static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
| 192 | { | 207 | { |
| 193 | const struct xxx_par *par = (const struct xxx_par *) info->par; | ||
| 194 | /* ... */ | 208 | /* ... */ |
| 195 | return 0; | 209 | return 0; |
| 196 | } | 210 | } |
| @@ -204,14 +218,39 @@ static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
| 204 | * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in | 218 | * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in |
| 205 | * fb_info since we are using that data. This means we depend on the | 219 | * fb_info since we are using that data. This means we depend on the |
| 206 | * data in var inside fb_info to be supported by the hardware. | 220 | * data in var inside fb_info to be supported by the hardware. |
| 207 | * xxxfb_check_var is always called before xxxfb_set_par to ensure this. | 221 | * |
| 222 | * This function is also used to recover/restore the hardware to a | ||
| 223 | * known working state. | ||
| 224 | * | ||
| 225 | * xxxfb_check_var is always called before xxxfb_set_par to ensure that | ||
| 226 | * the contents of var is always valid. | ||
| 227 | * | ||
| 208 | * Again if you can't change the resolution you don't need this function. | 228 | * Again if you can't change the resolution you don't need this function. |
| 209 | * | 229 | * |
| 230 | * However, even if your hardware does not support mode changing, | ||
| 231 | * a set_par might be needed to at least initialize the hardware to | ||
| 232 | * a known working state, especially if it came back from another | ||
| 233 | * process that also modifies the same hardware, such as X. | ||
| 234 | * | ||
| 235 | * If this is the case, a combination such as the following should work: | ||
| 236 | * | ||
| 237 | * static int xxxfb_check_var(struct fb_var_screeninfo *var, | ||
| 238 | * struct fb_info *info) | ||
| 239 | * { | ||
| 240 | * *var = info->var; | ||
| 241 | * return 0; | ||
| 242 | * } | ||
| 243 | * | ||
| 244 | * static int xxxfb_set_par(struct fb_info *info) | ||
| 245 | * { | ||
| 246 | * init your hardware here | ||
| 247 | * } | ||
| 248 | * | ||
| 210 | * Returns negative errno on error, or zero on success. | 249 | * Returns negative errno on error, or zero on success. |
| 211 | */ | 250 | */ |
| 212 | static int xxxfb_set_par(struct fb_info *info) | 251 | static int xxxfb_set_par(struct fb_info *info) |
| 213 | { | 252 | { |
| 214 | struct xxx_par *par = (struct xxx_par *) info->par; | 253 | struct xxx_par *par = info->par; |
| 215 | /* ... */ | 254 | /* ... */ |
| 216 | return 0; | 255 | return 0; |
| 217 | } | 256 | } |
| @@ -258,70 +297,110 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
| 258 | * var->{color}.offset contains start of bitfield | 297 | * var->{color}.offset contains start of bitfield |
| 259 | * var->{color}.length contains length of bitfield | 298 | * var->{color}.length contains length of bitfield |
| 260 | * {hardwarespecific} contains width of DAC | 299 | * {hardwarespecific} contains width of DAC |
| 261 | * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) | 300 | * pseudo_palette[X] is programmed to (X << red.offset) | |
| 301 | * (X << green.offset) | | ||
| 302 | * (X << blue.offset) | ||
| 262 | * RAMDAC[X] is programmed to (red, green, blue) | 303 | * RAMDAC[X] is programmed to (red, green, blue) |
| 304 | * color depth = SUM(var->{color}.length) | ||
| 263 | * | 305 | * |
| 264 | * Pseudocolor: | 306 | * Pseudocolor: |
| 265 | * uses offset = 0 && length = DAC register width. | ||
| 266 | * var->{color}.offset is 0 | 307 | * var->{color}.offset is 0 |
| 267 | * var->{color}.length contains widht of DAC | 308 | * var->{color}.length contains width of DAC or the number of unique |
| 268 | * cmap is not used | 309 | * colors available (color depth) |
| 269 | * DAC[X] is programmed to (red, green, blue) | 310 | * pseudo_palette is not used |
| 311 | * RAMDAC[X] is programmed to (red, green, blue) | ||
| 312 | * color depth = var->{color}.length | ||
| 313 | * | ||
| 314 | * Static pseudocolor: | ||
| 315 | * same as Pseudocolor, but the RAMDAC is not programmed (read-only) | ||
| 316 | * | ||
| 317 | * Mono01/Mono10: | ||
| 318 | * Has only 2 values, black on white or white on black (fg on bg), | ||
| 319 | * var->{color}.offset is 0 | ||
| 320 | * white = (1 << var->{color}.length) - 1, black = 0 | ||
| 321 | * pseudo_palette is not used | ||
| 322 | * RAMDAC does not exist | ||
| 323 | * color depth is always 2 | ||
| 324 | * | ||
| 270 | * Truecolor: | 325 | * Truecolor: |
| 271 | * does not use RAMDAC (usually has 3 of them). | 326 | * does not use RAMDAC (usually has 3 of them). |
| 272 | * var->{color}.offset contains start of bitfield | 327 | * var->{color}.offset contains start of bitfield |
| 273 | * var->{color}.length contains length of bitfield | 328 | * var->{color}.length contains length of bitfield |
| 274 | * cmap is programmed to (red << red.offset) | (green << green.offset) | | 329 | * pseudo_palette is programmed to (red << red.offset) | |
| 275 | * (blue << blue.offset) | (transp << transp.offset) | 330 | * (green << green.offset) | |
| 331 | * (blue << blue.offset) | | ||
| 332 | * (transp << transp.offset) | ||
| 276 | * RAMDAC does not exist | 333 | * RAMDAC does not exist |
| 334 | * color depth = SUM(var->{color}.length}) | ||
| 335 | * | ||
| 336 | * The color depth is used by fbcon for choosing the logo and also | ||
| 337 | * for color palette transformation if color depth < 4 | ||
| 338 | * | ||
| 339 | * As can be seen from the above, the field bits_per_pixel is _NOT_ | ||
| 340 | * a criteria for describing the color visual. | ||
| 341 | * | ||
| 342 | * A common mistake is assuming that bits_per_pixel <= 8 is pseudocolor, | ||
| 343 | * and higher than that, true/directcolor. This is incorrect, one needs | ||
| 344 | * to look at the fix->visual. | ||
| 345 | * | ||
| 346 | * Another common mistake is using bits_per_pixel to calculate the color | ||
| 347 | * depth. The bits_per_pixel field does not directly translate to color | ||
| 348 | * depth. You have to compute for the color depth (using the color | ||
| 349 | * bitfields) and fix->visual as seen above. | ||
| 350 | */ | ||
| 351 | |||
| 352 | /* | ||
| 353 | * This is the point where the color is converted to something that | ||
| 354 | * is acceptable by the hardware. | ||
| 277 | */ | 355 | */ |
| 278 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 356 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) |
| 279 | switch (info->fix.visual) { | 357 | red = CNVT_TOHW(red, info->var.red.length); |
| 280 | case FB_VISUAL_TRUECOLOR: | 358 | green = CNVT_TOHW(green, info->var.green.length); |
| 281 | case FB_VISUAL_PSEUDOCOLOR: | 359 | blue = CNVT_TOHW(blue, info->var.blue.length); |
| 282 | red = CNVT_TOHW(red, info->var.red.length); | 360 | transp = CNVT_TOHW(transp, info->var.transp.length); |
| 283 | green = CNVT_TOHW(green, info->var.green.length); | ||
| 284 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
| 285 | transp = CNVT_TOHW(transp, info->var.transp.length); | ||
| 286 | break; | ||
| 287 | case FB_VISUAL_DIRECTCOLOR: | ||
| 288 | /* example here assumes 8 bit DAC. Might be different | ||
| 289 | * for your hardware */ | ||
| 290 | red = CNVT_TOHW(red, 8); | ||
| 291 | green = CNVT_TOHW(green, 8); | ||
| 292 | blue = CNVT_TOHW(blue, 8); | ||
| 293 | /* hey, there is bug in transp handling... */ | ||
| 294 | transp = CNVT_TOHW(transp, 8); | ||
| 295 | break; | ||
| 296 | } | ||
| 297 | #undef CNVT_TOHW | 361 | #undef CNVT_TOHW |
| 298 | /* Truecolor has hardware independent palette */ | 362 | /* |
| 299 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | 363 | * This is the point where the function feeds the color to the hardware |
| 300 | u32 v; | 364 | * palette after converting the colors to something acceptable by |
| 301 | 365 | * the hardware. Note, only FB_VISUAL_DIRECTCOLOR and | |
| 302 | if (regno >= 16) | 366 | * FB_VISUAL_PSEUDOCOLOR visuals need to write to the hardware palette. |
| 303 | return -EINVAL; | 367 | * If you have code that writes to the hardware CLUT, and it's not |
| 304 | 368 | * any of the above visuals, then you are doing something wrong. | |
| 305 | v = (red << info->var.red.offset) | | 369 | */ |
| 306 | (green << info->var.green.offset) | | 370 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || |
| 307 | (blue << info->var.blue.offset) | | 371 | info->fix.visual == FB_VISUAL_TRUECOLOR) |
| 308 | (transp << info->var.transp.offset); | 372 | write_{red|green|blue|transp}_to_clut(); |
| 309 | 373 | ||
| 310 | switch (info->var.bits_per_pixel) { | 374 | /* This is the point were you need to fill up the contents of |
| 311 | case 8: | 375 | * info->pseudo_palette. This structure is used _only_ by fbcon, thus |
| 312 | /* Yes some hand held devices have this. */ | 376 | * it only contains 16 entries to match the number of colors supported |
| 313 | ((u8*)(info->pseudo_palette))[regno] = v; | 377 | * by the console. The pseudo_palette is used only if the visual is |
| 314 | break; | 378 | * in directcolor or truecolor mode. With other visuals, the |
| 315 | case 16: | 379 | * pseudo_palette is not used. (This might change in the future.) |
| 316 | ((u16*)(info->pseudo_palette))[regno] = v; | 380 | * |
| 317 | break; | 381 | * The contents of the pseudo_palette is in raw pixel format. Ie, each |
| 318 | case 24: | 382 | * entry can be written directly to the framebuffer without any conversion. |
| 319 | case 32: | 383 | * The pseudo_palette is (void *). However, if using the generic |
| 320 | ((u32*)(info->pseudo_palette))[regno] = v; | 384 | * drawing functions (cfb_imageblit, cfb_fillrect), the pseudo_palette |
| 321 | break; | 385 | * must be casted to (u32 *) _regardless_ of the bits per pixel. If the |
| 322 | } | 386 | * driver is using its own drawing functions, then it can use whatever |
| 323 | return 0; | 387 | * size it wants. |
| 388 | */ | ||
| 389 | if (info->fix.visual == FB_VISUAL_TRUECOLOR || | ||
| 390 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
| 391 | u32 v; | ||
| 392 | |||
| 393 | if (regno >= 16) | ||
| 394 | return -EINVAL; | ||
| 395 | |||
| 396 | v = (red << info->var.red.offset) | | ||
| 397 | (green << info->var.green.offset) | | ||
| 398 | (blue << info->var.blue.offset) | | ||
| 399 | (transp << info->var.transp.offset); | ||
| 400 | |||
| 401 | ((u32*)(info->pseudo_palette))[regno] = v; | ||
| 324 | } | 402 | } |
| 403 | |||
| 325 | /* ... */ | 404 | /* ... */ |
| 326 | return 0; | 405 | return 0; |
| 327 | } | 406 | } |
| @@ -340,6 +419,17 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
| 340 | static int xxxfb_pan_display(struct fb_var_screeninfo *var, | 419 | static int xxxfb_pan_display(struct fb_var_screeninfo *var, |
| 341 | const struct fb_info *info) | 420 | const struct fb_info *info) |
| 342 | { | 421 | { |
| 422 | /* | ||
| 423 | * If your hardware does not support panning, _do_ _not_ implement this | ||
| 424 | * function. Creating a dummy function will just confuse user apps. | ||
| 425 | */ | ||
| 426 | |||
| 427 | /* | ||
| 428 | * Note that even if this function is fully functional, a setting of | ||
| 429 | * 0 in both xpanstep and ypanstep means that this function will never | ||
| 430 | * get called. | ||
| 431 | */ | ||
| 432 | |||
| 343 | /* ... */ | 433 | /* ... */ |
| 344 | return 0; | 434 | return 0; |
| 345 | } | 435 | } |
| @@ -349,15 +439,20 @@ static int xxxfb_pan_display(struct fb_var_screeninfo *var, | |||
| 349 | * @blank_mode: the blank mode we want. | 439 | * @blank_mode: the blank mode we want. |
| 350 | * @info: frame buffer structure that represents a single frame buffer | 440 | * @info: frame buffer structure that represents a single frame buffer |
| 351 | * | 441 | * |
| 352 | * Blank the screen if blank_mode != 0, else unblank. Return 0 if | 442 | * Blank the screen if blank_mode != FB_BLANK_UNBLANK, else unblank. |
| 353 | * blanking succeeded, != 0 if un-/blanking failed due to e.g. a | 443 | * Return 0 if blanking succeeded, != 0 if un-/blanking failed due to |
| 354 | * video mode which doesn't support it. Implements VESA suspend | 444 | * e.g. a video mode which doesn't support it. |
| 355 | * and powerdown modes on hardware that supports disabling hsync/vsync: | ||
| 356 | * blank_mode == 2: suspend vsync | ||
| 357 | * blank_mode == 3: suspend hsync | ||
| 358 | * blank_mode == 4: powerdown | ||
| 359 | * | 445 | * |
| 360 | * Returns negative errno on error, or zero on success. | 446 | * Implements VESA suspend and powerdown modes on hardware that supports |
| 447 | * disabling hsync/vsync: | ||
| 448 | * | ||
| 449 | * FB_BLANK_NORMAL = display is blanked, syncs are on. | ||
| 450 | * FB_BLANK_HSYNC_SUSPEND = hsync off | ||
| 451 | * FB_BLANK_VSYNC_SUSPEND = vsync off | ||
| 452 | * FB_BLANK_POWERDOWN = hsync and vsync off | ||
| 453 | * | ||
| 454 | * If implementing this function, at least support FB_BLANK_UNBLANK. | ||
| 455 | * Return !0 for any modes that are unimplemented. | ||
| 361 | * | 456 | * |
| 362 | */ | 457 | */ |
| 363 | static int xxxfb_blank(int blank_mode, const struct fb_info *info) | 458 | static int xxxfb_blank(int blank_mode, const struct fb_info *info) |
| @@ -454,6 +549,14 @@ void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) | |||
| 454 | * @data: The actual data used to construct the image on the display. | 549 | * @data: The actual data used to construct the image on the display. |
| 455 | * @cmap: The colormap used for color images. | 550 | * @cmap: The colormap used for color images. |
| 456 | */ | 551 | */ |
| 552 | |||
| 553 | /* | ||
| 554 | * The generic function, cfb_imageblit, expects that the bitmap scanlines are | ||
| 555 | * padded to the next byte. Most hardware accelerators may require padding to | ||
| 556 | * the next u16 or the next u32. If that is the case, the driver can specify | ||
| 557 | * this by setting info->pixmap.scan_align = 2 or 4. See a more | ||
| 558 | * comprehensive description of the pixmap below. | ||
| 559 | */ | ||
| 457 | } | 560 | } |
| 458 | 561 | ||
| 459 | /** | 562 | /** |
| @@ -517,6 +620,7 @@ int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
| 517 | */ | 620 | */ |
| 518 | void xxxfb_rotate(struct fb_info *info, int angle) | 621 | void xxxfb_rotate(struct fb_info *info, int angle) |
| 519 | { | 622 | { |
| 623 | /* Will be deprecated */ | ||
| 520 | } | 624 | } |
| 521 | 625 | ||
| 522 | /** | 626 | /** |
| @@ -540,6 +644,9 @@ void xxxfb_poll(struct fb_info *info, poll_table *wait) | |||
| 540 | * so we can have consistent display output. | 644 | * so we can have consistent display output. |
| 541 | * | 645 | * |
| 542 | * @info: frame buffer structure that represents a single frame buffer | 646 | * @info: frame buffer structure that represents a single frame buffer |
| 647 | * | ||
| 648 | * If the driver has implemented its own hardware-based drawing function, | ||
| 649 | * implementing this function is highly recommended. | ||
| 543 | */ | 650 | */ |
| 544 | void xxxfb_sync(struct fb_info *info) | 651 | void xxxfb_sync(struct fb_info *info) |
| 545 | { | 652 | { |
| @@ -549,20 +656,25 @@ void xxxfb_sync(struct fb_info *info) | |||
| 549 | * Initialization | 656 | * Initialization |
| 550 | */ | 657 | */ |
| 551 | 658 | ||
| 552 | int __init xxxfb_init(void) | 659 | /* static int __init xxfb_probe (struct device *device) -- for platform devs */ |
| 660 | static int __init xxxfb_probe(struct pci_dev *dev, | ||
| 661 | const_struct pci_device_id *ent) | ||
| 553 | { | 662 | { |
| 663 | struct fb_info *info; | ||
| 664 | struct xxx_par *par; | ||
| 665 | struct device = &dev->dev; /* for pci drivers */ | ||
| 554 | int cmap_len, retval; | 666 | int cmap_len, retval; |
| 555 | 667 | ||
| 556 | /* | 668 | /* |
| 557 | * For kernel boot options (in 'video=xxxfb:<options>' format) | 669 | * Dynamically allocate info and par |
| 558 | */ | 670 | */ |
| 559 | #ifndef MODULE | 671 | info = framebuffer_alloc(sizeof(struct xxx_par), device); |
| 560 | char *option = NULL; | ||
| 561 | 672 | ||
| 562 | if (fb_get_options("xxxfb", &option)) | 673 | if (!info) { |
| 563 | return -ENODEV; | 674 | /* goto error path */ |
| 564 | xxxfb_setup(option); | 675 | } |
| 565 | #endif | 676 | |
| 677 | par = info->par; | ||
| 566 | 678 | ||
| 567 | /* | 679 | /* |
| 568 | * Here we set the screen_base to the virtual memory address | 680 | * Here we set the screen_base to the virtual memory address |
| @@ -570,18 +682,87 @@ int __init xxxfb_init(void) | |||
| 570 | * from the bus layer and then translate it to virtual memory | 682 | * from the bus layer and then translate it to virtual memory |
| 571 | * space via ioremap. Consult ioport.h. | 683 | * space via ioremap. Consult ioport.h. |
| 572 | */ | 684 | */ |
| 573 | info.screen_base = framebuffer_virtual_memory; | 685 | info->screen_base = framebuffer_virtual_memory; |
| 574 | info.fbops = &xxxfb_ops; | 686 | info->fbops = &xxxfb_ops; |
| 575 | info.fix = xxxfb_fix; | 687 | info->fix = xxxfb_fix; /* this will be the only time xxxfb_fix will be |
| 576 | info.pseudo_palette = pseudo_palette; | 688 | * used, so mark it as __initdata |
| 577 | 689 | */ | |
| 690 | info->pseudo_palette = pseudo_palette; /* The pseudopalette is an | ||
| 691 | * 16-member array | ||
| 692 | */ | ||
| 578 | /* | 693 | /* |
| 579 | * Set up flags to indicate what sort of acceleration your | 694 | * Set up flags to indicate what sort of acceleration your |
| 580 | * driver can provide (pan/wrap/copyarea/etc.) and whether it | 695 | * driver can provide (pan/wrap/copyarea/etc.) and whether it |
| 581 | * is a module -- see FBINFO_* in include/linux/fb.h | 696 | * is a module -- see FBINFO_* in include/linux/fb.h |
| 697 | * | ||
| 698 | * If your hardware can support any of the hardware accelerated functions | ||
| 699 | * fbcon performance will improve if info->flags is set properly. | ||
| 700 | * | ||
| 701 | * FBINFO_HWACCEL_COPYAREA - hardware moves | ||
| 702 | * FBINFO_HWACCEL_FILLRECT - hardware fills | ||
| 703 | * FBINFO_HWACCEL_IMAGEBLIT - hardware mono->color expansion | ||
| 704 | * FBINFO_HWACCEL_YPAN - hardware can pan display in y-axis | ||
| 705 | * FBINFO_HWACCEL_YWRAP - hardware can wrap display in y-axis | ||
| 706 | * FBINFO_HWACCEL_DISABLED - supports hardware accels, but disabled | ||
| 707 | * FBINFO_READS_FAST - if set, prefer moves over mono->color expansion | ||
| 708 | * FBINFO_MISC_TILEBLITTING - hardware can do tile blits | ||
| 709 | * | ||
| 710 | * NOTE: These are for fbcon use only. | ||
| 711 | */ | ||
| 712 | info->flags = FBINFO_DEFAULT; | ||
| 713 | |||
| 714 | /********************* This stage is optional ******************************/ | ||
| 715 | /* | ||
| 716 | * The struct pixmap is a scratch pad for the drawing functions. This | ||
| 717 | * is where the monochrome bitmap is constructed by the higher layers | ||
| 718 | * and then passed to the accelerator. For drivers that uses | ||
| 719 | * cfb_imageblit, you can skip this part. For those that have a more | ||
| 720 | * rigorous requirement, this stage is needed | ||
| 721 | */ | ||
| 722 | |||
| 723 | /* PIXMAP_SIZE should be small enough to optimize drawing, but not | ||
| 724 | * large enough that memory is wasted. A safe size is | ||
| 725 | * (max_xres * max_font_height/8). max_xres is driver dependent, | ||
| 726 | * max_font_height is 32. | ||
| 727 | */ | ||
| 728 | info->pixmap.addr = kmalloc(PIXMAP_SIZE, GFP_KERNEL); | ||
| 729 | if (!info->pixmap.addr) { | ||
| 730 | /* goto error */ | ||
| 731 | } | ||
| 732 | |||
| 733 | info->pixmap.size = PIXMAP_SIZE; | ||
| 734 | |||
| 735 | /* | ||
| 736 | * FB_PIXMAP_SYSTEM - memory is in system ram | ||
| 737 | * FB_PIXMAP_IO - memory is iomapped | ||
| 738 | * FB_PIXMAP_SYNC - if set, will call fb_sync() per access to pixmap, | ||
| 739 | * usually if FB_PIXMAP_IO is set. | ||
| 740 | * | ||
| 741 | * Currently, FB_PIXMAP_IO is unimplemented. | ||
| 742 | */ | ||
| 743 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
| 744 | |||
| 745 | /* | ||
| 746 | * scan_align is the number of padding for each scanline. It is in bytes. | ||
| 747 | * Thus for accelerators that need padding to the next u32, put 4 here. | ||
| 748 | */ | ||
| 749 | info->pixmap.scan_align = 4; | ||
| 750 | |||
| 751 | /* | ||
| 752 | * buf_align is the amount to be padded for the buffer. For example, | ||
| 753 | * the i810fb needs a scan_align of 2 but expects it to be fed with | ||
| 754 | * dwords, so a buf_align = 4 is required. | ||
| 582 | */ | 755 | */ |
| 583 | info.flags = FBINFO_DEFAULT; | 756 | info->pixmap.buf_align = 4; |
| 584 | info.par = current_par; | 757 | |
| 758 | /* access_align is how many bits can be accessed from the framebuffer | ||
| 759 | * ie. some epson cards allow 16-bit access only. Most drivers will | ||
| 760 | * be safe with u32 here. | ||
| 761 | * | ||
| 762 | * NOTE: This field is currently unused. | ||
| 763 | */ | ||
| 764 | info->pixmap.scan_align = 32 | ||
| 765 | /***************************** End optional stage ***************************/ | ||
| 585 | 766 | ||
| 586 | /* | 767 | /* |
| 587 | * This should give a reasonable default video mode. The following is | 768 | * This should give a reasonable default video mode. The following is |
| @@ -590,42 +771,145 @@ int __init xxxfb_init(void) | |||
| 590 | if (!mode_option) | 771 | if (!mode_option) |
| 591 | mode_option = "640x480@60"; | 772 | mode_option = "640x480@60"; |
| 592 | 773 | ||
| 593 | retval = fb_find_mode(&info.var, &info, mode_option, NULL, 0, NULL, 8); | 774 | retval = fb_find_mode(info->var, info, mode_option, NULL, 0, NULL, 8); |
| 594 | 775 | ||
| 595 | if (!retval || retval == 4) | 776 | if (!retval || retval == 4) |
| 596 | return -EINVAL; | 777 | return -EINVAL; |
| 597 | 778 | ||
| 598 | /* This has to been done !!! */ | 779 | /* This has to been done !!! */ |
| 599 | fb_alloc_cmap(&info.cmap, cmap_len, 0); | 780 | fb_alloc_cmap(info->cmap, cmap_len, 0); |
| 600 | 781 | ||
| 601 | /* | 782 | /* |
| 602 | * The following is done in the case of having hardware with a static | 783 | * The following is done in the case of having hardware with a static |
| 603 | * mode. If we are setting the mode ourselves we don't call this. | 784 | * mode. If we are setting the mode ourselves we don't call this. |
| 604 | */ | 785 | */ |
| 605 | info.var = xxxfb_var; | 786 | info->var = xxxfb_var; |
| 606 | 787 | ||
| 607 | if (register_framebuffer(&info) < 0) | 788 | /* |
| 789 | * For drivers that can... | ||
| 790 | */ | ||
| 791 | xxxfb_check_var(&info->var, info); | ||
| 792 | |||
| 793 | /* | ||
| 794 | * Does a call to fb_set_par() before register_framebuffer needed? This | ||
| 795 | * will depend on you and the hardware. If you are sure that your driver | ||
| 796 | * is the only device in the system, a call to fb_set_par() is safe. | ||
| 797 | * | ||
| 798 | * Hardware in x86 systems has a VGA core. Calling set_par() at this | ||
| 799 | * point will corrupt the VGA console, so it might be safer to skip a | ||
| 800 | * call to set_par here and just allow fbcon to do it for you. | ||
| 801 | */ | ||
| 802 | /* xxxfb_set_par(info); */ | ||
| 803 | |||
| 804 | if (register_framebuffer(info) < 0) | ||
| 608 | return -EINVAL; | 805 | return -EINVAL; |
| 609 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info.node, | 806 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
| 610 | info.fix.id); | 807 | info->fix.id); |
| 808 | pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */ | ||
| 611 | return 0; | 809 | return 0; |
| 612 | } | 810 | } |
| 613 | 811 | ||
| 614 | /* | 812 | /* |
| 615 | * Cleanup | 813 | * Cleanup |
| 616 | */ | 814 | */ |
| 815 | /* static void __exit xxxfb_remove(struct device *device) */ | ||
| 816 | static void __exit xxxfb_remove(struct pci_dev *dev) | ||
| 817 | { | ||
| 818 | struct fb_info *info = pci_get_drv_data(dev); | ||
| 819 | /* or dev_get_drv_data(device); */ | ||
| 820 | |||
| 821 | if (info) { | ||
| 822 | unregister_framebuffer(info); | ||
| 823 | fb_dealloc_cmap(&info.cmap); | ||
| 824 | /* ... */ | ||
| 825 | framebuffer_release(info); | ||
| 826 | } | ||
| 827 | |||
| 828 | return 0; | ||
| 829 | } | ||
| 617 | 830 | ||
| 618 | static void __exit xxxfb_cleanup(void) | 831 | #if CONFIG_PCI |
| 832 | /* For PCI drivers */ | ||
| 833 | static struct pci_driver xxxfb_driver = { | ||
| 834 | .name = "xxxfb", | ||
| 835 | .id_table = xxxfb_devices, | ||
| 836 | .probe = xxxfb_probe, | ||
| 837 | .remove = __devexit_p(xxxfb_remove), | ||
| 838 | .suspend = xxxfb_suspend, /* optional */ | ||
| 839 | .resume = xxxfb_resume, /* optional */ | ||
| 840 | }; | ||
| 841 | |||
| 842 | static int __init xxxfb_init(void) | ||
| 619 | { | 843 | { |
| 620 | /* | 844 | /* |
| 621 | * If your driver supports multiple boards, you should unregister and | 845 | * For kernel boot options (in 'video=xxxfb:<options>' format) |
| 622 | * clean up all instances. | 846 | */ |
| 623 | */ | 847 | #ifndef MODULE |
| 848 | char *option = NULL; | ||
| 624 | 849 | ||
| 625 | unregister_framebuffer(info); | 850 | if (fb_get_options("xxxfb", &option)) |
| 626 | fb_dealloc_cmap(&info.cmap); | 851 | return -ENODEV; |
| 627 | /* ... */ | 852 | xxxfb_setup(option); |
| 853 | #endif | ||
| 854 | |||
| 855 | return pci_register_driver(&xxxfb_driver); | ||
| 856 | } | ||
| 857 | |||
| 858 | static void __exit xxxfb_exit(void) | ||
| 859 | { | ||
| 860 | pci_unregister_driver(&xxxfb_driver); | ||
| 628 | } | 861 | } |
| 862 | #else | ||
| 863 | #include <linux/platform_device.h> | ||
| 864 | /* for platform devices */ | ||
| 865 | static struct device_driver xxxfb_driver = { | ||
| 866 | .name = "xxxfb", | ||
| 867 | .bus = &platform_bus_type, | ||
| 868 | .probe = xxxfb_probe, | ||
| 869 | .remove = xxxfb_remove, | ||
| 870 | .suspend = xxxfb_suspend, /* optional */ | ||
| 871 | .resume = xxxfb_resume, /* optional */ | ||
| 872 | }; | ||
| 873 | |||
| 874 | static struct platform_device xxxfb_device = { | ||
| 875 | .name = "xxxfb", | ||
| 876 | }; | ||
| 877 | |||
| 878 | static int __init xxxfb_init(void) | ||
| 879 | { | ||
| 880 | int ret; | ||
| 881 | /* | ||
| 882 | * For kernel boot options (in 'video=xxxfb:<options>' format) | ||
| 883 | */ | ||
| 884 | #ifndef MODULE | ||
| 885 | char *option = NULL; | ||
| 886 | |||
| 887 | if (fb_get_options("xxxfb", &option)) | ||
| 888 | return -ENODEV; | ||
| 889 | xxxfb_setup(option); | ||
| 890 | #endif | ||
| 891 | ret = driver_register(&xxxfb_driver); | ||
| 892 | |||
| 893 | if (!ret) { | ||
| 894 | ret = platform_device_register(&xxxfb_device); | ||
| 895 | if (ret) | ||
| 896 | driver_unregister(&xxxfb_driver); | ||
| 897 | } | ||
| 898 | |||
| 899 | return ret; | ||
| 900 | } | ||
| 901 | |||
| 902 | static void __exit xxxfb_exit(void) | ||
| 903 | { | ||
| 904 | platform_device_unregister(&xxxfb_device); | ||
| 905 | driver_unregister(&xxxfb_driver); | ||
| 906 | } | ||
| 907 | #endif | ||
| 908 | |||
| 909 | MODULE_LICENSE("GPL"); | ||
| 910 | module_init(xxxfb_init); | ||
| 911 | module_exit(xxxfb_exit); | ||
| 912 | |||
| 629 | 913 | ||
| 630 | /* | 914 | /* |
| 631 | * Setup | 915 | * Setup |
