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