File Index
Files and directories
Sign in
FILE

fbcon_cw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/core/fbcon_cw.c C
  1/*
  2 *  linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
  3 *
  4 *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
  5 *
  6 *  This file is subject to the terms and conditions of the GNU General Public
  7 *  License.  See the file COPYING in the main directory of this archive for
  8 *  more details.
  9 */
 10
 11#include <linux/module.h>
 12#include <linux/slab.h>
 13#include <linux/string.h>
 14#include <linux/fb.h>
 15#include <linux/vt_kern.h>
 16#include <linux/console.h>
 17#include <asm/types.h>
 18#include "fbcon.h"
 19#include "fbcon_rotate.h"
 20
 21/*
 22 * Rotation 90 degrees
 23 */
 24
 25static void cw_update_attr(u8 *dst, u8 *src, int attribute,
 26				  struct vc_data *vc)
 27{
 28	int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
 29	int width = (vc->vc_font.height + 7) >> 3;
 30	u8 c, msk = ~(0xff >> offset);
 31
 32	for (i = 0; i < vc->vc_font.width; i++) {
 33		for (j = 0; j < width; j++) {
 34			c = *src;
 35			if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
 36				c |= msk;
 37			if (attribute & FBCON_ATTRIBUTE_BOLD && i)
 38				c |= *(src-width);
 39			if (attribute & FBCON_ATTRIBUTE_REVERSE)
 40				c = ~c;
 41			src++;
 42			*dst++ = c;
 43		}
 44	}
 45}
 46
 47
 48static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
 49		     int sx, int dy, int dx, int height, int width)
 50{
 51	struct fbcon_par *par = info->fbcon_par;
 52	struct fb_copyarea area;
 53	u32 vxres = GETVXRES(par->p, info);
 54
 55	area.sx = vxres - ((sy + height) * vc->vc_font.height);
 56	area.sy = sx * vc->vc_font.width;
 57	area.dx = vxres - ((dy + height) * vc->vc_font.height);
 58	area.dy = dx * vc->vc_font.width;
 59	area.width = height * vc->vc_font.height;
 60	area.height  = width * vc->vc_font.width;
 61
 62	info->fbops->fb_copyarea(info, &area);
 63}
 64
 65static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
 66		     int sx, int height, int width, int fg, int bg)
 67{
 68	struct fbcon_par *par = info->fbcon_par;
 69	struct fb_fillrect region;
 70	u32 vxres = GETVXRES(par->p, info);
 71
 72	region.color = bg;
 73	region.dx = vxres - ((sy + height) * vc->vc_font.height);
 74	region.dy = sx *  vc->vc_font.width;
 75	region.height = width * vc->vc_font.width;
 76	region.width = height * vc->vc_font.height;
 77	region.rop = ROP_COPY;
 78
 79	info->fbops->fb_fillrect(info, &region);
 80}
 81
 82static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
 83				    const u16 *s, u32 attr, u32 cnt,
 84				    u32 d_pitch, u32 s_pitch, u32 cellsize,
 85				    struct fb_image *image, u8 *buf, u8 *dst)
 86{
 87	struct fbcon_par *par = info->fbcon_par;
 88	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
 89	u32 idx = (vc->vc_font.height + 7) >> 3;
 90	u8 *src;
 91
 92	while (cnt--) {
 93		src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize;
 94
 95		if (attr) {
 96			cw_update_attr(buf, src, attr, vc);
 97			src = buf;
 98		}
 99
100		if (likely(idx == 1))
101			__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
102						vc->vc_font.width);
103		else
104			fb_pad_aligned_buffer(dst, d_pitch, src, idx,
105					      vc->vc_font.width);
106
107		dst += d_pitch * vc->vc_font.width;
108	}
109
110	info->fbops->fb_imageblit(info, image);
111}
112
113static void cw_putcs(struct vc_data *vc, struct fb_info *info,
114		      const unsigned short *s, int count, int yy, int xx,
115		      int fg, int bg)
116{
117	struct fb_image image;
118	struct fbcon_par *par = info->fbcon_par;
119	u32 width = (vc->vc_font.height + 7)/8;
120	u32 cellsize = width * vc->vc_font.width;
121	u32 maxcnt = info->pixmap.size/cellsize;
122	u32 scan_align = info->pixmap.scan_align - 1;
123	u32 buf_align = info->pixmap.buf_align - 1;
124	u32 cnt, pitch, size;
125	u32 attribute = get_attribute(info, scr_readw(s));
126	u8 *dst, *buf = NULL;
127	u32 vxres = GETVXRES(par->p, info);
128
129	if (!par->fontbuffer)
130		return;
131
132	image.fg_color = fg;
133	image.bg_color = bg;
134	image.dx = vxres - ((yy + 1) * vc->vc_font.height);
135	image.dy = xx * vc->vc_font.width;
136	image.width = vc->vc_font.height;
137	image.depth = 1;
138
139	if (attribute) {
140		buf = kmalloc(cellsize, GFP_KERNEL);
141		if (!buf)
142			return;
143	}
144
145	while (count) {
146		if (count > maxcnt)
147			cnt = maxcnt;
148		else
149			cnt = count;
150
151		image.height = vc->vc_font.width * cnt;
152		pitch = ((image.width + 7) >> 3) + scan_align;
153		pitch &= ~scan_align;
154		size = pitch * image.height + buf_align;
155		size &= ~buf_align;
156		dst = fb_get_buffer_offset(info, &info->pixmap, size);
157		image.data = dst;
158		cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
159				 width, cellsize, &image, buf, dst);
160		image.dy += image.height;
161		count -= cnt;
162		s += cnt;
163	}
164
165	/* buf is always NULL except when in monochrome mode, so in this case
166	   it's a gain to check buf against NULL even though kfree() handles
167	   NULL pointers just fine */
168	if (unlikely(buf))
169		kfree(buf);
170
171}
172
173static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
174			     int color, int bottom_only)
175{
176	unsigned int cw = vc->vc_font.width;
177	unsigned int ch = vc->vc_font.height;
178	unsigned int rw = info->var.yres - (vc->vc_cols*cw);
179	unsigned int bh = info->var.xres - (vc->vc_rows*ch);
180	unsigned int rs = info->var.yres - rw;
181	struct fb_fillrect region;
182
183	region.color = color;
184	region.rop = ROP_COPY;
185
186	if ((int) rw > 0 && !bottom_only) {
187		region.dx = 0;
188		region.dy = info->var.yoffset + rs;
189		region.height = rw;
190		region.width = info->var.xres_virtual;
191		info->fbops->fb_fillrect(info, &region);
192	}
193
194	if ((int) bh > 0) {
195		region.dx = info->var.xoffset;
196		region.dy = info->var.yoffset;
197                region.height = info->var.yres;
198                region.width = bh;
199		info->fbops->fb_fillrect(info, &region);
200	}
201}
202
203static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
204		      int fg, int bg)
205{
206	struct fb_cursor cursor;
207	struct fbcon_par *par = info->fbcon_par;
208	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
209	int w = (vc->vc_font.height + 7) >> 3, c;
210	int y = real_y(par->p, vc->state.y);
211	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
212	int err = 1, dx, dy;
213	char *src;
214	u32 vxres = GETVXRES(par->p, info);
215
216	if (!par->fontbuffer)
217		return;
218
219	cursor.set = 0;
220
221 	c = scr_readw((u16 *) vc->vc_pos);
222	attribute = get_attribute(info, c);
223	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
224
225	if (par->cursor_state.image.data != src ||
226	    par->cursor_reset) {
227		par->cursor_state.image.data = src;
228		cursor.set |= FB_CUR_SETIMAGE;
229	}
230
231	if (attribute) {
232		u8 *dst;
233
234		dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
235		if (!dst)
236			return;
237		kfree(par->cursor_data);
238		par->cursor_data = dst;
239		cw_update_attr(dst, src, attribute, vc);
240		src = dst;
241	}
242
243	if (par->cursor_state.image.fg_color != fg ||
244	    par->cursor_state.image.bg_color != bg ||
245	    par->cursor_reset) {
246		par->cursor_state.image.fg_color = fg;
247		par->cursor_state.image.bg_color = bg;
248		cursor.set |= FB_CUR_SETCMAP;
249	}
250
251	if (par->cursor_state.image.height != vc->vc_font.width ||
252	    par->cursor_state.image.width != vc->vc_font.height ||
253	    par->cursor_reset) {
254		par->cursor_state.image.height = vc->vc_font.width;
255		par->cursor_state.image.width = vc->vc_font.height;
256		cursor.set |= FB_CUR_SETSIZE;
257	}
258
259	dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
260	dy = vc->state.x * vc->vc_font.width;
261
262	if (par->cursor_state.image.dx != dx ||
263	    par->cursor_state.image.dy != dy ||
264	    par->cursor_reset) {
265		par->cursor_state.image.dx = dx;
266		par->cursor_state.image.dy = dy;
267		cursor.set |= FB_CUR_SETPOS;
268	}
269
270	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
271	    par->cursor_reset) {
272		par->cursor_state.hot.x = cursor.hot.y = 0;
273		cursor.set |= FB_CUR_SETHOT;
274	}
275
276	if (cursor.set & FB_CUR_SETSIZE ||
277	    vc->vc_cursor_type != par->p->cursor_shape ||
278	    par->cursor_state.mask == NULL ||
279	    par->cursor_reset) {
280		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
281						 GFP_ATOMIC);
282		int cur_height, size, i = 0;
283		int width = (vc->vc_font.width + 7)/8;
284
285		if (!mask)
286			return;
287
288		tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
289
290		if (!tmp) {
291			kfree(mask);
292			return;
293		}
294
295		kfree(par->cursor_state.mask);
296		par->cursor_state.mask = mask;
297
298		par->p->cursor_shape = vc->vc_cursor_type;
299		cursor.set |= FB_CUR_SETSHAPE;
300
301		switch (CUR_SIZE(par->p->cursor_shape)) {
302		case CUR_NONE:
303			cur_height = 0;
304			break;
305		case CUR_UNDERLINE:
306			cur_height = (vc->vc_font.height < 10) ? 1 : 2;
307			break;
308		case CUR_LOWER_THIRD:
309			cur_height = vc->vc_font.height/3;
310			break;
311		case CUR_LOWER_HALF:
312			cur_height = vc->vc_font.height >> 1;
313			break;
314		case CUR_TWO_THIRDS:
315			cur_height = (vc->vc_font.height << 1)/3;
316			break;
317		case CUR_BLOCK:
318		default:
319			cur_height = vc->vc_font.height;
320			break;
321		}
322
323		size = (vc->vc_font.height - cur_height) * width;
324		while (size--)
325			tmp[i++] = 0;
326		size = cur_height * width;
327		while (size--)
328			tmp[i++] = 0xff;
329		memset(mask, 0, w * vc->vc_font.width);
330		rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
331		kfree(tmp);
332	}
333
334	par->cursor_state.enable = enable && !use_sw;
335
336	cursor.image.data = src;
337	cursor.image.fg_color = par->cursor_state.image.fg_color;
338	cursor.image.bg_color = par->cursor_state.image.bg_color;
339	cursor.image.dx = par->cursor_state.image.dx;
340	cursor.image.dy = par->cursor_state.image.dy;
341	cursor.image.height = par->cursor_state.image.height;
342	cursor.image.width = par->cursor_state.image.width;
343	cursor.hot.x = par->cursor_state.hot.x;
344	cursor.hot.y = par->cursor_state.hot.y;
345	cursor.mask = par->cursor_state.mask;
346	cursor.enable = par->cursor_state.enable;
347	cursor.image.depth = 1;
348	cursor.rop = ROP_XOR;
349
350	if (info->fbops->fb_cursor)
351		err = info->fbops->fb_cursor(info, &cursor);
352
353	if (err)
354		soft_cursor(info, &cursor);
355
356	par->cursor_reset = 0;
357}
358
359static int cw_update_start(struct fb_info *info)
360{
361	struct fbcon_par *par = info->fbcon_par;
362	u32 vxres = GETVXRES(par->p, info);
363	u32 xoffset;
364	int err;
365
366	xoffset = vxres - (info->var.xres + par->var.yoffset);
367	par->var.yoffset = par->var.xoffset;
368	par->var.xoffset = xoffset;
369	err = fb_pan_display(info, &par->var);
370	par->var.xoffset = info->var.xoffset;
371	par->var.yoffset = info->var.yoffset;
372	par->var.vmode = info->var.vmode;
373	return err;
374}
375
376static const struct fbcon_bitops cw_fbcon_bitops = {
377	.bmove = cw_bmove,
378	.clear = cw_clear,
379	.putcs = cw_putcs,
380	.clear_margins = cw_clear_margins,
381	.cursor = cw_cursor,
382	.update_start = cw_update_start,
383	.rotate_font = fbcon_rotate_font,
384};
385
386void fbcon_set_bitops_cw(struct fbcon_par *par)
387{
388	par->bitops = &cw_fbcon_bitops;
389}
~/ Read-only file preview.