FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/bt485.c
1 /* $NetBSD: bt485.c,v 1.18 2018/01/24 05:35:58 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 /* This code was derived from and originally located in sys/dev/pci/
31 * NetBSD: tga_bt485.c,v 1.4 1999/03/24 05:51:21 mrg Exp
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: bt485.c,v 1.18 2018/01/24 05:35:58 riastradh Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/buf.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43
44 #include <dev/pci/pcivar.h>
45 #include <dev/ic/bt485reg.h>
46 #include <dev/ic/bt485var.h>
47 #include <dev/ic/ramdac.h>
48
49 #include <dev/wscons/wsconsio.h>
50
51 /*
52 * Functions exported via the RAMDAC configuration table.
53 */
54 void bt485_init(struct ramdac_cookie *);
55 int bt485_set_cmap(struct ramdac_cookie *, struct wsdisplay_cmap *);
56 int bt485_get_cmap(struct ramdac_cookie *, struct wsdisplay_cmap *);
57 int bt485_set_cursor(struct ramdac_cookie *, struct wsdisplay_cursor *);
58 int bt485_get_cursor(struct ramdac_cookie *, struct wsdisplay_cursor *);
59 int bt485_set_curpos(struct ramdac_cookie *, struct wsdisplay_curpos *);
60 int bt485_get_curpos(struct ramdac_cookie *, struct wsdisplay_curpos *);
61 int bt485_get_curmax(struct ramdac_cookie *, struct wsdisplay_curpos *);
62
63 /* XXX const */
64 struct ramdac_funcs bt485_funcsstruct = {
65 "Bt485",
66 bt485_register,
67 bt485_init,
68 bt485_set_cmap,
69 bt485_get_cmap,
70 bt485_set_cursor,
71 bt485_get_cursor,
72 bt485_set_curpos,
73 bt485_get_curpos,
74 bt485_get_curmax,
75 NULL, /* check_curcmap; not needed */
76 NULL, /* set_curcmap; not needed */
77 NULL, /* get_curcmap; not needed */
78 NULL, /* no dot clock to set */
79 };
80
81 /*
82 * Private data.
83 */
84 struct bt485data {
85 void *cookie; /* This is what is passed
86 * around, and is probably
87 * struct tga_devconfig *
88 */
89
90 int (*ramdac_sched_update)(void *, void (*)(void *));
91 void (*ramdac_wr)(void *, u_int, u_int8_t);
92 u_int8_t (*ramdac_rd)(void *, u_int);
93
94 int changed; /* what changed; see below */
95 int curenb; /* cursor enabled */
96 struct wsdisplay_curpos curpos; /* current cursor position */
97 struct wsdisplay_curpos curhot; /* cursor hotspot */
98 char curcmap_r[2]; /* cursor colormap */
99 char curcmap_g[2];
100 char curcmap_b[2];
101 struct wsdisplay_curpos cursize; /* current cursor size */
102 char curimage[512]; /* cursor image data */
103 char curmask[512]; /* cursor mask data */
104 char cmap_r[256]; /* colormap */
105 char cmap_g[256];
106 char cmap_b[256];
107 };
108
109 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
110 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
111 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
112 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
113 #define DATA_ALL_CHANGED 0x0f
114
115 #define CURSOR_MAX_SIZE 64
116
117 /*
118 * Internal functions.
119 */
120
121 void bt485_update(void *);
122 void bt485_update_curpos(struct bt485data *);
123
124 static inline void
125 bt485_wr_i(struct bt485data *data, u_int8_t ireg, u_int8_t val)
126 {
127 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, ireg);
128 data->ramdac_wr(data->cookie, BT485_REG_EXTENDED, val);
129 }
130
131 static inline u_int8_t
132 bt485_rd_i(struct bt485data *data, u_int8_t ireg)
133 {
134 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, ireg);
135 return (data->ramdac_rd(data->cookie, BT485_REG_EXTENDED));
136 }
137
138 /*****************************************************************************/
139
140 /*
141 * Functions exported via the RAMDAC configuration table.
142 */
143
144 struct ramdac_funcs *
145 bt485_funcs(void)
146 {
147 return &bt485_funcsstruct;
148 }
149
150 struct ramdac_cookie *
151 bt485_register(
152 void *v,
153 int (*sched_update)(void *, void (*)(void *)),
154 void (*wr)(void *, u_int, u_int8_t),
155 u_int8_t (*rd)(void *, u_int))
156 {
157 struct bt485data *data;
158 /*
159 * XXX -- comment out of date. rcd.
160 * If we should allocate a new private info struct, do so.
161 * Otherwise, use the one we have (if it's there), or
162 * use the temporary one on the stack.
163 */
164 data = malloc(sizeof *data, M_DEVBUF, M_WAITOK);
165 /* XXX -- if !data */
166 data->cookie = v;
167 data->ramdac_sched_update = sched_update;
168 data->ramdac_wr = wr;
169 data->ramdac_rd = rd;
170 return (struct ramdac_cookie *)data;
171 }
172
173 /*
174 * This function exists solely to provide a means to init
175 * the RAMDAC without first registering. It is useful for
176 * initializing the console early on.
177 */
178 void
179 bt485_cninit(
180 void *v,
181 int (*sched_update)(void *, void (*)(void *)),
182 void (*wr)(void *, u_int, u_int8_t),
183 u_int8_t (*rd)(void *, u_int))
184 {
185 struct bt485data tmp, *data = &tmp;
186 data->cookie = v;
187 data->ramdac_sched_update = sched_update;
188 data->ramdac_wr = wr;
189 data->ramdac_rd = rd;
190 bt485_init((struct ramdac_cookie *)data);
191 }
192
193 void
194 bt485_init(struct ramdac_cookie *rc)
195 {
196 u_int8_t regval;
197 struct bt485data *data = (struct bt485data *)rc;
198 int i;
199
200 /*
201 * Init the BT485 for normal operation.
202 */
203
204 /*
205 * Allow indirect register access. (Actually, this is
206 * already enabled. In fact, if it is _disabled_, for
207 * some reason the monitor appears to lose sync!!! (?!?!)
208 */
209 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_0);
210 regval |= 0x80;
211 /*
212 * Set the RAMDAC to 8 bit resolution, rather than 6 bit
213 * resolution.
214 */
215 regval |= 0x02;
216 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_0, regval);
217
218 /* Set the RAMDAC to 8BPP (no interestion options). */
219 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_1, 0x40);
220
221 /* Disable the cursor (for now) */
222 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_2);
223 regval &= ~0x03;
224 regval |= 0x24;
225 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_2, regval);
226
227 /* Use a 64x64x2 cursor */
228 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3);
229 regval |= 0x04;
230 regval |= 0x08;
231 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval);
232
233 /* Set the Pixel Mask to something useful */
234 data->ramdac_wr(data->cookie, BT485_REG_PIXMASK, 0xff);
235
236 /*
237 * Initialize the RAMDAC info struct to hold all of our
238 * data, and fill it in.
239 */
240 data->changed = DATA_ALL_CHANGED;
241
242 data->curenb = 0; /* cursor disabled */
243 data->curpos.x = data->curpos.y = 0; /* right now at 0,0 */
244 data->curhot.x = data->curhot.y = 0; /* hot spot at 0,0 */
245
246 /* initial cursor colormap: 0 is black, 1 is white */
247 data->curcmap_r[0] = data->curcmap_g[0] = data->curcmap_b[0] = 0;
248 data->curcmap_r[1] = data->curcmap_g[1] = data->curcmap_b[1] = 0xff;
249
250 /* initial cursor data: 64x64 block of white. */
251 data->cursize.x = data->cursize.y = 64;
252 for (i = 0; i < 512; i++)
253 data->curimage[i] = data->curmask[i] = 0xff;
254
255 /* Initial colormap: 0 is black, everything else is white */
256 data->cmap_r[0] = data->cmap_g[0] = data->cmap_b[0] = 0;
257 for (i = 1; i < 256; i++)
258 data->cmap_r[i] = data->cmap_g[i] = data->cmap_b[i] = 255;
259
260 bt485_update((void *)data);
261 }
262
263 int
264 bt485_set_cmap(struct ramdac_cookie *rc, struct wsdisplay_cmap *cmapp)
265 {
266 struct bt485data *data = (struct bt485data *)rc;
267 u_int count, index;
268 uint8_t r[256], g[256], b[256];
269 int s, error;
270
271 if (cmapp->index >= 256 || cmapp->count > 256 - cmapp->index)
272 return (EINVAL);
273
274 index = cmapp->index;
275 count = cmapp->count;
276 error = copyin(cmapp->red, &r[index], count);
277 if (error)
278 return error;
279 error = copyin(cmapp->green, &g[index], count);
280 if (error)
281 return error;
282 error = copyin(cmapp->blue, &b[index], count);
283 if (error)
284 return error;
285 s = spltty();
286 memcpy(&data->cmap_r[index], &r[index], count);
287 memcpy(&data->cmap_g[index], &g[index], count);
288 memcpy(&data->cmap_b[index], &b[index], count);
289 data->changed |= DATA_CMAP_CHANGED;
290 data->ramdac_sched_update(data->cookie, bt485_update);
291 splx(s);
292 return (0);
293 }
294
295 int
296 bt485_get_cmap(struct ramdac_cookie *rc, struct wsdisplay_cmap *cmapp)
297 {
298 struct bt485data *data = (struct bt485data *)rc;
299 u_int count, index;
300 int error;
301
302 if (cmapp->index >= 256 || cmapp->count > 256 - cmapp->index )
303 return (EINVAL);
304
305 count = cmapp->count;
306 index = cmapp->index;
307 error = copyout(&data->cmap_r[index], cmapp->red, count);
308 if (error)
309 return (error);
310 error = copyout(&data->cmap_g[index], cmapp->green, count);
311 if (error)
312 return (error);
313 error = copyout(&data->cmap_b[index], cmapp->blue, count);
314 return (error);
315 }
316
317 int
318 bt485_set_cursor(struct ramdac_cookie *rc, struct wsdisplay_cursor *cursorp)
319 {
320 struct bt485data *data = (struct bt485data *)rc;
321 u_int count = 0, icount = 0, index = 0, v;
322 char r[2], g[2], b[2], image[512], mask[512];
323 int s, error;
324
325 v = cursorp->which;
326
327 /*
328 * For DOCMAP and DOSHAPE, copy in the new data
329 * before we do anything that we can't recover from.
330 */
331 if (v & WSDISPLAY_CURSOR_DOCMAP) {
332 if (cursorp->cmap.index > 2 ||
333 cursorp->cmap.count > 2 - cursorp->cmap.index)
334 return (EINVAL);
335 count = cursorp->cmap.count;
336 index = cursorp->cmap.index;
337 error = copyin(cursorp->cmap.red, &r[index], count);
338 if (error)
339 return error;
340 error = copyin(cursorp->cmap.green, &g[index], count);
341 if (error)
342 return error;
343 error = copyin(cursorp->cmap.blue, &b[index], count);
344 if (error)
345 return error;
346 }
347 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
348 if (cursorp->size.x > CURSOR_MAX_SIZE ||
349 cursorp->size.y > CURSOR_MAX_SIZE)
350 return (EINVAL);
351 icount = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y;
352 error = copyin(cursorp->image, image, icount);
353 if (error)
354 return error;
355 error = copyin(cursorp->mask, mask, icount);
356 if (error)
357 return error;
358 }
359
360 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
361 if (v & WSDISPLAY_CURSOR_DOPOS)
362 data->curpos = cursorp->pos;
363 if (v & WSDISPLAY_CURSOR_DOCUR)
364 data->curhot = cursorp->hot;
365 bt485_update_curpos(data);
366 }
367
368 s = spltty();
369
370 /* Data is all available; perform the requested operations. */
371 if (v & WSDISPLAY_CURSOR_DOCUR) {
372 data->curenb = cursorp->enable;
373 data->changed |= DATA_ENB_CHANGED;
374 }
375 if (v & WSDISPLAY_CURSOR_DOCMAP) {
376 memcpy(&data->curcmap_r[index], &r[index], count);
377 memcpy(&data->curcmap_g[index], &g[index], count);
378 memcpy(&data->curcmap_b[index], &b[index], count);
379 data->changed |= DATA_CURCMAP_CHANGED;
380 }
381 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
382 data->cursize = cursorp->size;
383 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y;
384 memset(data->curimage, 0, sizeof data->curimage);
385 memset(data->curmask, 0, sizeof data->curmask);
386 memcpy(data->curimage, image, icount);
387 memcpy(data->curmask, mask, icount);
388 data->changed |= DATA_CURSHAPE_CHANGED;
389 }
390
391 if (data->changed)
392 data->ramdac_sched_update(data->cookie, bt485_update);
393 splx(s);
394
395 return (0);
396 }
397
398 int
399 bt485_get_cursor(struct ramdac_cookie *rc, struct wsdisplay_cursor *cursorp)
400 {
401 struct bt485data *data = (struct bt485data *)rc;
402 int error, count;
403
404 /* we return everything they want */
405 cursorp->which = WSDISPLAY_CURSOR_DOALL;
406
407 cursorp->enable = data->curenb; /* DOCUR */
408 cursorp->pos = data->curpos; /* DOPOS */
409 cursorp->hot = data->curhot; /* DOHOT */
410
411 cursorp->cmap.index = 0; /* DOCMAP */
412 cursorp->cmap.count = 2;
413 if (cursorp->cmap.red != NULL) {
414 error = copyout(data->curcmap_r, cursorp->cmap.red, 2);
415 if (error)
416 return (error);
417 }
418 if (cursorp->cmap.green != NULL) {
419 error = copyout(data->curcmap_g, cursorp->cmap.green, 2);
420 if (error)
421 return (error);
422 }
423 if (cursorp->cmap.blue != NULL) {
424 error = copyout(data->curcmap_b, cursorp->cmap.blue, 2);
425 if (error)
426 return (error);
427 }
428
429 cursorp->size = data->cursize; /* DOSHAPE */
430 if (cursorp->image != NULL) {
431 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y;
432 error = copyout(data->curimage, cursorp->image, count);
433 if (error)
434 return (error);
435 error = copyout(data->curmask, cursorp->mask, count);
436 if (error)
437 return (error);
438 }
439
440 return (0);
441 }
442
443 int
444 bt485_set_curpos(struct ramdac_cookie *rc, struct wsdisplay_curpos *curposp)
445 {
446 struct bt485data *data = (struct bt485data *)rc;
447
448 data->curpos = *curposp;
449 bt485_update_curpos(data);
450
451 return (0);
452 }
453
454 int
455 bt485_get_curpos(struct ramdac_cookie *rc, struct wsdisplay_curpos *curposp)
456 {
457 struct bt485data *data = (struct bt485data *)rc;
458
459 *curposp = data->curpos;
460 return (0);
461 }
462
463 int
464 bt485_get_curmax(struct ramdac_cookie *rc, struct wsdisplay_curpos *curposp)
465 {
466
467 curposp->x = curposp->y = CURSOR_MAX_SIZE;
468 return (0);
469 }
470
471 /*****************************************************************************/
472
473 /*
474 * Internal functions.
475 */
476
477 void
478 bt485_update(void *vp)
479 {
480 struct bt485data *data = vp;
481 u_int8_t regval;
482 int count, i, v;
483
484 v = data->changed;
485 data->changed = 0;
486
487 if (v & DATA_ENB_CHANGED) {
488 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_2);
489 if (data->curenb)
490 regval |= 0x01;
491 else
492 regval &= ~0x03;
493 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_2, regval);
494 }
495
496 if (v & DATA_CURCMAP_CHANGED) {
497 /* addr[9:0] assumed to be 0 */
498 /* set addr[7:0] to 1 */
499 data->ramdac_wr(data->cookie, BT485_REG_COC_WRADDR, 0x01);
500
501 /* spit out the cursor data */
502 for (i = 0; i < 2; i++) {
503 data->ramdac_wr(data->cookie, BT485_REG_COCDATA,
504 data->curcmap_r[i]);
505 data->ramdac_wr(data->cookie, BT485_REG_COCDATA,
506 data->curcmap_g[i]);
507 data->ramdac_wr(data->cookie, BT485_REG_COCDATA,
508 data->curcmap_b[i]);
509 }
510 }
511
512 if (v & DATA_CURSHAPE_CHANGED) {
513 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y;
514
515 /*
516 * Write the cursor image data:
517 * set addr[9:8] to 0,
518 * set addr[7:0] to 0,
519 * spit it all out.
520 */
521 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3);
522 regval &= ~0x03;
523 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval);
524 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0);
525 for (i = 0; i < count; i++)
526 data->ramdac_wr(data->cookie, BT485_REG_CURSOR_RAM,
527 data->curimage[i]);
528
529 /*
530 * Write the cursor mask data:
531 * set addr[9:8] to 2,
532 * set addr[7:0] to 0,
533 * spit it all out.
534 */
535 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3);
536 regval &= ~0x03; regval |= 0x02;
537 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval);
538 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0);
539 for (i = 0; i < count; i++)
540 data->ramdac_wr(data->cookie, BT485_REG_CURSOR_RAM,
541 data->curmask[i]);
542
543 /* set addr[9:0] back to 0 */
544 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3);
545 regval &= ~0x03;
546 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval);
547 }
548
549 if (v & DATA_CMAP_CHANGED) {
550 /* addr[9:0] assumed to be 0 */
551 /* set addr[7:0] to 0 */
552 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0x00);
553
554 /* spit out the cursor data */
555 for (i = 0; i < 256; i++) {
556 data->ramdac_wr(data->cookie, BT485_REG_PALETTE,
557 data->cmap_r[i]);
558 data->ramdac_wr(data->cookie, BT485_REG_PALETTE,
559 data->cmap_g[i]);
560 data->ramdac_wr(data->cookie, BT485_REG_PALETTE,
561 data->cmap_b[i]);
562 }
563 }
564 }
565
566 void
567 bt485_update_curpos(struct bt485data *data)
568 {
569 void *cookie = data->cookie;
570 int s, x, y;
571
572 s = spltty();
573
574 x = data->curpos.x + CURSOR_MAX_SIZE - data->curhot.x;
575 y = data->curpos.y + CURSOR_MAX_SIZE - data->curhot.y;
576 data->ramdac_wr(cookie, BT485_REG_CURSOR_X_LOW, x & 0xff);
577 data->ramdac_wr(cookie, BT485_REG_CURSOR_X_HIGH, (x >> 8) & 0x0f);
578 data->ramdac_wr(cookie, BT485_REG_CURSOR_Y_LOW, y & 0xff);
579 data->ramdac_wr(cookie, BT485_REG_CURSOR_Y_HIGH, (y >> 8) & 0x0f);
580
581 splx(s);
582 }
Cache object: 9c2bf88d18bfcb1fd4576a2384a71c3d
|