Merge branch 'vendor/GCC50'
[dragonfly.git] / sys / dev / misc / syscons / scvtb.c
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/syscons/scvtb.c,v 1.5.2.1 2001/07/16 05:21:23 yokota Exp $
27  * $DragonFly: src/sys/dev/misc/syscons/scvtb.c,v 1.9 2006/09/05 03:48:10 dillon Exp $
28  */
29
30 #include "opt_syscons.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34
35 #include <machine/console.h>
36 #include <machine/cpufunc.h>
37 #include <machine/md_var.h>
38
39 #include <dev/video/fb/fbreg.h>
40 #include "syscons.h"
41
42 #define vtb_wrap(vtb, at, offset)                               \
43     (((at) + (offset) + (vtb)->vtb_size)%(vtb)->vtb_size)
44
45
46 /*
47  * Intel text mode emulations can't handle 32-bit or 64-bit writes.
48  * Use 16-bit writes.  32 and 64-bit writes appear to simply get thrown
49  * away.  (observed on D2500HN mobo).
50  *
51  * We don't care about performance so just use a word-write bcopy mode.
52  */
53 static
54 void
55 sc_vtb_bcopy(void *s, void *d, size_t bytes)
56 {
57         size_t count;
58         size_t n;
59         uint16_t *sw = s;
60         uint16_t *dw = d;
61
62         count = bytes >> 1;
63         if (s < d) {
64                 if (bytes & 1)
65                         *(uint8_t *)(dw + count) = *(uint8_t *)(sw + count);
66                 while (count--) {
67                         dw[count] = sw[count];
68                 }
69         } else {
70                 for (n = 0; n < count; ++n)
71                         dw[n] = sw[n];
72                 if (bytes & 1) {
73                         *(uint8_t *)(dw + n) = *(uint8_t *)(sw + n);
74                 }
75         }
76 }
77
78 void
79 sc_vtb_init(sc_vtb_t *vtb, int type, int cols, int rows, void *buf, int wait)
80 {
81         vtb->vtb_flags = 0;
82         vtb->vtb_type = type;
83         vtb->vtb_cols = cols;
84         vtb->vtb_rows = rows;
85         vtb->vtb_size = cols*rows;
86         vtb->vtb_buffer = NULL;
87         vtb->vtb_tail = 0;
88
89         switch (type) {
90         case VTB_MEMORY:
91         case VTB_RINGBUFFER:
92                 if ((buf == NULL) && (cols*rows != 0)) {
93                         vtb->vtb_buffer = kmalloc(cols*rows*sizeof(uint16_t),
94                                     M_SYSCONS,
95                                     M_ZERO | ((wait) ? M_WAITOK : M_NOWAIT));
96                         if (vtb->vtb_buffer != NULL) {
97                                 vtb->vtb_flags |= VTB_VALID;
98                                 vtb->vtb_flags |= VTB_ALLOCED;
99                         }
100                 } else {
101                         vtb->vtb_buffer = buf;
102                         vtb->vtb_flags |= VTB_VALID;
103                 }
104                 break;
105         case VTB_FRAMEBUFFER:
106                 vtb->vtb_buffer = buf;
107                 vtb->vtb_flags |= VTB_VALID;
108                 break;
109         default:
110                 break;
111         }
112 }
113
114 void
115 sc_vtb_destroy(sc_vtb_t *vtb)
116 {
117         uint16_t *p;
118
119         vtb->vtb_cols = 0;
120         vtb->vtb_rows = 0;
121         vtb->vtb_size = 0;
122         vtb->vtb_tail = 0;
123
124         p = vtb->vtb_buffer;
125         vtb->vtb_buffer = NULL;
126         switch (vtb->vtb_type) {
127         case VTB_MEMORY:
128         case VTB_RINGBUFFER:
129                 if ((vtb->vtb_flags & VTB_ALLOCED) && (p != NULL))
130                         kfree(p, M_SYSCONS);
131                 break;
132         default:
133                 break;
134         }
135         vtb->vtb_flags = 0;
136         vtb->vtb_type = VTB_INVALID;
137 }
138
139 size_t
140 sc_vtb_size(int cols, int rows)
141 {
142         return (size_t)(cols*rows*sizeof(uint16_t));
143 }
144
145 int
146 sc_vtb_getc(sc_vtb_t *vtb, int at)
147 {
148         if (vtb->vtb_type == VTB_FRAMEBUFFER)
149                 return (readw(vtb->vtb_buffer + at) & 0x00ff);
150         else
151                 return (*(vtb->vtb_buffer + at) & 0x00ff);
152 }
153
154 int
155 sc_vtb_geta(sc_vtb_t *vtb, int at)
156 {
157         if (vtb->vtb_type == VTB_FRAMEBUFFER)
158                 return (readw(vtb->vtb_buffer + at) & 0xff00);
159         else
160                 return (*(vtb->vtb_buffer + at) & 0xff00);
161 }
162
163 void
164 sc_vtb_putc(sc_vtb_t *vtb, int at, int c, int a)
165 {
166         if (vtb->vtb_type == VTB_FRAMEBUFFER)
167                 writew(vtb->vtb_buffer + at, a | c);
168         else
169                 *(vtb->vtb_buffer + at) = a | c;
170 }
171
172 uint16_t *
173 sc_vtb_putchar(sc_vtb_t *vtb, uint16_t *p, int c, int a)
174 {
175         if (vtb->vtb_type == VTB_FRAMEBUFFER)
176                 writew(p, a | c);
177         else
178                 *p = a | c;
179         return (p + 1);
180 }
181
182 int
183 sc_vtb_pos(sc_vtb_t *vtb, int pos, int offset)
184 {
185         return ((pos + offset + vtb->vtb_size)%vtb->vtb_size);
186 }
187
188 void
189 sc_vtb_clear(sc_vtb_t *vtb, int c, int attr)
190 {
191         if (vtb->vtb_type == VTB_FRAMEBUFFER)
192                 fillw_io(attr | c, vtb->vtb_buffer, vtb->vtb_size);
193         else
194                 fillw(attr | c, vtb->vtb_buffer, vtb->vtb_size);
195 }
196
197 void
198 sc_vtb_copy(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int to, int count)
199 {
200         /* XXX if both are VTB_VRAMEBUFFER... */
201         if (vtb2->vtb_type == VTB_FRAMEBUFFER) {
202                 sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
203                            count*sizeof(uint16_t));
204         } else if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
205                 sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
206                              count*sizeof(uint16_t));
207         } else {
208                 sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
209                       count*sizeof(uint16_t));
210         }
211 }
212
213 void
214 sc_vtb_append(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int count)
215 {
216         int len;
217
218         if (vtb2->vtb_type != VTB_RINGBUFFER)
219                 return;
220
221         while (count > 0) {
222                 len = imin(count, vtb2->vtb_size - vtb2->vtb_tail);
223                 if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
224                         sc_vtb_bcopy(vtb1->vtb_buffer + from,
225                                      vtb2->vtb_buffer + vtb2->vtb_tail,
226                                      len*sizeof(uint16_t));
227                 } else {
228                         sc_vtb_bcopy(vtb1->vtb_buffer + from,
229                               vtb2->vtb_buffer + vtb2->vtb_tail,
230                               len*sizeof(uint16_t));
231                 }
232                 from += len;
233                 count -= len;
234                 vtb2->vtb_tail = vtb_wrap(vtb2, vtb2->vtb_tail, len);
235         }
236 }
237
238 void
239 sc_vtb_seek(sc_vtb_t *vtb, int pos)
240 {
241         vtb->vtb_tail = pos%vtb->vtb_size;
242 }
243
244 void
245 sc_vtb_erase(sc_vtb_t *vtb, int at, int count, int c, int attr)
246 {
247         if (at + count > vtb->vtb_size)
248                 count = vtb->vtb_size - at;
249         if (vtb->vtb_type == VTB_FRAMEBUFFER)
250                 fillw_io(attr | c, vtb->vtb_buffer + at, count);
251         else
252                 fillw(attr | c, vtb->vtb_buffer + at, count);
253 }
254
255 void
256 sc_vtb_move(sc_vtb_t *vtb, int from, int to, int count)
257 {
258         if (from + count > vtb->vtb_size)
259                 count = vtb->vtb_size - from;
260         if (to + count > vtb->vtb_size)
261                 count = vtb->vtb_size - to;
262         if (count <= 0)
263                 return;
264         if (vtb->vtb_type == VTB_FRAMEBUFFER) {
265                 sc_vtb_bcopy(vtb->vtb_buffer + from, vtb->vtb_buffer + to,
266                          count*sizeof(uint16_t)); 
267         } else {
268                 sc_vtb_bcopy(vtb->vtb_buffer + from, vtb->vtb_buffer + to,
269                       count*sizeof(uint16_t));
270         }
271 }
272
273 void
274 sc_vtb_delete(sc_vtb_t *vtb, int at, int count, int c, int attr)
275 {
276         int len;
277
278         if (at + count > vtb->vtb_size)
279                 count = vtb->vtb_size - at;
280         len = vtb->vtb_size - at - count;
281         if (len > 0) {
282                 if (vtb->vtb_type == VTB_FRAMEBUFFER) {
283                         sc_vtb_bcopy(vtb->vtb_buffer + at + count,
284                                  vtb->vtb_buffer + at,
285                                  len*sizeof(uint16_t)); 
286                 } else {
287                         sc_vtb_bcopy(vtb->vtb_buffer + at + count,
288                               vtb->vtb_buffer + at,
289                               len*sizeof(uint16_t)); 
290                 }
291         }
292         if (vtb->vtb_type == VTB_FRAMEBUFFER)
293                 fillw_io(attr | c, vtb->vtb_buffer + at + len,
294                          vtb->vtb_size - at - len);
295         else
296                 fillw(attr | c, vtb->vtb_buffer + at + len,
297                       vtb->vtb_size - at - len);
298 }
299
300 void
301 sc_vtb_ins(sc_vtb_t *vtb, int at, int count, int c, int attr)
302 {
303         if (at + count > vtb->vtb_size) {
304                 count = vtb->vtb_size - at;
305         } else {
306                 if (vtb->vtb_type == VTB_FRAMEBUFFER) {
307                         sc_vtb_bcopy(vtb->vtb_buffer + at,
308                                  vtb->vtb_buffer + at + count,
309                                  (vtb->vtb_size - at - count)*sizeof(uint16_t));
310                 } else {
311                         sc_vtb_bcopy(vtb->vtb_buffer + at,
312                               vtb->vtb_buffer + at + count,
313                               (vtb->vtb_size - at - count)*sizeof(uint16_t)); 
314                 }
315         }
316         if (vtb->vtb_type == VTB_FRAMEBUFFER)
317                 fillw_io(attr | c, vtb->vtb_buffer + at, count);
318         else
319                 fillw(attr | c, vtb->vtb_buffer + at, count);
320 }