matroxfb_crtc2.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:23k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *
  3.  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  4.  *
  5.  * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  6.  *
  7.  * Version: 1.52 2001/05/25
  8.  *
  9.  */
  10. #include "matroxfb_maven.h"
  11. #include "matroxfb_crtc2.h"
  12. #include "matroxfb_misc.h"
  13. #include "matroxfb_DAC1064.h"
  14. #include <linux/matroxfb.h>
  15. #include <asm/uaccess.h>
  16. /* **************************************************** */
  17. static int mem = 8192;
  18. MODULE_PARM(mem, "i");
  19. MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
  20. /* **************************************************** */
  21. static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
  22. unsigned *blue, unsigned *transp, struct fb_info* info) {
  23. #define m2info ((struct matroxfb_dh_fb_info*)info)
  24. if (regno > 16)
  25. return 1;
  26. *red = m2info->palette[regno].red;
  27. *blue = m2info->palette[regno].blue;
  28. *green = m2info->palette[regno].green;
  29. *transp = m2info->palette[regno].transp;
  30. return 0;
  31. #undef m2info
  32. }
  33. static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
  34. unsigned blue, unsigned transp, struct fb_info* info) {
  35. #define m2info ((struct matroxfb_dh_fb_info*)info)
  36. struct display* p;
  37. if (regno > 16)
  38. return 1;
  39. m2info->palette[regno].red = red;
  40. m2info->palette[regno].blue = blue;
  41. m2info->palette[regno].green = green;
  42. m2info->palette[regno].transp = transp;
  43. p = m2info->currcon_display;
  44. if (p->var.grayscale) {
  45. /* gray = 0.30*R + 0.59*G + 0.11*B */
  46. red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
  47. }
  48. red = CNVT_TOHW(red, p->var.red.length);
  49. green = CNVT_TOHW(green, p->var.green.length);
  50. blue = CNVT_TOHW(blue, p->var.blue.length);
  51. transp = CNVT_TOHW(transp, p->var.transp.length);
  52. switch (p->var.bits_per_pixel) {
  53. #ifdef FBCON_HAS_CFB16
  54. case 16:
  55. m2info->cmap.cfb16[regno] =
  56. (red << p->var.red.offset)     |
  57. (green << p->var.green.offset) |
  58. (blue << p->var.blue.offset)   |
  59. (transp << p->var.transp.offset);
  60. break;
  61. #endif
  62. #ifdef FBCON_HAS_CFB32
  63. case 32:
  64. m2info->cmap.cfb32[regno] =
  65. (red << p->var.red.offset)     |
  66. (green << p->var.green.offset) |
  67. (blue << p->var.blue.offset)   |
  68. (transp << p->var.transp.offset);
  69. break;
  70. #endif
  71. }
  72. return 0;
  73. #undef m2info
  74. }
  75. static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
  76. if (p->cmap.len)
  77. fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
  78. else
  79. fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
  80. }
  81. static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
  82. struct my_timming* mt,
  83. struct display* p,
  84. int mode,
  85. unsigned int pos) {
  86. u_int32_t tmp;
  87. MINFO_FROM(m2info->primary_dev);
  88. switch (mode) {
  89. case 15:
  90. tmp = 0x00200000;
  91. break;
  92. case 16:
  93. tmp = 0x00400000;
  94. break;
  95. /* case 32: */
  96. default:
  97. tmp = 0x00800000;
  98. break;
  99. }
  100. if (ACCESS_FBINFO(output.sh)) {
  101. tmp |= 0x00000001; /* enable CRTC2 */
  102. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
  103. if (ACCESS_FBINFO(devflags.g450dac)) {
  104. tmp |= 0x00000006; /* source from secondary pixel PLL */
  105. /* no vidrst */
  106. } else {
  107. tmp |= 0x00000002; /* source from VDOCLK */
  108. tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
  109. /* MGA TVO is our clock source */
  110. }
  111. } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
  112. tmp |= 0x00000004; /* source from pixclock */
  113. /* PIXPLL is our clock source */
  114. }
  115. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
  116. tmp |= 0x00100000; /* connect CRTC2 to DAC */
  117. }
  118. if (mt->interlaced) {
  119. tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */
  120. mt->VDisplay >>= 1;
  121. mt->VSyncStart >>= 1;
  122. mt->VSyncEnd >>= 1;
  123. mt->VTotal >>= 1;
  124. }
  125. mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */
  126. mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
  127. mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
  128. mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
  129. mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
  130. mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
  131. {
  132. u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
  133. if (mt->interlaced) {
  134. /* field #0 is smaller, so... */
  135. mga_outl(0x3C2C, pos); /* field #1 vmemory start */
  136. mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */
  137. linelen <<= 1;
  138. } else {
  139. mga_outl(0x3C28, pos); /* vmemory start */
  140. }
  141. mga_outl(0x3C40, linelen);
  142. }
  143. tmp = 0x0FFF0000; /* line compare */
  144. if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
  145. tmp |= 0x00000100;
  146. if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
  147. tmp |= 0x00000200;
  148. mga_outl(0x3C44, tmp);
  149. mga_outl(0x3C4C, 0); /* data control */
  150. }
  151. static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
  152. struct display* p) {
  153. /* no acceleration for secondary head... */
  154. }
  155. static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
  156. struct fb_var_screeninfo* var) {
  157. unsigned int pos;
  158. unsigned int linelen;
  159. unsigned int pixelsize;
  160. #define minfo (m2info->primary_dev)
  161. pixelsize = var->bits_per_pixel >> 3;
  162. linelen = var->xres_virtual * pixelsize;
  163. pos = var->yoffset * linelen + var->xoffset * pixelsize;
  164. pos += m2info->video.offbase;
  165. if (var->vmode & FB_VMODE_INTERLACED) {
  166. mga_outl(0x3C2C, pos);
  167. mga_outl(0x3C28, pos + linelen);
  168. } else {
  169. mga_outl(0x3C28, pos);
  170. }
  171. #undef minfo
  172. }
  173. static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
  174. struct display* p,
  175. struct fb_var_screeninfo* var,
  176. int *visual,
  177. int *video_cmap_len,
  178. int *mode) {
  179. unsigned int mask;
  180. unsigned int memlen;
  181. unsigned int vramlen;
  182. switch (var->bits_per_pixel) {
  183. #ifdef FBCON_HAS_CFB16
  184. case 16: mask = 0x1F;
  185. break;
  186. #endif
  187. #ifdef FBCON_HAS_CFB32
  188. case 32: mask = 0x0F;
  189. break;
  190. #endif
  191. default: return -EINVAL;
  192. }
  193. vramlen = m2info->video.len_usable;
  194. if (var->yres_virtual < var->yres)
  195. var->yres_virtual = var->yres;
  196. if (var->xres_virtual < var->xres)
  197. var->xres_virtual = var->xres;
  198. var->xres_virtual = (var->xres_virtual + mask) & ~mask;
  199. if (var->yres_virtual > 32767)
  200. return -EINVAL;
  201. memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3);
  202. if (memlen > vramlen)
  203. return -EINVAL;
  204. if (var->xoffset + var->xres > var->xres_virtual)
  205. var->xoffset = var->xres_virtual - var->xres;
  206. if (var->yoffset + var->yres > var->yres_virtual)
  207. var->yoffset = var->yres_virtual - var->yres;
  208. var->xres &= ~7;
  209. var->left_margin &= ~7;
  210. var->right_margin &= ~7;
  211. var->hsync_len &= ~7;
  212. *mode = var->bits_per_pixel;
  213. if (var->bits_per_pixel == 16) {
  214. if (var->green.length == 5) {
  215. var->red.offset = 10;
  216. var->red.length = 5;
  217. var->green.offset = 5;
  218. var->green.length = 5;
  219. var->blue.offset = 0;
  220. var->blue.length = 5;
  221. var->transp.offset = 15;
  222. var->transp.length = 1;
  223. *mode = 15;
  224. } else {
  225. var->red.offset = 11;
  226. var->red.length = 5;
  227. var->green.offset = 5;
  228. var->green.length = 6;
  229. var->blue.offset = 0;
  230. var->blue.length = 5;
  231. var->transp.offset = 0;
  232. var->transp.length = 0;
  233. }
  234. } else {
  235. var->red.offset = 16;
  236. var->red.length = 8;
  237. var->green.offset = 8;
  238. var->green.length = 8;
  239. var->blue.offset = 0;
  240. var->blue.length = 8;
  241. var->transp.offset = 24;
  242. var->transp.length = 8;
  243. }
  244. *visual = FB_VISUAL_TRUECOLOR;
  245. *video_cmap_len = 16;
  246. return 0;
  247. }
  248. static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) {
  249. switch (p->var.bits_per_pixel) {
  250. #ifdef FBCON_HAS_CFB16
  251. case 16:
  252. p->dispsw_data = m2info->cmap.cfb16;
  253. p->dispsw = &fbcon_cfb16;
  254. break;
  255. #endif
  256. #ifdef FBCON_HAS_CFB32
  257. case 32:
  258. p->dispsw_data = m2info->cmap.cfb32;
  259. p->dispsw = &fbcon_cfb32;
  260. break;
  261. #endif
  262. default:
  263. p->dispsw_data = NULL;
  264. p->dispsw = &fbcon_dummy;
  265. break;
  266. }
  267. }
  268. static int matroxfb_dh_open(struct fb_info* info, int user) {
  269. #define m2info ((struct matroxfb_dh_fb_info*)info)
  270. MINFO_FROM(m2info->primary_dev);
  271. if (MINFO) {
  272. if (ACCESS_FBINFO(dead)) {
  273. return -ENXIO;
  274. }
  275. }
  276. return 0;
  277. #undef m2info
  278. }
  279. static int matroxfb_dh_release(struct fb_info* info, int user) {
  280. #define m2info ((struct matroxfb_dh_fb_info*)info)
  281. MINFO_FROM(m2info->primary_dev);
  282. if (MINFO) {
  283. }
  284. return 0;
  285. #undef m2info
  286. }
  287. static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
  288. struct fb_info* info) {
  289. #define m2info ((struct matroxfb_dh_fb_info*)info)
  290. struct display* p;
  291. if (con >= 0)
  292. p = fb_display + con;
  293. else
  294. p = m2info->fbcon.disp;
  295. memset(fix, 0, sizeof(*fix));
  296. strcpy(fix->id, "MATROX DH");
  297. fix->smem_start = m2info->video.base;
  298. fix->smem_len = m2info->video.len_usable;
  299. fix->type = p->type;
  300. fix->type_aux = p->type_aux;
  301. fix->visual = p->visual;
  302. fix->xpanstep = 8; /* TBD */
  303. fix->ypanstep = 1;
  304. fix->ywrapstep = 0;
  305. fix->line_length = p->line_length;
  306. fix->mmio_start = m2info->mmio.base;
  307. fix->mmio_len = m2info->mmio.len;
  308. fix->accel = 0; /* no accel... */
  309. return 0;
  310. #undef m2info
  311. }
  312. static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
  313. struct fb_info* info) {
  314. #define m2info ((struct matroxfb_dh_fb_info*)info)
  315. if (con < 0)
  316. *var = m2info->fbcon.disp->var;
  317. else
  318. *var = fb_display[con].var;
  319. return 0;
  320. #undef m2info
  321. }
  322. static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
  323. struct fb_info* info) {
  324. #define m2info ((struct matroxfb_dh_fb_info*)info)
  325. struct display* p;
  326. int chgvar;
  327. int visual;
  328. int cmap_len;
  329. int mode;
  330. int err;
  331. MINFO_FROM(m2info->primary_dev);
  332. if (con < 0)
  333. p = m2info->fbcon.disp;
  334. else
  335. p = fb_display + con;
  336. if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0)
  337. return err;
  338. switch (var->activate & FB_ACTIVATE_MASK) {
  339. case FB_ACTIVATE_TEST: return 0;
  340. case FB_ACTIVATE_NXTOPEN:
  341. case FB_ACTIVATE_NOW: break;
  342. default: return -EINVAL;
  343. }
  344. if (con >= 0) {
  345. chgvar = (p->var.xres != var->xres) ||
  346. (p->var.yres != var->yres) ||
  347. (p->var.xres_virtual != var->xres_virtual) ||
  348. (p->var.yres_virtual != var->yres_virtual) ||
  349. (p->var.bits_per_pixel != var->bits_per_pixel) ||
  350. memcmp(&p->var.red, &var->red, sizeof(var->red)) ||
  351. memcmp(&p->var.green, &var->green, sizeof(var->green)) ||
  352. memcmp(&p->var.blue, &var->blue, sizeof(var->blue));
  353. } else
  354. chgvar = 0;
  355. p->var = *var;
  356. /* cmap */
  357. p->screen_base = vaddr_va(m2info->video.vbase);
  358. p->visual = visual;
  359. p->ypanstep = 1;
  360. p->ywrapstep = 0;
  361. p->type = FB_TYPE_PACKED_PIXELS;
  362. p->type_aux = 0;
  363. p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
  364. p->can_soft_blank = 0;
  365. p->inverse = 0; /* TBD */
  366. initMatroxDH(m2info, p);
  367. if (chgvar && info && info->changevar)
  368. info->changevar(con);
  369. if (con == m2info->currcon) {
  370. struct my_timming mt;
  371. struct matrox_hw_state* hw;
  372. struct matrox_hw_state* ohw;
  373. unsigned int pos;
  374. matroxfb_var2my(var, &mt);
  375. /* CRTC2 delay */
  376. mt.delay = 34;
  377. hw = ACCESS_FBINFO(newhw);
  378. ohw = ACCESS_FBINFO(currenthw);
  379. /* copy last setting... */
  380. memcpy(hw, ohw, sizeof(*hw));
  381. pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
  382. pos += m2info->video.offbase;
  383. DAC1064_global_init(PMINFO hw);
  384. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
  385. if (ACCESS_FBINFO(primout))
  386. ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw);
  387. }
  388. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
  389. down_read(&ACCESS_FBINFO(altout.lock));
  390. if (ACCESS_FBINFO(altout.output))
  391. ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw);
  392. up_read(&ACCESS_FBINFO(altout.lock));
  393. }
  394. matroxfb_dh_restore(m2info, &mt, p, mode, pos);
  395. DAC1064_global_restore(PMINFO hw);
  396. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
  397. if (ACCESS_FBINFO(primout))
  398. ACCESS_FBINFO(primout)->program(MINFO, hw);
  399. }
  400. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
  401. down_read(&ACCESS_FBINFO(altout.lock));
  402. if (ACCESS_FBINFO(altout.output))
  403. ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw);
  404. up_read(&ACCESS_FBINFO(altout.lock));
  405. }
  406. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
  407. if (ACCESS_FBINFO(primout))
  408. ACCESS_FBINFO(primout)->start(MINFO);
  409. }
  410. if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
  411. down_read(&ACCESS_FBINFO(altout.lock));
  412. if (ACCESS_FBINFO(altout.output))
  413. ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
  414. up_read(&ACCESS_FBINFO(altout.lock));
  415. }
  416. matroxfb_dh_cfbX_init(m2info, p);
  417. do_install_cmap(m2info, p);
  418. }
  419. return 0;
  420. #undef m2info
  421. }
  422. static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
  423. struct fb_info* info) {
  424. #define m2info ((struct matroxfb_dh_fb_info*)info)
  425. struct display* dsp;
  426. if (con < 0)
  427. dsp = m2info->fbcon.disp;
  428. else
  429. dsp = fb_display + con;
  430. if (con == m2info->currcon)
  431. return fb_get_cmap(cmap, kspc, matroxfb_dh_getcolreg, info);
  432. else if (dsp->cmap.len)
  433. fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
  434. else
  435. fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
  436. return 0;
  437. #undef m2info
  438. }
  439. static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
  440. struct fb_info* info) {
  441. #define m2info ((struct matroxfb_dh_fb_info*)info)
  442. struct display* dsp;
  443. if (con < 0)
  444. dsp = m2info->fbcon.disp;
  445. else
  446. dsp = fb_display + con;
  447. if (dsp->cmap.len != 16) {
  448. int err;
  449. err = fb_alloc_cmap(&dsp->cmap, 16, 0);
  450. if (err)
  451. return err;
  452. }
  453. if (con == m2info->currcon)
  454. return fb_set_cmap(cmap, kspc, matroxfb_dh_setcolreg, info);
  455. else
  456. fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
  457. return 0;
  458. #undef m2info
  459. }
  460. static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
  461. struct fb_info* info) {
  462. #define m2info ((struct matroxfb_dh_fb_info*)info)
  463. if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
  464.     var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
  465. return -EINVAL;
  466. if (con == m2info->currcon)
  467. matroxfb_dh_pan_var(m2info, var);
  468. fb_display[con].var.xoffset = var->xoffset;
  469. fb_display[con].var.yoffset = var->yoffset;
  470. return 0;
  471. #undef m2info
  472. }
  473. static int matroxfb_dh_switch(int con, struct fb_info* info);
  474. static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
  475. MINFO_FROM(m2info->primary_dev);
  476. memset(vblank, 0, sizeof(*vblank));
  477. vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
  478. /* mask out reserved bits + field number (odd/even) */
  479. vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
  480. /* compatibility stuff */
  481. if (vblank->vcount >= m2info->currcon_display->var.yres)
  482. vblank->flags |= FB_VBLANK_VBLANKING;
  483. return 0;
  484. }
  485. static int matroxfb_dh_ioctl(struct inode* inode,
  486. struct file* file,
  487. unsigned int cmd,
  488. unsigned long arg,
  489. int con,
  490. struct fb_info* info) {
  491. #define m2info ((struct matroxfb_dh_fb_info*)info)
  492. MINFO_FROM(m2info->primary_dev);
  493. DBG("matroxfb_crtc2_ioctl")
  494. switch (cmd) {
  495. case FBIOGET_VBLANK:
  496. {
  497. struct fb_vblank vblank;
  498. int err;
  499. err = matroxfb_dh_get_vblank(m2info, &vblank);
  500. if (err)
  501. return err;
  502. if (copy_to_user((struct fb_vblank*)arg, &vblank, sizeof(vblank)))
  503. return -EFAULT;
  504. return 0;
  505. }
  506. case MATROXFB_SET_OUTPUT_MODE:
  507. case MATROXFB_GET_OUTPUT_MODE:
  508. case MATROXFB_GET_ALL_OUTPUTS:
  509. {
  510. return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, con, &ACCESS_FBINFO(fbcon));
  511. }
  512. case MATROXFB_SET_OUTPUT_CONNECTION:
  513. {
  514. u_int32_t tmp;
  515. if (get_user(tmp, (u_int32_t*)arg))
  516. return -EFAULT;
  517. if (tmp & ~ACCESS_FBINFO(output.all))
  518. return -EINVAL;
  519. if (tmp & ACCESS_FBINFO(output.ph))
  520. return -EINVAL;
  521. if (tmp & MATROXFB_OUTPUT_CONN_DFP)
  522. return -EINVAL;
  523. if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
  524. return -EINVAL;
  525. if (tmp == ACCESS_FBINFO(output.sh))
  526. return 0;
  527. ACCESS_FBINFO(output.sh) = tmp;
  528. matroxfb_dh_switch(m2info->currcon, info);
  529. return 0;
  530. }
  531. case MATROXFB_GET_OUTPUT_CONNECTION:
  532. {
  533. if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
  534. return -EFAULT;
  535. return 0;
  536. }
  537. case MATROXFB_GET_AVAILABLE_OUTPUTS:
  538. {
  539. u_int32_t tmp;
  540. /* we do not support DFP from CRTC2 */
  541. tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
  542. /* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
  543. if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
  544. tmp = 0;
  545. if (put_user(tmp, (u_int32_t*)arg))
  546. return -EFAULT;
  547. return 0;
  548. }
  549. }
  550. return -EINVAL;
  551. #undef m2info
  552. }
  553. static struct fb_ops matroxfb_dh_ops = {
  554. owner: THIS_MODULE,
  555. fb_open: matroxfb_dh_open,
  556. fb_release: matroxfb_dh_release,
  557. fb_get_fix: matroxfb_dh_get_fix,
  558. fb_get_var: matroxfb_dh_get_var,
  559. fb_set_var: matroxfb_dh_set_var,
  560. fb_get_cmap: matroxfb_dh_get_cmap,
  561. fb_set_cmap: matroxfb_dh_set_cmap,
  562. fb_pan_display: matroxfb_dh_pan_display,
  563. fb_ioctl: matroxfb_dh_ioctl,
  564. };
  565. static int matroxfb_dh_switch(int con, struct fb_info* info) {
  566. #define m2info ((struct matroxfb_dh_fb_info*)info)
  567. struct fb_cmap* cmap;
  568. struct display* p;
  569. if (m2info->currcon >= 0) {
  570. cmap = &m2info->currcon_display->cmap;
  571. if (cmap->len) {
  572. fb_get_cmap(cmap, 1, matroxfb_dh_getcolreg, info);
  573. }
  574. }
  575. m2info->currcon = con;
  576. if (con < 0)
  577. p = m2info->fbcon.disp;
  578. else
  579. p = fb_display + con;
  580. m2info->currcon_display = p;
  581. p->var.activate = FB_ACTIVATE_NOW;
  582. matroxfb_dh_set_var(&p->var, con, info);
  583. return 0;
  584. #undef m2info
  585. }
  586. static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
  587. #define m2info ((struct matroxfb_dh_fb_info*)info)
  588. matroxfb_dh_pan_var(m2info, &fb_display[con].var);
  589. return 0;
  590. #undef m2info
  591. }
  592. static void matroxfb_dh_blank(int blank, struct fb_info* info) {
  593. #define m2info ((struct matroxfb_dh_fb_info*)info)
  594. switch (blank) {
  595. case 1:
  596. case 2:
  597. case 3:
  598. case 4:
  599. default:;
  600. }
  601. /* do something... */
  602. #undef m2info
  603. }
  604. static struct fb_var_screeninfo matroxfb_dh_defined = {
  605. 640,480,640,480,/* W,H, virtual W,H */
  606. 0,0, /* offset */
  607. 32, /* depth */
  608. 0, /* gray */
  609. {0,0,0}, /* R */
  610. {0,0,0}, /* G */
  611. {0,0,0}, /* B */
  612. {0,0,0}, /* alpha */
  613. 0, /* nonstd */
  614. FB_ACTIVATE_NOW,
  615. -1,-1, /* display size */
  616. 0, /* accel flags */
  617. 39721L,48L,16L,33L,10L,
  618. 96L,2,0, /* no sync info */
  619. FB_VMODE_NONINTERLACED,
  620. {0,0,0,0,0,0}
  621. };
  622. static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
  623. #define minfo (m2info->primary_dev)
  624. struct display* d;
  625. void* oldcrtc2;
  626. d = kmalloc(sizeof(*d), GFP_KERNEL);
  627. if (!d) {
  628. return -ENOMEM;
  629. }
  630. memset(d, 0, sizeof(*d));
  631. strcpy(m2info->fbcon.modename, "MATROX CRTC2");
  632. m2info->fbcon.changevar = NULL;
  633. m2info->fbcon.node = -1;
  634. m2info->fbcon.fbops = &matroxfb_dh_ops;
  635. m2info->fbcon.disp = d;
  636. m2info->fbcon.switch_con = &matroxfb_dh_switch;
  637. m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
  638. m2info->fbcon.blank = &matroxfb_dh_blank;
  639. m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
  640. m2info->currcon = -1;
  641. m2info->currcon_display = d;
  642. if (mem < 64)
  643. mem *= 1024;
  644. if (mem < 64*1024)
  645. mem *= 1024;
  646. mem &= ~0x00000FFF; /* PAGE_MASK? */
  647. if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len))
  648. m2info->video.offbase = ACCESS_FBINFO(video.len) - mem;
  649. else if (ACCESS_FBINFO(video.len) < mem) {
  650. kfree(d);
  651. return -ENOMEM;
  652. } else { /* check yres on first head... */
  653. m2info->video.borrowed = mem;
  654. ACCESS_FBINFO(video.len_usable) -= mem;
  655. m2info->video.offbase = ACCESS_FBINFO(video.len_usable);
  656. }
  657. m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase;
  658. m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem;
  659. m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase;
  660. m2info->mmio.base = ACCESS_FBINFO(mmio.base);
  661. m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
  662. m2info->mmio.len = ACCESS_FBINFO(mmio.len);
  663. /*
  664.  *  If we have unused output, connect CRTC2 to it...
  665.  */
  666. if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && 
  667.    !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
  668.    !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
  669. ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
  670. ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
  671. }
  672. matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
  673. if (register_framebuffer(&m2info->fbcon)) {
  674. kfree(d);
  675. return -ENXIO;
  676. }
  677. if (m2info->currcon < 0) {
  678. matroxfb_dh_set_var(&matroxfb_dh_defined, -1, &m2info->fbcon);
  679. }
  680. down_write(&ACCESS_FBINFO(crtc2.lock));
  681. oldcrtc2 = ACCESS_FBINFO(crtc2.info);
  682. ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
  683. up_write(&ACCESS_FBINFO(crtc2.lock));
  684. if (oldcrtc2) {
  685. printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %pn",
  686. oldcrtc2);
  687. }
  688. return 0;
  689. #undef minfo
  690. }
  691. /* ************************** */
  692. static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {
  693. #define minfo (m2info->primary_dev)
  694. if (matroxfb_dh_regit(PMINFO m2info)) {
  695. printk(KERN_ERR "matroxfb_crtc2: secondary head failed to registern");
  696. return -1;
  697. }
  698. printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%un",
  699. GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), GET_FB_IDX(m2info->fbcon.node));
  700. m2info->fbcon_registered = 1;
  701. return 0;
  702. #undef minfo
  703. }
  704. static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
  705. #define minfo (m2info->primary_dev)
  706. if (m2info->fbcon_registered) {
  707. int id;
  708. struct fb_info* crtc2;
  709. down_write(&ACCESS_FBINFO(crtc2.lock));
  710. crtc2 = ACCESS_FBINFO(crtc2.info);
  711. if (crtc2 == &m2info->fbcon)
  712. ACCESS_FBINFO(crtc2.info) = NULL;
  713. up_write(&ACCESS_FBINFO(crtc2.lock));
  714. if (crtc2 != &m2info->fbcon) {
  715. printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %pn",
  716. crtc2, &m2info->fbcon);
  717. printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.n");
  718. return;
  719. }
  720. id = GET_FB_IDX(m2info->fbcon.node);
  721. unregister_framebuffer(&m2info->fbcon);
  722. kfree(m2info->fbcon.disp);
  723. /* return memory back to primary head */
  724. ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed;
  725. printk(KERN_INFO "matroxfb_crtc2: fb%u unregisteredn", id);
  726. m2info->fbcon_registered = 0;
  727. }
  728. #undef minfo
  729. }
  730. static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
  731. struct matroxfb_dh_fb_info* m2info;
  732. /* hardware is CRTC2 incapable... */
  733. if (!ACCESS_FBINFO(devflags.crtc2))
  734. return NULL;
  735. m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
  736. if (!m2info) {
  737. printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structsn");
  738. return NULL;
  739. }
  740. memset(m2info, 0, sizeof(*m2info));
  741. m2info->primary_dev = MINFO;
  742. if (matroxfb_dh_registerfb(m2info)) {
  743. kfree(m2info);
  744. printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to registern");
  745. return NULL;
  746. }
  747. return m2info;
  748. }
  749. static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
  750. matroxfb_dh_deregisterfb(crtc2);
  751. }
  752. static struct matroxfb_driver crtc2 = {
  753. name: "Matrox G400 CRTC2",
  754. probe: matroxfb_crtc2_probe,
  755. remove: matroxfb_crtc2_remove };
  756. static int matroxfb_crtc2_init(void) {
  757. matroxfb_register_driver(&crtc2);
  758. return 0;
  759. }
  760. static void matroxfb_crtc2_exit(void) {
  761. matroxfb_unregister_driver(&crtc2);
  762. }
  763. MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
  764. MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
  765. MODULE_LICENSE("GPL");
  766. module_init(matroxfb_crtc2_init);
  767. module_exit(matroxfb_crtc2_exit);
  768. /* we do not have __setup() yet */