linux/drivers/staging/sm750fb/sm750.c
<<
>>
Prefs
   1#include<linux/kernel.h>
   2#include<linux/module.h>
   3#include<linux/errno.h>
   4#include<linux/string.h>
   5#include<linux/mm.h>
   6#include<linux/slab.h>
   7#include<linux/delay.h>
   8#include<linux/fb.h>
   9#include<linux/ioport.h>
  10#include<linux/init.h>
  11#include<linux/pci.h>
  12#include<linux/mm_types.h>
  13#include<linux/vmalloc.h>
  14#include<linux/pagemap.h>
  15#include<linux/screen_info.h>
  16#include<linux/vmalloc.h>
  17#include<linux/pagemap.h>
  18#include <linux/console.h>
  19#ifdef CONFIG_MTRR
  20#include <asm/mtrr.h>
  21#endif
  22#include <asm/fb.h>
  23#include "sm750.h"
  24#include "sm750_hw.h"
  25#include "sm750_accel.h"
  26#include "sm750_cursor.h"
  27
  28#include "modedb.h"
  29
  30int smi_indent = 0;
  31
  32
  33/*
  34 * #ifdef __BIG_ENDIAN
  35 * ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf,
  36 * size_t count, loff_t *ppos);
  37 * ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf,
  38 * size_t count, loff_t *ppos);
  39 * #endif
  40 */
  41
  42typedef void (*PROC_SPEC_SETUP)(struct lynx_share*, char *);
  43typedef int (*PROC_SPEC_MAP)(struct lynx_share*, struct pci_dev*);
  44typedef int (*PROC_SPEC_INITHW)(struct lynx_share*, struct pci_dev*);
  45
  46
  47/* common var for all device */
  48static int g_hwcursor = 1;
  49static int g_noaccel;
  50#ifdef CONFIG_MTRR
  51static int g_nomtrr;
  52#endif
  53static const char *g_fbmode[] = {NULL, NULL};
  54static const char *g_def_fbmode = "800x600-16@60";
  55static char *g_settings = NULL;
  56static int g_dualview;
  57static char *g_option = NULL;
  58
  59
  60static const struct fb_videomode lynx750_ext[] = {
  61        /*      1024x600-60 VESA        [1.71:1] */
  62        {NULL,  60, 1024, 600, 20423, 144,  40, 18, 1, 104, 3,
  63         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  64         FB_VMODE_NONINTERLACED},
  65
  66        /*      1024x600-70 VESA */
  67        {NULL,  70, 1024, 600, 17211, 152,  48, 21, 1, 104, 3,
  68         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  69         FB_VMODE_NONINTERLACED},
  70
  71        /*      1024x600-75 VESA */
  72        {NULL,  75, 1024, 600, 15822, 160,  56, 23, 1, 104, 3,
  73         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  74         FB_VMODE_NONINTERLACED},
  75
  76        /*      1024x600-85 VESA */
  77        {NULL,  85, 1024, 600, 13730, 168,  56, 26, 1, 112, 3,
  78         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  79         FB_VMODE_NONINTERLACED},
  80
  81        /*      720x480 */
  82        {NULL, 60,  720,  480,  37427, 88,   16, 13, 1,   72,  3,
  83         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  84         FB_VMODE_NONINTERLACED},
  85
  86        /*      1280x720                [1.78:1]        */
  87        {NULL, 60,  1280,  720,  13426, 162, 86, 22, 1,  136, 3,
  88         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  89         FB_VMODE_NONINTERLACED},
  90
  91        /*      1280x768@60 */
  92        {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
  93         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  94         FB_VMODE_NONINTERLACED},
  95
  96        {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
  97         FB_SYNC_HOR_HIGH_ACT|FB_VMODE_NONINTERLACED},
  98
  99        /*      1360 x 768      [1.77083:1]     */
 100        {NULL,  60, 1360, 768, 11804, 208,  64, 23, 1, 144, 3,
 101         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 102         FB_VMODE_NONINTERLACED},
 103
 104        /*      1368 x 768      [1.78:1]        */
 105        {NULL, 60,  1368,  768,  11647, 216, 72, 23, 1,  144, 3,
 106         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 107         FB_VMODE_NONINTERLACED},
 108
 109        /*      1440 x 900              [16:10] */
 110        {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
 111         FB_SYNC_VERT_HIGH_ACT,
 112         FB_VMODE_NONINTERLACED},
 113
 114        /*      1440x960                [15:10] */
 115        {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
 116         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 117         FB_VMODE_NONINTERLACED},
 118
 119        /*      1920x1080       [16:9]  */
 120        {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
 121         FB_SYNC_VERT_HIGH_ACT,
 122         FB_VMODE_NONINTERLACED},
 123};
 124
 125
 126
 127
 128/* no hardware cursor supported under version 2.6.10, kernel bug */
 129static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
 130{
 131        struct lynxfb_par *par;
 132        struct lynxfb_crtc *crtc;
 133        struct lynx_cursor *cursor;
 134
 135        par = info->par;
 136        crtc = &par->crtc;
 137        cursor = &crtc->cursor;
 138
 139        if (fbcursor->image.width > cursor->maxW ||
 140           fbcursor->image.height > cursor->maxH ||
 141           fbcursor->image.depth > 1) {
 142                return -ENXIO;
 143        }
 144
 145        cursor->disable(cursor);
 146        if (fbcursor->set & FB_CUR_SETSIZE)
 147                cursor->setSize(cursor,
 148                                fbcursor->image.width,
 149                                fbcursor->image.height);
 150
 151        if (fbcursor->set & FB_CUR_SETPOS)
 152                cursor->setPos(cursor,
 153                               fbcursor->image.dx - info->var.xoffset,
 154                               fbcursor->image.dy - info->var.yoffset);
 155
 156        if (fbcursor->set & FB_CUR_SETCMAP) {
 157                /* get the 16bit color of kernel means */
 158                u16 fg, bg;
 159
 160                fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800))|
 161                      ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5)|
 162                      ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11);
 163
 164                bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800))|
 165                      ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5)|
 166                      ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11);
 167
 168                cursor->setColor(cursor, fg, bg);
 169        }
 170
 171
 172        if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
 173                cursor->setData(cursor,
 174                                fbcursor->rop,
 175                                fbcursor->image.data,
 176                                fbcursor->mask);
 177        }
 178
 179        if (fbcursor->enable)
 180                cursor->enable(cursor);
 181
 182        return 0;
 183}
 184
 185static void lynxfb_ops_fillrect(struct fb_info *info,
 186                                const struct fb_fillrect *region)
 187{
 188        struct lynxfb_par *par;
 189        struct lynx_share *share;
 190        unsigned int base, pitch, Bpp, rop;
 191        u32 color;
 192
 193        if (info->state != FBINFO_STATE_RUNNING)
 194                return;
 195
 196        par = info->par;
 197        share = par->share;
 198
 199        /* each time 2d function begin to work,below three variable always need
 200         * be set, seems we can put them together in some place  */
 201        base = par->crtc.oScreen;
 202        pitch = info->fix.line_length;
 203        Bpp = info->var.bits_per_pixel >> 3;
 204
 205        color = (Bpp == 1)?region->color:((u32 *)info->pseudo_palette)[region->color];
 206        rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR:HW_ROP2_COPY;
 207
 208        /*
 209         * If not use spin_lock,system will die if user load driver
 210         * and immediatly unload driver frequently (dual)
 211         */
 212        if (share->dual)
 213                spin_lock(&share->slock);
 214
 215        share->accel.de_fillrect(&share->accel,
 216                                 base, pitch, Bpp,
 217                                 region->dx, region->dy,
 218                                 region->width, region->height,
 219                                 color, rop);
 220        if (share->dual)
 221                spin_unlock(&share->slock);
 222}
 223
 224static void lynxfb_ops_copyarea(struct fb_info *info,
 225                                const struct fb_copyarea *region)
 226{
 227        struct lynxfb_par *par;
 228        struct lynx_share *share;
 229        unsigned int base, pitch, Bpp;
 230
 231        par = info->par;
 232        share = par->share;
 233
 234        /* each time 2d function begin to work,below three variable always need
 235         * be set, seems we can put them together in some place  */
 236        base = par->crtc.oScreen;
 237        pitch = info->fix.line_length;
 238        Bpp = info->var.bits_per_pixel >> 3;
 239
 240        /*
 241         * If not use spin_lock, system will die if user load driver
 242         * and immediatly unload driver frequently (dual)
 243         */
 244        if (share->dual)
 245                spin_lock(&share->slock);
 246
 247        share->accel.de_copyarea(&share->accel,
 248                                 base, pitch, region->sx, region->sy,
 249                                 base, pitch, Bpp, region->dx, region->dy,
 250                                 region->width, region->height, HW_ROP2_COPY);
 251        if (share->dual)
 252                spin_unlock(&share->slock);
 253}
 254
 255static void lynxfb_ops_imageblit(struct fb_info *info,
 256                                 const struct fb_image *image)
 257{
 258        unsigned int base, pitch, Bpp;
 259        unsigned int fgcol, bgcol;
 260        struct lynxfb_par *par;
 261        struct lynx_share *share;
 262
 263        par = info->par;
 264        share = par->share;
 265        /* each time 2d function begin to work,below three variable always need
 266         * be set, seems we can put them together in some place  */
 267        base = par->crtc.oScreen;
 268        pitch = info->fix.line_length;
 269        Bpp = info->var.bits_per_pixel >> 3;
 270
 271        if (image->depth == 1) {
 272                if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 273                    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 274                        fgcol = ((u32 *)info->pseudo_palette)[image->fg_color];
 275                        bgcol = ((u32 *)info->pseudo_palette)[image->bg_color];
 276                } else {
 277                        fgcol = image->fg_color;
 278                        bgcol = image->bg_color;
 279                }
 280                goto _do_work;
 281        }
 282        return;
 283_do_work:
 284        /*
 285         * If not use spin_lock, system will die if user load driver
 286         * and immediatly unload driver frequently (dual)
 287         */
 288        if (share->dual)
 289                spin_lock(&share->slock);
 290
 291        share->accel.de_imageblit(&share->accel,
 292                                  image->data, image->width>>3, 0,
 293                                  base, pitch, Bpp,
 294                                  image->dx, image->dy,
 295                                  image->width, image->height,
 296                                  fgcol, bgcol, HW_ROP2_COPY);
 297        if (share->dual)
 298                spin_unlock(&share->slock);
 299}
 300
 301static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var,
 302                                  struct fb_info *info)
 303{
 304        struct lynxfb_par *par;
 305        struct lynxfb_crtc *crtc;
 306        int ret;
 307
 308
 309        if (!info)
 310                return -EINVAL;
 311
 312        ret = 0;
 313        par = info->par;
 314        crtc = &par->crtc;
 315        ret = crtc->proc_panDisplay(crtc, var, info);
 316
 317        return ret;
 318}
 319
 320static int lynxfb_ops_set_par(struct fb_info *info)
 321{
 322        struct lynxfb_par *par;
 323        struct lynx_share *share;
 324        struct lynxfb_crtc *crtc;
 325        struct lynxfb_output *output;
 326        struct fb_var_screeninfo *var;
 327        struct fb_fix_screeninfo *fix;
 328        int ret;
 329        unsigned int line_length;
 330
 331        if (!info)
 332                return -EINVAL;
 333
 334        ret = 0;
 335        par = info->par;
 336        share = par->share;
 337        crtc = &par->crtc;
 338        output = &par->output;
 339        var = &info->var;
 340        fix = &info->fix;
 341
 342        /* fix structur is not so FIX ... */
 343        line_length = var->xres_virtual * var->bits_per_pixel / 8;
 344        line_length = PADDING(crtc->line_pad, line_length);
 345        fix->line_length = line_length;
 346        pr_err("fix->line_length = %d\n", fix->line_length);
 347
 348        /* var->red,green,blue,transp are need to be set by driver
 349         * and these data should be set before setcolreg routine
 350         * */
 351
 352        switch (var->bits_per_pixel) {
 353        case 8:
 354                fix->visual = FB_VISUAL_PSEUDOCOLOR;
 355                var->red.offset = 0;
 356                var->red.length = 8;
 357                var->green.offset = 0;
 358                var->green.length = 8;
 359                var->blue.offset = 0;
 360                var->blue.length = 8;
 361                var->transp.length = 0;
 362                var->transp.offset = 0;
 363                break;
 364        case 16:
 365                var->red.offset = 11;
 366                var->red.length = 5;
 367                var->green.offset = 5;
 368                var->green.length = 6;
 369                var->blue.offset = 0;
 370                var->blue.length = 5;
 371                var->transp.length = 0;
 372                var->transp.offset = 0;
 373                fix->visual = FB_VISUAL_TRUECOLOR;
 374                break;
 375        case 24:
 376        case 32:
 377                var->red.offset = 16;
 378                var->red.length = 8;
 379                var->green.offset = 8;
 380                var->green.length = 8;
 381                var->blue.offset = 0;
 382                var->blue.length = 8;
 383                fix->visual = FB_VISUAL_TRUECOLOR;
 384                break;
 385        default:
 386                ret = -EINVAL;
 387                break;
 388        }
 389        var->height = var->width = -1;
 390        var->accel_flags = 0;/*FB_ACCELF_TEXT;*/
 391
 392        if (ret) {
 393                pr_err("pixel bpp format not satisfied\n.");
 394                return ret;
 395        }
 396        ret = crtc->proc_setMode(crtc, var, fix);
 397        if (!ret)
 398                ret = output->proc_setMode(output, var, fix);
 399        return ret;
 400}
 401
 402static inline unsigned int chan_to_field(unsigned int chan,
 403                                         struct fb_bitfield *bf)
 404{
 405        chan &= 0xffff;
 406        chan >>= 16 - bf->length;
 407        return chan << bf->offset;
 408}
 409
 410#ifdef CONFIG_PM
 411static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg)
 412{
 413        struct fb_info *info;
 414        struct lynx_share *share;
 415        int ret;
 416
 417        if (mesg.event == pdev->dev.power.power_state.event)
 418                return 0;
 419
 420        ret = 0;
 421        share = pci_get_drvdata(pdev);
 422        switch (mesg.event) {
 423        case PM_EVENT_FREEZE:
 424        case PM_EVENT_PRETHAW:
 425                pdev->dev.power.power_state = mesg;
 426                return 0;
 427        }
 428
 429        console_lock();
 430        if (mesg.event & PM_EVENT_SLEEP) {
 431                info = share->fbinfo[0];
 432                if (info)
 433                        /* 1 means do suspend */
 434                        fb_set_suspend(info, 1);
 435                info = share->fbinfo[1];
 436                if (info)
 437                        /* 1 means do suspend */
 438                        fb_set_suspend(info, 1);
 439
 440                ret = pci_save_state(pdev);
 441                if (ret) {
 442                        pr_err("error:%d occurred in pci_save_state\n", ret);
 443                        return ret;
 444                }
 445
 446                /* set chip to sleep mode */
 447                if (share->suspend)
 448                        (*share->suspend)(share);
 449
 450                pci_disable_device(pdev);
 451                ret = pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
 452                if (ret) {
 453                        pr_err("error:%d occurred in pci_set_power_state\n", ret);
 454                        return ret;
 455                }
 456        }
 457
 458        pdev->dev.power.power_state = mesg;
 459        console_unlock();
 460        return ret;
 461}
 462
 463static int lynxfb_resume(struct pci_dev *pdev)
 464{
 465        struct fb_info *info;
 466        struct lynx_share *share;
 467
 468        struct lynxfb_par *par;
 469        struct lynxfb_crtc *crtc;
 470        struct lynx_cursor *cursor;
 471
 472        int ret;
 473
 474
 475        ret = 0;
 476        share = pci_get_drvdata(pdev);
 477
 478        console_lock();
 479
 480        ret = pci_set_power_state(pdev, PCI_D0);
 481        if (ret) {
 482                pr_err("error:%d occured in pci_set_power_state\n", ret);
 483                return ret;
 484        }
 485
 486
 487        if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
 488                pci_restore_state(pdev);
 489                ret = pci_enable_device(pdev);
 490                if (ret) {
 491                        pr_err("error:%d occured in pci_enable_device\n", ret);
 492                        return ret;
 493                }
 494                pci_set_master(pdev);
 495        }
 496        if (share->resume)
 497                (*share->resume)(share);
 498
 499        hw_sm750_inithw(share, pdev);
 500
 501
 502        info = share->fbinfo[0];
 503
 504        if (info) {
 505                par = info->par;
 506                crtc = &par->crtc;
 507                cursor = &crtc->cursor;
 508                memset_io(cursor->vstart, 0x0, cursor->size);
 509                memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
 510                lynxfb_ops_set_par(info);
 511                fb_set_suspend(info, 0);
 512        }
 513
 514        info = share->fbinfo[1];
 515
 516        if (info) {
 517                par = info->par;
 518                crtc = &par->crtc;
 519                cursor = &crtc->cursor;
 520                memset_io(cursor->vstart, 0x0, cursor->size);
 521                memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
 522                lynxfb_ops_set_par(info);
 523                fb_set_suspend(info, 0);
 524        }
 525
 526
 527        console_unlock();
 528        return ret;
 529}
 530#endif
 531
 532static int lynxfb_ops_check_var(struct fb_var_screeninfo *var,
 533                                struct fb_info *info)
 534{
 535        struct lynxfb_par *par;
 536        struct lynxfb_crtc *crtc;
 537        struct lynxfb_output *output;
 538        struct lynx_share *share;
 539        int ret;
 540        resource_size_t request;
 541
 542
 543        par = info->par;
 544        crtc = &par->crtc;
 545        output = &par->output;
 546        share = par->share;
 547        ret = 0;
 548
 549        pr_debug("check var:%dx%d-%d\n",
 550                 var->xres,
 551                 var->yres,
 552                 var->bits_per_pixel);
 553
 554
 555        switch (var->bits_per_pixel) {
 556        case 8:
 557        case 16:
 558        case 24: /* support 24 bpp for only lynx712/722/720 */
 559        case 32:
 560                break;
 561        default:
 562                pr_err("bpp %d not supported\n", var->bits_per_pixel);
 563                ret = -EINVAL;
 564                goto exit;
 565        }
 566
 567        switch (var->bits_per_pixel) {
 568        case 8:
 569                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 570                var->red.offset = 0;
 571                var->red.length = 8;
 572                var->green.offset = 0;
 573                var->green.length = 8;
 574                var->blue.offset = 0;
 575                var->blue.length = 8;
 576                var->transp.length = 0;
 577                var->transp.offset = 0;
 578                break;
 579        case 16:
 580                var->red.offset = 11;
 581                var->red.length = 5;
 582                var->green.offset = 5;
 583                var->green.length = 6;
 584                var->blue.offset = 0;
 585                var->blue.length = 5;
 586                var->transp.length = 0;
 587                var->transp.offset = 0;
 588                info->fix.visual = FB_VISUAL_TRUECOLOR;
 589                break;
 590        case 24:
 591        case 32:
 592                var->red.offset = 16;
 593                var->red.length = 8;
 594                var->green.offset = 8;
 595                var->green.length = 8;
 596                var->blue.offset = 0;
 597                var->blue.length = 8;
 598                info->fix.visual = FB_VISUAL_TRUECOLOR;
 599                break;
 600        default:
 601                ret = -EINVAL;
 602                break;
 603        }
 604        var->height = var->width = -1;
 605        var->accel_flags = 0;/* FB_ACCELF_TEXT; */
 606
 607        /* check if current fb's video memory big enought to hold the onscreen*/
 608        request = var->xres_virtual * (var->bits_per_pixel >> 3);
 609        /* defaulty crtc->channel go with par->index */
 610
 611        request = PADDING(crtc->line_pad, request);
 612        request = request * var->yres_virtual;
 613        if (crtc->vidmem_size < request) {
 614                pr_err("not enough video memory for mode\n");
 615                return -ENOMEM;
 616        }
 617
 618        ret = output->proc_checkMode(output, var);
 619        if (!ret)
 620                ret = crtc->proc_checkMode(crtc, var);
 621exit:
 622        return ret;
 623}
 624
 625
 626static int lynxfb_ops_setcolreg(unsigned regno,
 627                                unsigned red,
 628                                unsigned green,
 629                                unsigned blue,
 630                                unsigned transp,
 631                                struct fb_info *info)
 632{
 633        struct lynxfb_par *par;
 634        struct lynxfb_crtc *crtc;
 635        struct fb_var_screeninfo *var;
 636        int ret;
 637
 638        par = info->par;
 639        crtc = &par->crtc;
 640        var = &info->var;
 641        ret = 0;
 642
 643        if (regno > 256) {
 644                pr_err("regno = %d\n", regno);
 645                return -EINVAL;
 646        }
 647
 648        if (info->var.grayscale)
 649                red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
 650
 651        if (var->bits_per_pixel == 8 &&
 652            info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
 653                red >>= 8;
 654                green >>= 8;
 655                blue >>= 8;
 656                ret = crtc->proc_setColReg(crtc, regno, red, green, blue);
 657                goto exit;
 658        }
 659
 660
 661        if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) {
 662                u32 val;
 663
 664                if (var->bits_per_pixel == 16 ||
 665                    var->bits_per_pixel == 32 ||
 666                    var->bits_per_pixel == 24) {
 667                        val = chan_to_field(red, &var->red);
 668                        val |= chan_to_field(green, &var->green);
 669                        val |= chan_to_field(blue, &var->blue);
 670                        par->pseudo_palette[regno] = val;
 671                        goto exit;
 672                }
 673        }
 674
 675        ret = -EINVAL;
 676
 677exit:
 678        return ret;
 679}
 680
 681static int lynxfb_ops_blank(int blank, struct fb_info *info)
 682{
 683        struct lynxfb_par *par;
 684        struct lynxfb_output *output;
 685
 686        pr_debug("blank = %d.\n", blank);
 687        par = info->par;
 688        output = &par->output;
 689        return output->proc_setBLANK(output, blank);
 690}
 691
 692static int sm750fb_set_drv(struct lynxfb_par *par)
 693{
 694        int ret;
 695        struct lynx_share *share;
 696        struct sm750_share *spec_share;
 697        struct lynxfb_output *output;
 698        struct lynxfb_crtc *crtc;
 699
 700        ret = 0;
 701
 702        share = par->share;
 703        spec_share = container_of(share, struct sm750_share, share);
 704        output = &par->output;
 705        crtc = &par->crtc;
 706
 707        crtc->vidmem_size = (share->dual)?share->vidmem_size>>1:share->vidmem_size;
 708        /* setup crtc and output member */
 709        spec_share->hwCursor = g_hwcursor;
 710
 711        crtc->proc_setMode = hw_sm750_crtc_setMode;
 712        crtc->proc_checkMode = hw_sm750_crtc_checkMode;
 713        crtc->proc_setColReg = hw_sm750_setColReg;
 714        crtc->proc_panDisplay = hw_sm750_pan_display;
 715        crtc->clear = hw_sm750_crtc_clear;
 716        crtc->line_pad = 16;
 717        crtc->xpanstep = 8;
 718        crtc->ypanstep = 1;
 719        crtc->ywrapstep = 0;
 720
 721        output->proc_setMode = hw_sm750_output_setMode;
 722        output->proc_checkMode = hw_sm750_output_checkMode;
 723
 724        output->proc_setBLANK = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_setBLANK:hw_sm750_setBLANK;
 725        output->clear = hw_sm750_output_clear;
 726        /* chip specific phase */
 727        share->accel.de_wait = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_deWait : hw_sm750_deWait;
 728        switch (spec_share->state.dataflow) {
 729        case sm750_simul_pri:
 730                output->paths = sm750_pnc;
 731                crtc->channel = sm750_primary;
 732                crtc->oScreen = 0;
 733                crtc->vScreen = share->pvMem;
 734                pr_info("use simul primary mode\n");
 735                break;
 736        case sm750_simul_sec:
 737                output->paths = sm750_pnc;
 738                crtc->channel = sm750_secondary;
 739                crtc->oScreen = 0;
 740                crtc->vScreen = share->pvMem;
 741                break;
 742        case sm750_dual_normal:
 743                if (par->index == 0) {
 744                        output->paths = sm750_panel;
 745                        crtc->channel = sm750_primary;
 746                        crtc->oScreen = 0;
 747                        crtc->vScreen = share->pvMem;
 748                } else {
 749                        output->paths = sm750_crt;
 750                        crtc->channel = sm750_secondary;
 751                        /* not consider of padding stuffs for oScreen,need fix */
 752                        crtc->oScreen = (share->vidmem_size >> 1);
 753                        crtc->vScreen = share->pvMem + crtc->oScreen;
 754                }
 755                break;
 756        case sm750_dual_swap:
 757                if (par->index == 0) {
 758                        output->paths = sm750_panel;
 759                        crtc->channel = sm750_secondary;
 760                        crtc->oScreen = 0;
 761                        crtc->vScreen = share->pvMem;
 762                } else {
 763                        output->paths = sm750_crt;
 764                        crtc->channel = sm750_primary;
 765                        /* not consider of padding stuffs for oScreen,need fix */
 766                        crtc->oScreen = (share->vidmem_size >> 1);
 767                        crtc->vScreen = share->pvMem + crtc->oScreen;
 768                }
 769                break;
 770        default:
 771                ret = -EINVAL;
 772        }
 773
 774        return ret;
 775}
 776
 777static struct fb_ops lynxfb_ops = {
 778        .owner = THIS_MODULE,
 779        .fb_check_var =  lynxfb_ops_check_var,
 780        .fb_set_par = lynxfb_ops_set_par,
 781        .fb_setcolreg = lynxfb_ops_setcolreg,
 782        .fb_blank = lynxfb_ops_blank,
 783        .fb_fillrect = cfb_fillrect,
 784        .fb_imageblit = cfb_imageblit,
 785        .fb_copyarea = cfb_copyarea,
 786        /* cursor */
 787        .fb_cursor = lynxfb_ops_cursor,
 788};
 789
 790
 791static int lynxfb_set_fbinfo(struct fb_info *info, int index)
 792{
 793        int i;
 794        struct lynxfb_par *par;
 795        struct lynx_share *share;
 796        struct lynxfb_crtc *crtc;
 797        struct lynxfb_output *output;
 798        struct fb_var_screeninfo *var;
 799        struct fb_fix_screeninfo *fix;
 800
 801        const struct fb_videomode *pdb[] = {
 802                lynx750_ext, NULL, vesa_modes,
 803        };
 804        int cdb[] = {ARRAY_SIZE(lynx750_ext), 0, VESA_MODEDB_SIZE};
 805        static const char *mdb_desc[] = {
 806                "driver prepared modes",
 807                "kernel prepared default modedb",
 808                "kernel HELPERS prepared vesa_modes",
 809        };
 810
 811
 812        static const char *fixId[2] = {
 813                "sm750_fb1", "sm750_fb2",
 814        };
 815
 816        int ret, line_length;
 817
 818        ret = 0;
 819        par = (struct lynxfb_par *)info->par;
 820        share = par->share;
 821        crtc = &par->crtc;
 822        output = &par->output;
 823        var = &info->var;
 824        fix = &info->fix;
 825
 826        /* set index */
 827        par->index = index;
 828        output->channel = &crtc->channel;
 829        sm750fb_set_drv(par);
 830        lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display;
 831
 832
 833        /* set current cursor variable and proc pointer,
 834         * must be set after crtc member initialized */
 835        crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024;
 836        crtc->cursor.mmio = share->pvReg + 0x800f0 + (int)crtc->channel * 0x140;
 837
 838        pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
 839        crtc->cursor.maxH = crtc->cursor.maxW = 64;
 840        crtc->cursor.size = crtc->cursor.maxH*crtc->cursor.maxW*2/8;
 841        crtc->cursor.disable = hw_cursor_disable;
 842        crtc->cursor.enable = hw_cursor_enable;
 843        crtc->cursor.setColor = hw_cursor_setColor;
 844        crtc->cursor.setPos = hw_cursor_setPos;
 845        crtc->cursor.setSize = hw_cursor_setSize;
 846        crtc->cursor.setData = hw_cursor_setData;
 847        crtc->cursor.vstart = share->pvMem + crtc->cursor.offset;
 848
 849
 850        crtc->cursor.share = share;
 851                memset_io(crtc->cursor.vstart, 0, crtc->cursor.size);
 852        if (!g_hwcursor) {
 853                lynxfb_ops.fb_cursor = NULL;
 854                crtc->cursor.disable(&crtc->cursor);
 855        }
 856
 857
 858        /* set info->fbops, must be set before fb_find_mode */
 859        if (!share->accel_off) {
 860                /* use 2d acceleration */
 861                lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect;
 862                lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea;
 863                lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit;
 864        }
 865        info->fbops = &lynxfb_ops;
 866
 867        if (!g_fbmode[index]) {
 868                g_fbmode[index] = g_def_fbmode;
 869                if (index)
 870                        g_fbmode[index] = g_fbmode[0];
 871        }
 872
 873
 874        for (i = 0; i < 3; i++) {
 875
 876                ret = fb_find_mode(var, info, g_fbmode[index],
 877                                   pdb[i], cdb[i], NULL, 8);
 878
 879                if (ret == 1) {
 880                        pr_info("success! use specified mode:%s in %s\n",
 881                                g_fbmode[index],
 882                                mdb_desc[i]);
 883                        break;
 884                } else if (ret == 2) {
 885                        pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
 886                                g_fbmode[index],
 887                                mdb_desc[i]);
 888                        break;
 889                } else if (ret == 3) {
 890                        pr_warn("wanna use default mode\n");
 891                        /*break;*/
 892                } else if (ret == 4) {
 893                        pr_warn("fall back to any valid mode\n");
 894                } else {
 895                        pr_warn("ret = %d,fb_find_mode failed,with %s\n",
 896                                ret,
 897                                mdb_desc[i]);
 898                }
 899        }
 900
 901        /* some member of info->var had been set by fb_find_mode */
 902
 903        pr_info("Member of info->var is :\n\
 904                xres=%d\n\
 905                yres=%d\n\
 906                xres_virtual=%d\n\
 907                yres_virtual=%d\n\
 908                xoffset=%d\n\
 909                yoffset=%d\n\
 910                bits_per_pixel=%d\n \
 911                ...\n",
 912                var->xres,
 913                var->yres,
 914                var->xres_virtual,
 915                var->yres_virtual,
 916                var->xoffset,
 917                var->yoffset,
 918                var->bits_per_pixel);
 919
 920        /* set par */
 921        par->info = info;
 922
 923        /* set info */
 924        line_length = PADDING(crtc->line_pad,
 925                              (var->xres_virtual * var->bits_per_pixel/8));
 926
 927        info->pseudo_palette = &par->pseudo_palette[0];
 928        info->screen_base = crtc->vScreen;
 929        pr_debug("screen_base vaddr = %p\n", info->screen_base);
 930        info->screen_size = line_length * var->yres_virtual;
 931        info->flags = FBINFO_FLAG_DEFAULT|0;
 932
 933        /* set info->fix */
 934        fix->type = FB_TYPE_PACKED_PIXELS;
 935        fix->type_aux = 0;
 936        fix->xpanstep = crtc->xpanstep;
 937        fix->ypanstep = crtc->ypanstep;
 938        fix->ywrapstep = crtc->ywrapstep;
 939        fix->accel = FB_ACCEL_SMI;
 940
 941        strlcpy(fix->id, fixId[index], sizeof(fix->id));
 942
 943
 944        fix->smem_start = crtc->oScreen + share->vidmem_start;
 945        pr_info("fix->smem_start = %lx\n", fix->smem_start);
 946        /* according to mmap experiment from user space application,
 947         * fix->mmio_len should not larger than virtual size
 948         * (xres_virtual x yres_virtual x ByPP)
 949         * Below line maybe buggy when user mmap fb dev node and write
 950         * data into the bound over virtual size
 951         * */
 952        fix->smem_len = crtc->vidmem_size;
 953        pr_info("fix->smem_len = %x\n", fix->smem_len);
 954        info->screen_size = fix->smem_len;
 955        fix->line_length = line_length;
 956        fix->mmio_start = share->vidreg_start;
 957        pr_info("fix->mmio_start = %lx\n", fix->mmio_start);
 958        fix->mmio_len = share->vidreg_size;
 959        pr_info("fix->mmio_len = %x\n", fix->mmio_len);
 960        switch (var->bits_per_pixel) {
 961        case 8:
 962                fix->visual = FB_VISUAL_PSEUDOCOLOR;
 963                break;
 964        case 16:
 965        case 32:
 966                fix->visual = FB_VISUAL_TRUECOLOR;
 967                break;
 968        }
 969
 970        /* set var */
 971        var->activate = FB_ACTIVATE_NOW;
 972        var->accel_flags = 0;
 973        var->vmode = FB_VMODE_NONINTERLACED;
 974
 975        pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
 976                 info->cmap.start, info->cmap.len,
 977                 info->cmap.red, info->cmap.green, info->cmap.blue,
 978                 info->cmap.transp);
 979
 980        ret = fb_alloc_cmap(&info->cmap, 256, 0);
 981        if (ret < 0) {
 982                pr_err("Could not allcate memory for cmap.\n");
 983                goto exit;
 984        }
 985
 986        pr_debug("#2 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
 987                 info->cmap.start, info->cmap.len,
 988                 info->cmap.red, info->cmap.green, info->cmap.blue,
 989                 info->cmap.transp);
 990
 991exit:
 992        lynxfb_ops_check_var(var, info);
 993        return ret;
 994}
 995
 996/*      chip specific g_option configuration routine */
 997static void sm750fb_setup(struct lynx_share *share, char *src)
 998{
 999        struct sm750_share *spec_share;
1000        char *opt;
1001#ifdef CAP_EXPENSION
1002        char *exp_res;
1003#endif
1004        int swap;
1005
1006
1007        spec_share = container_of(share, struct sm750_share, share);
1008#ifdef CAP_EXPENSIION
1009        exp_res = NULL;
1010#endif
1011        swap = 0;
1012
1013        spec_share->state.initParm.chip_clk = 0;
1014        spec_share->state.initParm.mem_clk = 0;
1015        spec_share->state.initParm.master_clk = 0;
1016        spec_share->state.initParm.powerMode = 0;
1017        spec_share->state.initParm.setAllEngOff = 0;
1018        spec_share->state.initParm.resetMemory = 1;
1019
1020        /* defaultly turn g_hwcursor on for both view */
1021        g_hwcursor = 3;
1022
1023        if (!src || !*src) {
1024                pr_warn("no specific g_option.\n");
1025                goto NO_PARAM;
1026        }
1027
1028        while ((opt = strsep(&src, ":")) != NULL && *opt != 0) {
1029                pr_err("opt=%s\n", opt);
1030                pr_err("src=%s\n", src);
1031
1032                if (!strncmp(opt, "swap", strlen("swap")))
1033                        swap = 1;
1034                else if (!strncmp(opt, "nocrt", strlen("nocrt")))
1035                        spec_share->state.nocrt = 1;
1036                else if (!strncmp(opt, "36bit", strlen("36bit")))
1037                        spec_share->state.pnltype = sm750_doubleTFT;
1038                else if (!strncmp(opt, "18bit", strlen("18bit")))
1039                        spec_share->state.pnltype = sm750_dualTFT;
1040                else if (!strncmp(opt, "24bit", strlen("24bit")))
1041                        spec_share->state.pnltype = sm750_24TFT;
1042#ifdef CAP_EXPANSION
1043                else if (!strncmp(opt, "exp:", strlen("exp:")))
1044                        exp_res = opt + strlen("exp:");
1045#endif
1046                else if (!strncmp(opt, "nohwc0", strlen("nohwc0")))
1047                        g_hwcursor &= ~0x1;
1048                else if (!strncmp(opt, "nohwc1", strlen("nohwc1")))
1049                        g_hwcursor &= ~0x2;
1050                else if (!strncmp(opt, "nohwc", strlen("nohwc")))
1051                        g_hwcursor = 0;
1052                else {
1053                        if (!g_fbmode[0]) {
1054                                g_fbmode[0] = opt;
1055                                pr_info("find fbmode0 : %s\n", g_fbmode[0]);
1056                        } else if (!g_fbmode[1]) {
1057                                g_fbmode[1] = opt;
1058                                pr_info("find fbmode1 : %s\n", g_fbmode[1]);
1059                        } else {
1060                                pr_warn("How many view you wann set?\n");
1061                        }
1062                }
1063        }
1064#ifdef CAP_EXPANSION
1065        if (getExpRes(exp_res,
1066                      &spec_share->state.xLCD,
1067                      &spec_share->state.yLCD)) {
1068                /* seems exp_res is not valid */
1069                spec_share->state.xLCD = spec_share->state.yLCD = 0;
1070        }
1071#endif
1072
1073NO_PARAM:
1074        if (share->revid != SM750LE_REVISION_ID) {
1075                if (share->dual) {
1076                        if (swap)
1077                                spec_share->state.dataflow = sm750_dual_swap;
1078                        else
1079                                spec_share->state.dataflow = sm750_dual_normal;
1080                } else {
1081                        if (swap)
1082                                spec_share->state.dataflow = sm750_simul_sec;
1083                        else
1084                                spec_share->state.dataflow = sm750_simul_pri;
1085                }
1086        } else {
1087                /* SM750LE only have one crt channel */
1088                spec_share->state.dataflow = sm750_simul_sec;
1089                /* sm750le do not have complex attributes */
1090                spec_share->state.nocrt = 0;
1091        }
1092}
1093
1094static int lynxfb_pci_probe(struct pci_dev *pdev,
1095                            const struct pci_device_id * ent)
1096{
1097        struct fb_info *info[] = {NULL, NULL};
1098        struct lynx_share *share = NULL;
1099
1100        struct sm750_share *spec_share = NULL;
1101        size_t spec_offset = 0;
1102        int fbidx;
1103
1104
1105        /* enable device */
1106        if (pci_enable_device(pdev)) {
1107                pr_err("can not enable device.\n");
1108                goto err_enable;
1109        }
1110
1111        /* though offset of share in sm750_share is 0,
1112         * we use this marcro as the same */
1113        spec_offset = offsetof(struct sm750_share, share);
1114
1115        spec_share = kzalloc(sizeof(*spec_share), GFP_KERNEL);
1116        if (!spec_share) {
1117                pr_err("Could not allocate memory for share.\n");
1118                goto err_share;
1119        }
1120
1121        /* setting share structure */
1122        share = (struct lynx_share *)(&(spec_share->share));
1123        share->fbinfo[0] = share->fbinfo[1] = NULL;
1124        share->devid = pdev->device;
1125        share->revid = pdev->revision;
1126
1127        pr_info("share->revid = %02x\n", share->revid);
1128        share->pdev = pdev;
1129#ifdef CONFIG_MTRR
1130        share->mtrr_off = g_nomtrr;
1131        share->mtrr.vram = 0;
1132        share->mtrr.vram_added = 0;
1133#endif
1134        share->accel_off = g_noaccel;
1135        share->dual = g_dualview;
1136        spin_lock_init(&share->slock);
1137
1138        if (!share->accel_off) {
1139                /* hook deInit and 2d routines, notes that below hw_xxx
1140                 * routine can work on most of lynx chips
1141                 * if some chip need specific function,
1142                 * please hook it in smXXX_set_drv routine */
1143                share->accel.de_init = hw_de_init;
1144                share->accel.de_fillrect = hw_fillrect;
1145                share->accel.de_copyarea = hw_copyarea;
1146                share->accel.de_imageblit = hw_imageblit;
1147                pr_info("enable 2d acceleration\n");
1148        } else {
1149                pr_info("disable 2d acceleration\n");
1150        }
1151
1152        /* call chip specific setup routine  */
1153        sm750fb_setup(share, g_settings);
1154
1155        /* call chip specific mmap routine */
1156        if (hw_sm750_map(share, pdev)) {
1157                pr_err("Memory map failed\n");
1158                goto err_map;
1159        }
1160
1161#ifdef CONFIG_MTRR
1162        if (!share->mtrr_off) {
1163                pr_info("enable mtrr\n");
1164                share->mtrr.vram = mtrr_add(share->vidmem_start,
1165                                            share->vidmem_size,
1166                                            MTRR_TYPE_WRCOMB, 1);
1167
1168                if (share->mtrr.vram < 0) {
1169                        /* don't block driver with the failure of MTRR */
1170                        pr_err("Unable to setup MTRR.\n");
1171                } else {
1172                        share->mtrr.vram_added = 1;
1173                        pr_info("MTRR added succesfully\n");
1174                }
1175        }
1176#endif
1177
1178        memset_io(share->pvMem, 0, share->vidmem_size);
1179
1180        pr_info("sm%3x mmio address = %p\n", share->devid, share->pvReg);
1181
1182        pci_set_drvdata(pdev, share);
1183
1184        /* call chipInit routine */
1185        hw_sm750_inithw(share, pdev);
1186
1187        /* allocate frame buffer info structor according to g_dualview */
1188        fbidx = 0;
1189ALLOC_FB:
1190        info[fbidx] = framebuffer_alloc(sizeof(struct lynxfb_par), &pdev->dev);
1191        if (!info[fbidx]) {
1192                pr_err("Could not allocate framebuffer #%d.\n", fbidx);
1193                if (fbidx == 0)
1194                        goto err_info0_alloc;
1195                else
1196                        goto err_info1_alloc;
1197        } else {
1198                struct lynxfb_par *par;
1199                int errno;
1200
1201                pr_info("framebuffer #%d alloc okay\n", fbidx);
1202                share->fbinfo[fbidx] = info[fbidx];
1203                par = info[fbidx]->par;
1204                par->share = share;
1205
1206                /* set fb_info structure */
1207                if (lynxfb_set_fbinfo(info[fbidx], fbidx)) {
1208                        pr_err("Failed to initial fb_info #%d.\n", fbidx);
1209                        if (fbidx == 0)
1210                                goto err_info0_set;
1211                        else
1212                                goto err_info1_set;
1213                }
1214
1215                /* register frame buffer */
1216                pr_info("Ready to register framebuffer #%d.\n", fbidx);
1217                errno = register_framebuffer(info[fbidx]);
1218                if (errno < 0) {
1219                        pr_err("Failed to register fb_info #%d. err %d\n",
1220                               fbidx,
1221                               errno);
1222                        if (fbidx == 0)
1223                                goto err_register0;
1224                        else
1225                                goto err_register1;
1226                }
1227                pr_info("Accomplished register framebuffer #%d.\n", fbidx);
1228        }
1229
1230        /* no dual view by far */
1231        fbidx++;
1232        if (share->dual && fbidx < 2)
1233                goto ALLOC_FB;
1234
1235        return 0;
1236
1237err_register1:
1238err_info1_set:
1239        framebuffer_release(info[1]);
1240err_info1_alloc:
1241        unregister_framebuffer(info[0]);
1242err_register0:
1243err_info0_set:
1244        framebuffer_release(info[0]);
1245err_info0_alloc:
1246err_map:
1247        kfree(spec_share);
1248err_share:
1249err_enable:
1250        return -ENODEV;
1251}
1252
1253static void lynxfb_pci_remove(struct pci_dev *pdev)
1254{
1255        struct fb_info *info;
1256        struct lynx_share *share;
1257        void *spec_share;
1258        struct lynxfb_par *par;
1259        int cnt;
1260
1261        cnt = 2;
1262        share = pci_get_drvdata(pdev);
1263
1264        while (cnt-- > 0) {
1265                info = share->fbinfo[cnt];
1266                if (!info)
1267                        continue;
1268                par = info->par;
1269
1270                unregister_framebuffer(info);
1271                /* clean crtc & output allocations */
1272                par->crtc.clear(&par->crtc);
1273                par->output.clear(&par->output);
1274                /* release frame buffer */
1275                framebuffer_release(info);
1276        }
1277#ifdef CONFIG_MTRR
1278        if (share->mtrr.vram_added)
1279                mtrr_del(share->mtrr.vram,
1280                         share->vidmem_start,
1281                         share->vidmem_size);
1282#endif
1283
1284        iounmap(share->pvReg);
1285        iounmap(share->pvMem);
1286        spec_share = container_of(share, struct sm750_share, share);
1287        kfree(g_settings);
1288        kfree(spec_share);
1289        pci_set_drvdata(pdev, NULL);
1290}
1291
1292static int __init lynxfb_setup(char *options)
1293{
1294        int len;
1295        char *opt, *tmp;
1296
1297
1298        if (!options || !*options) {
1299                pr_warn("no options.\n");
1300                return 0;
1301        }
1302
1303        pr_info("options:%s\n", options);
1304
1305        len = strlen(options) + 1;
1306        g_settings = kzalloc(len, GFP_KERNEL);
1307        if (!g_settings)
1308                return -ENOMEM;
1309
1310        tmp = g_settings;
1311
1312        /*      Notes:
1313                char * strsep(char **s,const char * ct);
1314                @s: the string to be searched
1315                @ct :the characters to search for
1316
1317                strsep() updates @options to pointer after the first found token
1318                it also returns the pointer ahead the token.
1319                */
1320        while ((opt = strsep(&options, ":")) != NULL) {
1321                /* options that mean for any lynx chips are configured here */
1322                if (!strncmp(opt, "noaccel", strlen("noaccel")))
1323                        g_noaccel = 1;
1324#ifdef CONFIG_MTRR
1325                else if (!strncmp(opt, "nomtrr", strlen("nomtrr")))
1326                        g_nomtrr = 1;
1327#endif
1328                else if (!strncmp(opt, "dual", strlen("dual")))
1329                        g_dualview = 1;
1330                else {
1331                        strcat(tmp, opt);
1332                        tmp += strlen(opt);
1333                        if (options != NULL)
1334                                *tmp++ = ':';
1335                        else
1336                                *tmp++ = 0;
1337                }
1338        }
1339
1340        /* misc g_settings are transport to chip specific routines */
1341        pr_info("parameter left for chip specific analysis:%s\n", g_settings);
1342        return 0;
1343}
1344
1345static struct pci_device_id smi_pci_table[] = {
1346        { PCI_DEVICE(0x126f, 0x0750), },
1347        {0,}
1348};
1349
1350MODULE_DEVICE_TABLE(pci, smi_pci_table);
1351
1352static struct pci_driver lynxfb_driver = {
1353        .name =         "sm750fb",
1354        .id_table =     smi_pci_table,
1355        .probe =        lynxfb_pci_probe,
1356        .remove =       lynxfb_pci_remove,
1357#ifdef CONFIG_PM
1358        .suspend = lynxfb_suspend,
1359        .resume = lynxfb_resume,
1360#endif
1361};
1362
1363
1364static int __init lynxfb_init(void)
1365{
1366        char *option;
1367        int ret;
1368
1369#ifdef MODULE
1370        option = g_option;
1371#else
1372        if (fb_get_options("sm750fb", &option))
1373                return -ENODEV;
1374#endif
1375
1376        lynxfb_setup(option);
1377        ret = pci_register_driver(&lynxfb_driver);
1378        return ret;
1379}
1380module_init(lynxfb_init);
1381
1382static void __exit lynxfb_exit(void)
1383{
1384        pci_unregister_driver(&lynxfb_driver);
1385}
1386module_exit(lynxfb_exit);
1387
1388module_param(g_option, charp, S_IRUGO);
1389
1390MODULE_PARM_DESC(g_option,
1391                 "\n\t\tCommon options:\n"
1392                 "\t\tnoaccel:disable 2d capabilities\n"
1393                 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1394                 "\t\tdualview:dual frame buffer feature enabled\n"
1395                 "\t\tnohwc:disable hardware cursor\n"
1396                 "\t\tUsual example:\n"
1397                 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1398                 );
1399
1400MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1401MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1402MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1403MODULE_LICENSE("GPL v2");
1404