Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 1 | // Code for manipulating VGA framebuffers. |
| 2 | // |
| 3 | // Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net> |
| 4 | // Copyright (C) 2001-2008 the LGPL VGABios developers Team |
| 5 | // |
| 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
| 7 | |
Kevin O'Connor | f98bbf0 | 2012-01-27 23:09:02 -0500 | [diff] [blame] | 8 | #include "vgabios.h" // vgafb_scroll |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 9 | #include "biosvar.h" // GET_BDA |
| 10 | #include "util.h" // memset_far |
Kevin O'Connor | b306459 | 2012-08-14 21:20:10 -0400 | [diff] [blame] | 11 | #include "byteorder.h" // cpu_to_be16 |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 12 | #include "stdvga.h" // stdvga_planar4_plane |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 13 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 14 | |
| 15 | /**************************************************************** |
| 16 | * Screen scrolling |
| 17 | ****************************************************************/ |
| 18 | |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 19 | static inline void * |
| 20 | memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 21 | { |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 22 | for (; lines; lines--, dst+=stride, src+=stride) |
| 23 | memcpy_far(seg, dst, seg, src, copylen); |
| 24 | return dst; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 25 | } |
| 26 | |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 27 | static inline void |
| 28 | memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 29 | { |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 30 | for (; lines; lines--, dst+=stride) |
| 31 | memset_far(seg, dst, val, setlen); |
| 32 | } |
| 33 | |
| 34 | static inline void |
| 35 | memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines) |
| 36 | { |
| 37 | for (; lines; lines--, dst+=stride) |
| 38 | memset16_far(seg, dst, val, setlen); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | static void |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 42 | scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr |
| 43 | , struct cursorpos ul, struct cursorpos lr) |
| 44 | { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 45 | int cheight = GET_GLOBAL(vmode_g->cheight); |
| 46 | int cwidth = 1; |
| 47 | int stride = GET_BDA(video_cols) * cwidth; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 48 | void *src_far, *dest_far; |
| 49 | if (nblines >= 0) { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 50 | dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 51 | src_far = dest_far + nblines * cheight * stride; |
| 52 | } else { |
| 53 | // Scroll down |
| 54 | nblines = -nblines; |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 55 | dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 56 | src_far = dest_far - nblines * cheight * stride; |
| 57 | stride = -stride; |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 58 | } |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 59 | if (attr < 0) |
| 60 | attr = 0; |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 61 | int cols = lr.x - ul.x + 1; |
| 62 | int rows = lr.y - ul.y + 1; |
| 63 | int i; |
| 64 | for (i=0; i<4; i++) { |
| 65 | stdvga_planar4_plane(i); |
| 66 | void *dest = dest_far; |
| 67 | if (nblines < rows) |
| 68 | dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth |
| 69 | , stride, (rows - nblines) * cheight); |
| 70 | u8 pixels = (attr & (1<<i)) ? 0xff : 0x00; |
| 71 | memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth |
| 72 | , stride, nblines * cheight); |
| 73 | } |
| 74 | stdvga_planar4_plane(-1); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 75 | } |
| 76 | |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 77 | static void |
| 78 | scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr |
| 79 | , struct cursorpos ul, struct cursorpos lr) |
| 80 | { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 81 | int cheight = GET_GLOBAL(vmode_g->cheight) / 2; |
Kevin O'Connor | 80da87d | 2012-01-02 11:13:14 -0500 | [diff] [blame] | 82 | int cwidth = GET_GLOBAL(vmode_g->depth); |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 83 | int stride = GET_BDA(video_cols) * cwidth; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 84 | void *src_far, *dest_far; |
| 85 | if (nblines >= 0) { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 86 | dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 87 | src_far = dest_far + nblines * cheight * stride; |
| 88 | } else { |
| 89 | // Scroll down |
| 90 | nblines = -nblines; |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 91 | dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 92 | src_far = dest_far - nblines * cheight * stride; |
| 93 | stride = -stride; |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 94 | } |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 95 | if (attr < 0) |
| 96 | attr = 0; |
Kevin O'Connor | b888695 | 2012-02-02 20:56:38 -0500 | [diff] [blame] | 97 | if (cwidth == 1) |
| 98 | attr = (attr&1) | ((attr&1)<<1); |
| 99 | attr &= 3; |
| 100 | attr |= (attr<<2) | (attr<<4) | (attr<<6); |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 101 | int cols = lr.x - ul.x + 1; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 102 | int rows = lr.y - ul.y + 1; |
| 103 | if (nblines < rows) { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 104 | memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth |
Kevin O'Connor | ae6eb8f | 2012-01-01 10:33:51 -0500 | [diff] [blame] | 105 | , stride, (rows - nblines) * cheight); |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 106 | dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth |
Kevin O'Connor | ae6eb8f | 2012-01-01 10:33:51 -0500 | [diff] [blame] | 107 | , stride, (rows - nblines) * cheight); |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 108 | } |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 109 | memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth |
Kevin O'Connor | ae6eb8f | 2012-01-01 10:33:51 -0500 | [diff] [blame] | 110 | , stride, nblines * cheight); |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 111 | memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth |
Kevin O'Connor | ae6eb8f | 2012-01-01 10:33:51 -0500 | [diff] [blame] | 112 | , stride, nblines * cheight); |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | static void |
Kevin O'Connor | b937397 | 2012-01-01 11:04:42 -0500 | [diff] [blame] | 116 | scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr |
| 117 | , struct cursorpos ul, struct cursorpos lr) |
| 118 | { |
| 119 | int cheight = 8; |
| 120 | int cwidth = 8; |
| 121 | int stride = GET_BDA(video_cols) * cwidth; |
| 122 | void *src_far, *dest_far; |
| 123 | if (nblines >= 0) { |
| 124 | dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); |
| 125 | src_far = dest_far + nblines * cheight * stride; |
| 126 | } else { |
| 127 | // Scroll down |
| 128 | nblines = -nblines; |
| 129 | dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); |
| 130 | src_far = dest_far - nblines * cheight * stride; |
| 131 | stride = -stride; |
| 132 | } |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 133 | if (attr < 0) |
| 134 | attr = 0; |
Kevin O'Connor | b937397 | 2012-01-01 11:04:42 -0500 | [diff] [blame] | 135 | int cols = lr.x - ul.x + 1; |
| 136 | int rows = lr.y - ul.y + 1; |
| 137 | if (nblines < rows) |
| 138 | dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth |
| 139 | , stride, (rows - nblines) * cheight); |
Kevin O'Connor | b937397 | 2012-01-01 11:04:42 -0500 | [diff] [blame] | 140 | memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth |
| 141 | , stride, nblines * cheight); |
| 142 | } |
| 143 | |
| 144 | static void |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 145 | scroll_text(struct vgamode_s *vmode_g, int nblines, int attr |
| 146 | , struct cursorpos ul, struct cursorpos lr) |
| 147 | { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 148 | int cheight = 1; |
| 149 | int cwidth = 2; |
Kevin O'Connor | 83047be | 2012-01-07 18:27:19 -0500 | [diff] [blame] | 150 | int stride = GET_BDA(video_cols) * cwidth; |
| 151 | void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page); |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 152 | if (nblines >= 0) { |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 153 | dest_far += ul.y * cheight * stride + ul.x * cwidth; |
| 154 | src_far = dest_far + nblines * cheight * stride; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 155 | } else { |
| 156 | // Scroll down |
| 157 | nblines = -nblines; |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 158 | dest_far += lr.y * cheight * stride + ul.x * cwidth; |
| 159 | src_far = dest_far - nblines * cheight * stride; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 160 | stride = -stride; |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 161 | } |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 162 | if (attr < 0) |
| 163 | attr = 0x07; |
| 164 | attr = (attr << 8) | ' '; |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 165 | int cols = lr.x - ul.x + 1; |
Kevin O'Connor | 2c34f41 | 2009-05-31 15:25:14 -0400 | [diff] [blame] | 166 | int rows = lr.y - ul.y + 1; |
| 167 | u16 seg = GET_GLOBAL(vmode_g->sstart); |
| 168 | if (nblines < rows) |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 169 | dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth |
| 170 | , stride, (rows - nblines) * cheight); |
Kevin O'Connor | 68ab041 | 2012-01-01 10:54:19 -0500 | [diff] [blame] | 171 | memset16_stride(seg, dest_far, attr, cols * cwidth |
| 172 | , stride, nblines * cheight); |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | void |
| 176 | vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr) |
| 177 | { |
| 178 | // Get the mode |
Kevin O'Connor | 4a73f93 | 2012-01-21 11:08:35 -0500 | [diff] [blame] | 179 | struct vgamode_s *vmode_g = get_current_mode(); |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 180 | if (!vmode_g) |
| 181 | return; |
| 182 | |
| 183 | // FIXME gfx mode not complete |
| 184 | switch (GET_GLOBAL(vmode_g->memmodel)) { |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 185 | case MM_TEXT: |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 186 | scroll_text(vmode_g, nblines, attr, ul, lr); |
| 187 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 188 | case MM_PLANAR: |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 189 | scroll_pl4(vmode_g, nblines, attr, ul, lr); |
| 190 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 191 | case MM_CGA: |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 192 | scroll_cga(vmode_g, nblines, attr, ul, lr); |
| 193 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 194 | case MM_DIRECT: |
| 195 | case MM_PACKED: |
Kevin O'Connor | b937397 | 2012-01-01 11:04:42 -0500 | [diff] [blame] | 196 | scroll_lin(vmode_g, nblines, attr, ul, lr); |
| 197 | break; |
Kevin O'Connor | a026308 | 2012-04-14 20:22:18 -0400 | [diff] [blame] | 198 | default: |
| 199 | break; |
Kevin O'Connor | 217f2bc | 2009-05-31 00:46:47 -0400 | [diff] [blame] | 200 | } |
| 201 | } |
| 202 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 203 | |
| 204 | /**************************************************************** |
| 205 | * Read/write characters to screen |
| 206 | ****************************************************************/ |
| 207 | |
| 208 | static void |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 209 | write_gfx_char_pl4(struct vgamode_s *vmode_g |
| 210 | , struct cursorpos cp, struct carattr ca) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 211 | { |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 212 | u16 nbcols = GET_BDA(video_cols); |
| 213 | if (cp.x >= nbcols) |
| 214 | return; |
| 215 | |
Kevin O'Connor | 87233e9 | 2011-12-23 21:40:34 -0500 | [diff] [blame] | 216 | u8 cheight = GET_GLOBAL(vmode_g->cheight); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 217 | u8 *fdata_g; |
| 218 | switch (cheight) { |
| 219 | case 14: |
| 220 | fdata_g = vgafont14; |
| 221 | break; |
| 222 | case 16: |
| 223 | fdata_g = vgafont16; |
| 224 | break; |
| 225 | default: |
| 226 | fdata_g = vgafont8; |
| 227 | } |
Kevin O'Connor | 918b156 | 2009-05-25 11:05:18 -0400 | [diff] [blame] | 228 | u16 addr = cp.x + cp.y * cheight * nbcols; |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 229 | u16 src = ca.car * cheight; |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 230 | int i; |
| 231 | for (i=0; i<4; i++) { |
| 232 | stdvga_planar4_plane(i); |
| 233 | u8 colors = ((ca.attr & (1<<i)) ? 0xff : 0x00); |
| 234 | int j; |
| 235 | for (j = 0; j < cheight; j++) { |
| 236 | u8 *dest_far = (void*)(addr + j * nbcols); |
| 237 | u8 pixels = colors & GET_GLOBAL(fdata_g[src + j]); |
| 238 | if (ca.attr & 0x80) |
| 239 | pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far); |
| 240 | SET_FARVAR(SEG_GRAPH, *dest_far, pixels); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 241 | } |
| 242 | } |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 243 | stdvga_planar4_plane(-1); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | static void |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 247 | write_gfx_char_cga(struct vgamode_s *vmode_g |
| 248 | , struct cursorpos cp, struct carattr ca) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 249 | { |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 250 | u16 nbcols = GET_BDA(video_cols); |
| 251 | if (cp.x >= nbcols) |
| 252 | return; |
| 253 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 254 | u8 *fdata_g = vgafont8; |
Kevin O'Connor | 80da87d | 2012-01-02 11:13:14 -0500 | [diff] [blame] | 255 | u8 bpp = GET_GLOBAL(vmode_g->depth); |
Kevin O'Connor | 918b156 | 2009-05-25 11:05:18 -0400 | [diff] [blame] | 256 | u16 addr = (cp.x * bpp) + cp.y * 320; |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 257 | u16 src = ca.car * 8; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 258 | u8 i; |
| 259 | for (i = 0; i < 8; i++) { |
| 260 | u8 *dest_far = (void*)(addr + (i >> 1) * 80); |
| 261 | if (i & 1) |
| 262 | dest_far += 0x2000; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 263 | if (bpp == 1) { |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 264 | u8 colors = (ca.attr & 0x01) ? 0xff : 0x00; |
| 265 | u8 pixels = colors & GET_GLOBAL(fdata_g[src + i]); |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 266 | if (ca.attr & 0x80) |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 267 | pixels ^= GET_FARVAR(SEG_GRAPH, *dest_far); |
| 268 | SET_FARVAR(SEG_CTEXT, *dest_far, pixels); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 269 | } else { |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 270 | u16 pixels = 0; |
| 271 | u8 fontline = GET_GLOBAL(fdata_g[src + i]); |
| 272 | int j; |
| 273 | for (j = 0; j < 8; j++) |
| 274 | if (fontline & (1<<j)) |
| 275 | pixels |= (ca.attr & 0x03) << (j*2); |
Kevin O'Connor | b306459 | 2012-08-14 21:20:10 -0400 | [diff] [blame] | 276 | pixels = cpu_to_be16(pixels); |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 277 | if (ca.attr & 0x80) |
| 278 | pixels ^= GET_FARVAR(SEG_GRAPH, *(u16*)dest_far); |
| 279 | SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, pixels); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 280 | } |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | static void |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 285 | write_gfx_char_lin(struct vgamode_s *vmode_g |
| 286 | , struct cursorpos cp, struct carattr ca) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 287 | { |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 288 | // Get the dimensions |
| 289 | u16 nbcols = GET_BDA(video_cols); |
| 290 | if (cp.x >= nbcols) |
| 291 | return; |
| 292 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 293 | u8 *fdata_g = vgafont8; |
Kevin O'Connor | 918b156 | 2009-05-25 11:05:18 -0400 | [diff] [blame] | 294 | u16 addr = cp.x * 8 + cp.y * nbcols * 64; |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 295 | u16 src = ca.car * 8; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 296 | u8 i; |
| 297 | for (i = 0; i < 8; i++) { |
| 298 | u8 *dest_far = (void*)(addr + i * nbcols * 8); |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 299 | u8 fontline = GET_GLOBAL(fdata_g[src + i]); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 300 | u8 j; |
| 301 | for (j = 0; j < 8; j++) { |
Kevin O'Connor | 9a4d0c1 | 2012-02-02 20:56:10 -0500 | [diff] [blame] | 302 | u8 pixel = (fontline & (0x80>>j)) ? ca.attr : 0x00; |
| 303 | SET_FARVAR(SEG_GRAPH, dest_far[j], pixel); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 304 | } |
| 305 | } |
| 306 | } |
| 307 | |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 308 | static void |
| 309 | write_text_char(struct vgamode_s *vmode_g |
| 310 | , struct cursorpos cp, struct carattr ca) |
| 311 | { |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 312 | // Compute the address |
Kevin O'Connor | 83047be | 2012-01-07 18:27:19 -0500 | [diff] [blame] | 313 | u16 nbcols = GET_BDA(video_cols); |
| 314 | void *address_far = (void*)(GET_BDA(video_pagesize) * cp.page |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 315 | + (cp.x + cp.y * nbcols) * 2); |
| 316 | |
| 317 | if (ca.use_attr) { |
| 318 | u16 dummy = (ca.attr << 8) | ca.car; |
| 319 | SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy); |
| 320 | } else { |
| 321 | SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car); |
| 322 | } |
| 323 | } |
| 324 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 325 | void |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 326 | vgafb_write_char(struct cursorpos cp, struct carattr ca) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 327 | { |
| 328 | // Get the mode |
Kevin O'Connor | 4a73f93 | 2012-01-21 11:08:35 -0500 | [diff] [blame] | 329 | struct vgamode_s *vmode_g = get_current_mode(); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 330 | if (!vmode_g) |
| 331 | return; |
| 332 | |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 333 | // FIXME gfx mode not complete |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 334 | switch (GET_GLOBAL(vmode_g->memmodel)) { |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 335 | case MM_TEXT: |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 336 | write_text_char(vmode_g, cp, ca); |
| 337 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 338 | case MM_PLANAR: |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 339 | write_gfx_char_pl4(vmode_g, cp, ca); |
| 340 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 341 | case MM_CGA: |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 342 | write_gfx_char_cga(vmode_g, cp, ca); |
| 343 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 344 | case MM_DIRECT: |
| 345 | case MM_PACKED: |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 346 | write_gfx_char_lin(vmode_g, cp, ca); |
| 347 | break; |
Kevin O'Connor | a026308 | 2012-04-14 20:22:18 -0400 | [diff] [blame] | 348 | default: |
| 349 | break; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 350 | } |
| 351 | } |
| 352 | |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 353 | struct carattr |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 354 | vgafb_read_char(struct cursorpos cp) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 355 | { |
| 356 | // Get the mode |
Kevin O'Connor | 4a73f93 | 2012-01-21 11:08:35 -0500 | [diff] [blame] | 357 | struct vgamode_s *vmode_g = get_current_mode(); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 358 | if (!vmode_g) |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 359 | goto fail; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 360 | |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 361 | if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) { |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 362 | // FIXME gfx mode |
| 363 | dprintf(1, "Read char in graphics mode\n"); |
| 364 | goto fail; |
| 365 | } |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 366 | |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 367 | // Compute the address |
Kevin O'Connor | 83047be | 2012-01-07 18:27:19 -0500 | [diff] [blame] | 368 | u16 nbcols = GET_BDA(video_cols); |
| 369 | u16 *address_far = (void*)(GET_BDA(video_pagesize) * cp.page |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 370 | + (cp.x + cp.y * nbcols) * 2); |
| 371 | u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far); |
| 372 | struct carattr ca = {v, v>>8, 0}; |
Kevin O'Connor | 0926241 | 2009-05-25 11:44:11 -0400 | [diff] [blame] | 373 | return ca; |
Kevin O'Connor | d3b3815 | 2009-05-26 00:05:37 -0400 | [diff] [blame] | 374 | |
| 375 | fail: ; |
| 376 | struct carattr ca2 = {0, 0, 0}; |
| 377 | return ca2; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 378 | } |
| 379 | |
| 380 | |
| 381 | /**************************************************************** |
| 382 | * Read/write pixels |
| 383 | ****************************************************************/ |
| 384 | |
| 385 | void |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 386 | vgafb_write_pixel(u8 color, u16 x, u16 y) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 387 | { |
| 388 | // Get the mode |
Kevin O'Connor | 4a73f93 | 2012-01-21 11:08:35 -0500 | [diff] [blame] | 389 | struct vgamode_s *vmode_g = get_current_mode(); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 390 | if (!vmode_g) |
| 391 | return; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 392 | |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 393 | u8 *addr_far, mask, attr, data, i; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 394 | switch (GET_GLOBAL(vmode_g->memmodel)) { |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 395 | case MM_PLANAR: |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 396 | addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); |
| 397 | mask = 0x80 >> (x & 0x07); |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 398 | for (i=0; i<4; i++) { |
| 399 | stdvga_planar4_plane(i); |
| 400 | u8 colors = (color & (1<<i)) ? 0xff : 0x00; |
| 401 | u8 orig = GET_FARVAR(SEG_GRAPH, *addr_far); |
| 402 | if (color & 0x80) |
| 403 | colors ^= orig; |
| 404 | SET_FARVAR(SEG_GRAPH, *addr_far, (colors & mask) | (orig & ~mask)); |
| 405 | } |
| 406 | stdvga_planar4_plane(-1); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 407 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 408 | case MM_CGA: |
Kevin O'Connor | 80da87d | 2012-01-02 11:13:14 -0500 | [diff] [blame] | 409 | if (GET_GLOBAL(vmode_g->depth) == 2) |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 410 | addr_far = (void*)((x >> 2) + (y >> 1) * 80); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 411 | else |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 412 | addr_far = (void*)((x >> 3) + (y >> 1) * 80); |
| 413 | if (y & 1) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 414 | addr_far += 0x2000; |
| 415 | data = GET_FARVAR(SEG_CTEXT, *addr_far); |
Kevin O'Connor | 80da87d | 2012-01-02 11:13:14 -0500 | [diff] [blame] | 416 | if (GET_GLOBAL(vmode_g->depth) == 2) { |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 417 | attr = (color & 0x03) << ((3 - (x & 0x03)) * 2); |
| 418 | mask = 0x03 << ((3 - (x & 0x03)) * 2); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 419 | } else { |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 420 | attr = (color & 0x01) << (7 - (x & 0x07)); |
| 421 | mask = 0x01 << (7 - (x & 0x07)); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 422 | } |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 423 | if (color & 0x80) { |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 424 | data ^= attr; |
| 425 | } else { |
| 426 | data &= ~mask; |
| 427 | data |= attr; |
| 428 | } |
| 429 | SET_FARVAR(SEG_CTEXT, *addr_far, data); |
| 430 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 431 | case MM_DIRECT: |
| 432 | case MM_PACKED: |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 433 | addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8)); |
| 434 | SET_FARVAR(SEG_GRAPH, *addr_far, color); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 435 | break; |
Kevin O'Connor | a026308 | 2012-04-14 20:22:18 -0400 | [diff] [blame] | 436 | default: |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 437 | case MM_TEXT: |
| 438 | return; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 439 | } |
| 440 | } |
| 441 | |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 442 | u8 |
| 443 | vgafb_read_pixel(u16 x, u16 y) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 444 | { |
| 445 | // Get the mode |
Kevin O'Connor | 4a73f93 | 2012-01-21 11:08:35 -0500 | [diff] [blame] | 446 | struct vgamode_s *vmode_g = get_current_mode(); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 447 | if (!vmode_g) |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 448 | return 0; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 449 | |
| 450 | u8 *addr_far, mask, attr=0, data, i; |
| 451 | switch (GET_GLOBAL(vmode_g->memmodel)) { |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 452 | case MM_PLANAR: |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 453 | addr_far = (void*)(x / 8 + y * GET_BDA(video_cols)); |
| 454 | mask = 0x80 >> (x & 0x07); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 455 | attr = 0x00; |
| 456 | for (i = 0; i < 4; i++) { |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 457 | stdvga_planar4_plane(i); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 458 | data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask; |
| 459 | if (data > 0) |
| 460 | attr |= (0x01 << i); |
| 461 | } |
Kevin O'Connor | 160d34a | 2012-01-16 18:48:26 -0500 | [diff] [blame] | 462 | stdvga_planar4_plane(-1); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 463 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 464 | case MM_CGA: |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 465 | addr_far = (void*)((x >> 2) + (y >> 1) * 80); |
| 466 | if (y & 1) |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 467 | addr_far += 0x2000; |
| 468 | data = GET_FARVAR(SEG_CTEXT, *addr_far); |
Kevin O'Connor | 80da87d | 2012-01-02 11:13:14 -0500 | [diff] [blame] | 469 | if (GET_GLOBAL(vmode_g->depth) == 2) |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 470 | attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 471 | else |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 472 | attr = (data >> (7 - (x & 0x07))) & 0x01; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 473 | break; |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 474 | case MM_DIRECT: |
| 475 | case MM_PACKED: |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 476 | addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8)); |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 477 | attr = GET_FARVAR(SEG_GRAPH, *addr_far); |
| 478 | break; |
Kevin O'Connor | a026308 | 2012-04-14 20:22:18 -0400 | [diff] [blame] | 479 | default: |
Kevin O'Connor | d4398ad | 2012-01-01 12:32:53 -0500 | [diff] [blame] | 480 | case MM_TEXT: |
| 481 | return 0; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 482 | } |
Kevin O'Connor | 227a2bb | 2009-05-31 22:00:20 -0400 | [diff] [blame] | 483 | return attr; |
Kevin O'Connor | c0c7df6 | 2009-05-17 18:11:33 -0400 | [diff] [blame] | 484 | } |