matroxfb_crtc2.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
源码类别:

Linux/Unix编程

开发平台:

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