sfb.c revision 1.10 1 /* $NetBSD: sfb.c,v 1.10 1999/02/23 06:34:49 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998 Tohru Nishimura. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tohru Nishimura
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34
35 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.10 1999/02/23 06:34:49 nisimura Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt459reg.h>
57 #include <dev/tc/sfbreg.h>
58
59 #include "opt_uvm.h"
60 #if defined(UVM)
61 #include <uvm/uvm_extern.h>
62 #define useracc uvm_useracc
63 #endif
64
65 /* XXX BUS'IFYING XXX */
66
67 #if defined(pmax)
68 #define machine_btop(x) mips_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
70 #endif
71
72 #if defined(__alpha__) || defined(alpha)
73 #define machine_btop(x) alpha_btop(x)
74 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
75 #endif
76
77 /*
78 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
79 * obscure register layout such as 2nd and 3rd Bt459 registers are
80 * adjacent each other in a word, i.e.,
81 * struct bt459triplet {
82 * struct {
83 * u_int8_t u0;
84 * u_int8_t u1;
85 * u_int8_t u2;
86 * unsigned :8;
87 * } bt_lo;
88 * ...
89 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
90 */
91 struct bt459reg {
92 u_int32_t bt_lo;
93 u_int32_t bt_hi;
94 u_int32_t bt_reg;
95 u_int32_t bt_cmap;
96 };
97
98 /* XXX XXX XXX */
99
100 struct fb_devconfig {
101 vaddr_t dc_vaddr; /* memory space virtual base address */
102 paddr_t dc_paddr; /* memory space physical base address */
103 vsize_t dc_size; /* size of slot memory */
104 int dc_wid; /* width of frame buffer */
105 int dc_ht; /* height of frame buffer */
106 int dc_depth; /* depth, bits per pixel */
107 int dc_rowbytes; /* bytes in a FB scan line */
108 vaddr_t dc_videobase; /* base of flat frame buffer */
109 struct raster dc_raster; /* raster description */
110 struct rcons dc_rcons; /* raster blitter control info */
111 int dc_blanked; /* currently has video disabled */
112 };
113
114 struct hwcmap {
115 #define CMAP_SIZE 256 /* 256 R/G/B entries */
116 u_int8_t r[CMAP_SIZE];
117 u_int8_t g[CMAP_SIZE];
118 u_int8_t b[CMAP_SIZE];
119 };
120
121 struct hwcursor {
122 struct wsdisplay_curpos cc_pos;
123 struct wsdisplay_curpos cc_hot;
124 struct wsdisplay_curpos cc_size;
125 #define CURSOR_MAX_SIZE 64
126 u_int8_t cc_color[6];
127 u_int64_t cc_image[64 + 64];
128 };
129
130 struct sfb_softc {
131 struct device sc_dev;
132 struct fb_devconfig *sc_dc; /* device configuration */
133 struct hwcmap sc_cmap; /* software copy of colormap */
134 struct hwcursor sc_cursor; /* software copy of cursor */
135 int sc_curenb; /* cursor sprite enabled */
136 int sc_changed; /* need update of colormap */
137 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
138 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
139 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
140 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
141 #define DATA_ALL_CHANGED 0x0f
142 int nscreens;
143 short magic_x, magic_y; /* HX cursor location offset */
144 #define HX_MAGIC_X 368
145 #define HX_MAGIC_Y 38
146 };
147
148 int sfbmatch __P((struct device *, struct cfdata *, void *));
149 void sfbattach __P((struct device *, struct device *, void *));
150
151 struct cfattach sfb_ca = {
152 sizeof(struct sfb_softc), sfbmatch, sfbattach,
153 };
154
155 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
156 struct fb_devconfig sfb_console_dc;
157 tc_addr_t sfb_consaddr;
158
159 #ifndef SFB_ROPS
160 struct wsdisplay_emulops sfb_emulops = {
161 rcons_cursor, /* could use hardware cursor; punt */
162 rcons_mapchar,
163 rcons_putchar,
164 rcons_copycols,
165 rcons_erasecols,
166 rcons_copyrows,
167 rcons_eraserows,
168 rcons_alloc_attr
169 };
170 #else
171 void sfb_cursor __P((void *, int, int, int));
172 int sfb_mapchar __P((void *, int, unsigned int *));
173 void sfb_putchar __P((void *, int, int, u_int, long));
174 void sfb_copycols __P((void *, int, int, int, int));
175 void sfb_erasecols __P((void *, int, int, int, long));
176 void sfb_copyrows __P((void *, int, int, int));
177 void sfb_eraserows __P((void *, int, int, long));
178 int sfb_alloc_attr __P((void *, int, int, int, long *));
179 #define rcons_alloc_attr sfb_alloc_attr
180
181 struct wsdisplay_emulops sfb_emulops = {
182 sfb_cursor, /* could use hardware cursor; punt */
183 sfb_mapchar,
184 sfb_putchar,
185 sfb_copycols,
186 sfb_erasecols,
187 sfb_copyrows,
188 sfb_eraserows,
189 sfb_alloc_attr
190 };
191 #endif
192
193 struct wsscreen_descr sfb_stdscreen = {
194 "std", 0, 0,
195 &sfb_emulops,
196 0, 0,
197 0
198 };
199
200 const struct wsscreen_descr *_sfb_scrlist[] = {
201 &sfb_stdscreen,
202 };
203
204 struct wsscreen_list sfb_screenlist = {
205 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
206 };
207
208 int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
209 int sfbmmap __P((void *, off_t, int));
210
211 int sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
212 void **, int *, int *, long *));
213 void sfb_free_screen __P((void *, void *));
214 void sfb_show_screen __P((void *, void *));
215
216 struct wsdisplay_accessops sfb_accessops = {
217 sfbioctl,
218 sfbmmap,
219 sfb_alloc_screen,
220 sfb_free_screen,
221 sfb_show_screen,
222 0 /* load_font */
223 };
224
225 int sfb_cnattach __P((tc_addr_t));
226 int sfbintr __P((void *));
227 void sfbinit __P((struct fb_devconfig *));
228
229 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
230 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
231 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
232 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
233 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
234 static void bt459_set_curpos __P((struct sfb_softc *));
235
236 /* XXX XXX XXX */
237 #define BT459_SELECT(vdac, regno) do { \
238 vdac->bt_lo = (regno) & 0x00ff; \
239 vdac->bt_hi = ((regno)& 0x0f00) >> 8; \
240 tc_wmb(); \
241 } while (0)
242 /* XXX XXX XXX */
243
244 /*
245 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
246 * M M M M I I I I M I M I M I M I
247 * [ before ] [ after ]
248 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
249 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
250 */
251 const static u_int8_t shuffle[256] = {
252 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
253 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
254 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
255 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
256 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
257 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
258 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
259 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
260 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
261 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
262 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
263 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
264 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
265 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
266 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
267 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
268 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
269 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
270 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
271 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
272 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
273 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
274 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
275 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
276 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
277 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
278 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
279 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
280 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
281 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
282 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
283 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
284 };
285
286 int
287 sfbmatch(parent, match, aux)
288 struct device *parent;
289 struct cfdata *match;
290 void *aux;
291 {
292 struct tc_attach_args *ta = aux;
293
294 if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
295 return (0);
296
297 return (1);
298 }
299
300 void
301 sfb_getdevconfig(dense_addr, dc)
302 tc_addr_t dense_addr;
303 struct fb_devconfig *dc;
304 {
305 struct raster *rap;
306 struct rcons *rcp;
307 caddr_t sfbasic;
308 int i, hsetup, vsetup, vbase;
309
310 dc->dc_vaddr = dense_addr;
311 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
312
313 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
314 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
315 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
316 vbase = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
317
318 dc->dc_wid = (hsetup & 0x1ff) << 2;
319 dc->dc_ht = (vsetup & 0x7ff);
320 dc->dc_depth = 8;
321 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
322 dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
323 dc->dc_blanked = 0;
324
325 /* initialize colormap and cursor resource */
326 sfbinit(dc);
327
328 /* clear the screen */
329 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
330 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
331
332 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
333
334 /* initialize the raster */
335 rap = &dc->dc_raster;
336 rap->width = dc->dc_wid;
337 rap->height = dc->dc_ht;
338 rap->depth = dc->dc_depth;
339 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
340 rap->pixels = (u_int32_t *)dc->dc_videobase;
341 rap->data = sfbasic;
342
343 /* initialize the raster console blitter */
344 rcp = &dc->dc_rcons;
345 rcp->rc_sp = rap;
346 rcp->rc_crow = rcp->rc_ccol = -1;
347 rcp->rc_crowp = &rcp->rc_crow;
348 rcp->rc_ccolp = &rcp->rc_ccol;
349 rcons_init(rcp, 34, 80);
350
351 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
352 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
353 }
354
355 void
356 sfbattach(parent, self, aux)
357 struct device *parent, *self;
358 void *aux;
359 {
360 struct sfb_softc *sc = (struct sfb_softc *)self;
361 struct tc_attach_args *ta = aux;
362 struct wsemuldisplaydev_attach_args waa;
363 struct hwcmap *cm;
364 caddr_t sfbasic;
365 int console, i;
366
367 console = (ta->ta_addr == sfb_consaddr);
368 if (console) {
369 sc->sc_dc = &sfb_console_dc;
370 sc->nscreens = 1;
371 }
372 else {
373 sc->sc_dc = (struct fb_devconfig *)
374 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
375 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
376 }
377 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
378 sc->sc_dc->dc_depth);
379
380 cm = &sc->sc_cmap;
381 cm->r[0] = cm->g[0] = cm->b[0] = 0;
382 for (i = 1; i < CMAP_SIZE; i++) {
383 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
384 }
385 sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
386
387 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
388
389 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
390 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
391 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
392
393 waa.console = console;
394 waa.scrdata = &sfb_screenlist;
395 waa.accessops = &sfb_accessops;
396 waa.accesscookie = sc;
397
398 config_found(self, &waa, wsemuldisplaydevprint);
399 }
400
401 int
402 sfbioctl(v, cmd, data, flag, p)
403 void *v;
404 u_long cmd;
405 caddr_t data;
406 int flag;
407 struct proc *p;
408 {
409 struct sfb_softc *sc = v;
410 struct fb_devconfig *dc = sc->sc_dc;
411 int turnoff;
412
413 switch (cmd) {
414 case WSDISPLAYIO_GTYPE:
415 *(u_int *)data = WSDISPLAY_TYPE_SFB;
416 return (0);
417
418 case WSDISPLAYIO_GINFO:
419 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
420 wsd_fbip->height = sc->sc_dc->dc_ht;
421 wsd_fbip->width = sc->sc_dc->dc_wid;
422 wsd_fbip->depth = sc->sc_dc->dc_depth;
423 wsd_fbip->cmsize = CMAP_SIZE;
424 #undef fbt
425 return (0);
426
427 case WSDISPLAYIO_GETCMAP:
428 return get_cmap(sc, (struct wsdisplay_cmap *)data);
429
430 case WSDISPLAYIO_PUTCMAP:
431 return set_cmap(sc, (struct wsdisplay_cmap *)data);
432
433 case WSDISPLAYIO_SVIDEO:
434 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
435 if ((dc->dc_blanked == 0) ^ turnoff) {
436 dc->dc_blanked = turnoff;
437 /* XXX later XXX */
438 }
439 return (0);
440
441 case WSDISPLAYIO_GVIDEO:
442 *(u_int *)data = dc->dc_blanked ?
443 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
444 return (0);
445
446 case WSDISPLAYIO_GCURPOS:
447 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
448 return (0);
449
450 case WSDISPLAYIO_SCURPOS:
451 set_curpos(sc, (struct wsdisplay_curpos *)data);
452 bt459_set_curpos(sc);
453 return (0);
454
455 case WSDISPLAYIO_GCURMAX:
456 ((struct wsdisplay_curpos *)data)->x =
457 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
458 return (0);
459
460 case WSDISPLAYIO_GCURSOR:
461 return get_cursor(sc, (struct wsdisplay_cursor *)data);
462
463 case WSDISPLAYIO_SCURSOR:
464 return set_cursor(sc, (struct wsdisplay_cursor *)data);
465 }
466 return ENOTTY;
467 }
468
469 int
470 sfbmmap(v, offset, prot)
471 void *v;
472 off_t offset;
473 int prot;
474 {
475 struct sfb_softc *sc = v;
476
477 if (offset >= SFB_SIZE || offset < 0)
478 return (-1);
479 return machine_btop(sc->sc_dc->dc_paddr + offset);
480 }
481
482 int
483 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
484 void *v;
485 const struct wsscreen_descr *type;
486 void **cookiep;
487 int *curxp, *curyp;
488 long *attrp;
489 {
490 struct sfb_softc *sc = v;
491 long defattr;
492
493 if (sc->nscreens > 0)
494 return (ENOMEM);
495
496 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
497 *curxp = 0;
498 *curyp = 0;
499 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
500 *attrp = defattr;
501 sc->nscreens++;
502 return (0);
503 }
504
505 void
506 sfb_free_screen(v, cookie)
507 void *v;
508 void *cookie;
509 {
510 struct sfb_softc *sc = v;
511
512 if (sc->sc_dc == &sfb_console_dc)
513 panic("sfb_free_screen: console");
514
515 sc->nscreens--;
516 }
517
518 void
519 sfb_show_screen(v, cookie)
520 void *v;
521 void *cookie;
522 {
523 }
524
525 int
526 sfb_cnattach(addr)
527 tc_addr_t addr;
528 {
529 struct fb_devconfig *dcp = &sfb_console_dc;
530 long defattr;
531
532 sfb_getdevconfig(addr, dcp);
533
534 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
535
536 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
537 0, 0, defattr);
538 sfb_consaddr = addr;
539 return(0);
540 }
541
542 int
543 sfbintr(arg)
544 void *arg;
545 {
546 struct sfb_softc *sc = arg;
547 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
548 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
549 struct bt459reg *vdac;
550 int v;
551
552 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
553 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
554
555 if (sc->sc_changed == 0)
556 return (1);
557
558 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
559 v = sc->sc_changed;
560 sc->sc_changed = 0;
561
562 if (v & DATA_ENB_CHANGED) {
563 BT459_SELECT(vdac, BT459_REG_CCR);
564 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
565 }
566 if (v & DATA_CURCMAP_CHANGED) {
567 u_int8_t *cp = sc->sc_cursor.cc_color;
568
569 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
570 vdac->bt_reg = cp[1]; tc_wmb();
571 vdac->bt_reg = cp[3]; tc_wmb();
572 vdac->bt_reg = cp[5]; tc_wmb();
573
574 vdac->bt_reg = cp[0]; tc_wmb();
575 vdac->bt_reg = cp[2]; tc_wmb();
576 vdac->bt_reg = cp[4]; tc_wmb();
577 }
578 if (v & DATA_CURSHAPE_CHANGED) {
579 u_int8_t *ip, *mp, img, msk;
580 u_int8_t u;
581 int bcnt;
582
583 ip = (u_int8_t *)sc->sc_cursor.cc_image;
584 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
585
586 bcnt = 0;
587 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
588 /* 64 pixel scan line is consisted with 16 byte cursor ram */
589 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
590 /* pad right half 32 pixel when smaller than 33 */
591 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
592 vdac->bt_reg = 0; tc_wmb();
593 vdac->bt_reg = 0; tc_wmb();
594 }
595 else {
596 img = *ip++;
597 msk = *mp++;
598 img &= msk; /* cookie off image */
599 u = (msk & 0x0f) << 4 | (img & 0x0f);
600 vdac->bt_reg = shuffle[u]; tc_wmb();
601 u = (msk & 0xf0) | (img & 0xf0) >> 4;
602 vdac->bt_reg = shuffle[u]; tc_wmb();
603 }
604 bcnt += 2;
605 }
606 /* pad unoccupied scan lines */
607 while (bcnt < CURSOR_MAX_SIZE * 16) {
608 vdac->bt_reg = 0; tc_wmb();
609 vdac->bt_reg = 0; tc_wmb();
610 bcnt += 2;
611 }
612 }
613 if (v & DATA_CMAP_CHANGED) {
614 struct hwcmap *cm = &sc->sc_cmap;
615 int index;
616
617 BT459_SELECT(vdac, 0);
618 for (index = 0; index < CMAP_SIZE; index++) {
619 vdac->bt_cmap = cm->r[index]; tc_wmb();
620 vdac->bt_cmap = cm->g[index]; tc_wmb();
621 vdac->bt_cmap = cm->b[index]; tc_wmb();
622 }
623 }
624 return (1);
625 }
626
627 void
628 sfbinit(dc)
629 struct fb_devconfig *dc;
630 {
631 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
632 struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
633 int i;
634
635 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 0;
636 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
637 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
638 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
639 *(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3;
640
641 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
642
643 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
644 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
645 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
646 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
647 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
648 vdac->bt_reg = 0; /* 205 */ tc_wmb();
649 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
650 vdac->bt_reg = 0; /* 207 */ tc_wmb();
651 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
652 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
653 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
654 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
655
656 BT459_SELECT(vdac, BT459_REG_CCR);
657 vdac->bt_reg = 0x0; tc_wmb();
658 vdac->bt_reg = 0x0; tc_wmb();
659 vdac->bt_reg = 0x0; tc_wmb();
660 vdac->bt_reg = 0x0; tc_wmb();
661 vdac->bt_reg = 0x0; tc_wmb();
662 vdac->bt_reg = 0x0; tc_wmb();
663 vdac->bt_reg = 0x0; tc_wmb();
664 vdac->bt_reg = 0x0; tc_wmb();
665 vdac->bt_reg = 0x0; tc_wmb();
666 vdac->bt_reg = 0x0; tc_wmb();
667 vdac->bt_reg = 0x0; tc_wmb();
668 vdac->bt_reg = 0x0; tc_wmb();
669 vdac->bt_reg = 0x0; tc_wmb();
670
671 /* build sane colormap */
672 BT459_SELECT(vdac, 0);
673 vdac->bt_cmap = 0; tc_wmb();
674 vdac->bt_cmap = 0; tc_wmb();
675 vdac->bt_cmap = 0; tc_wmb();
676 for (i = 1; i < CMAP_SIZE; i++) {
677 vdac->bt_cmap = 0xff; tc_wmb();
678 vdac->bt_cmap = 0xff; tc_wmb();
679 vdac->bt_cmap = 0xff; tc_wmb();
680 }
681
682 /* clear out cursor image */
683 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
684 for (i = 0; i < 1024; i++)
685 vdac->bt_reg = 0xff; tc_wmb();
686
687 /*
688 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
689 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
690 * image color. CCOLOR_1 will be never used.
691 */
692 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
693 vdac->bt_reg = 0xff; tc_wmb();
694 vdac->bt_reg = 0xff; tc_wmb();
695 vdac->bt_reg = 0xff; tc_wmb();
696
697 vdac->bt_reg = 0; tc_wmb();
698 vdac->bt_reg = 0; tc_wmb();
699 vdac->bt_reg = 0; tc_wmb();
700
701 vdac->bt_reg = 0xff; tc_wmb();
702 vdac->bt_reg = 0xff; tc_wmb();
703 vdac->bt_reg = 0xff; tc_wmb();
704 }
705
706 static int
707 get_cmap(sc, p)
708 struct sfb_softc *sc;
709 struct wsdisplay_cmap *p;
710 {
711 u_int index = p->index, count = p->count;
712
713 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
714 return (EINVAL);
715
716 if (!useracc(p->red, count, B_WRITE) ||
717 !useracc(p->green, count, B_WRITE) ||
718 !useracc(p->blue, count, B_WRITE))
719 return (EFAULT);
720
721 copyout(&sc->sc_cmap.r[index], p->red, count);
722 copyout(&sc->sc_cmap.g[index], p->green, count);
723 copyout(&sc->sc_cmap.b[index], p->blue, count);
724
725 return (0);
726 }
727
728 static int
729 set_cmap(sc, p)
730 struct sfb_softc *sc;
731 struct wsdisplay_cmap *p;
732 {
733 u_int index = p->index, count = p->count;
734
735 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
736 return (EINVAL);
737
738 if (!useracc(p->red, count, B_READ) ||
739 !useracc(p->green, count, B_READ) ||
740 !useracc(p->blue, count, B_READ))
741 return (EFAULT);
742
743 copyin(p->red, &sc->sc_cmap.r[index], count);
744 copyin(p->green, &sc->sc_cmap.g[index], count);
745 copyin(p->blue, &sc->sc_cmap.b[index], count);
746
747 sc->sc_changed |= DATA_CMAP_CHANGED;
748
749 return (0);
750 }
751
752
753 static int
754 set_cursor(sc, p)
755 struct sfb_softc *sc;
756 struct wsdisplay_cursor *p;
757 {
758 #define cc (&sc->sc_cursor)
759 int v, index, count, icount;
760
761 v = p->which;
762 if (v & WSDISPLAY_CURSOR_DOCMAP) {
763 index = p->cmap.index;
764 count = p->cmap.count;
765 if (index >= 2 || (index + count) > 2)
766 return (EINVAL);
767 if (!useracc(p->cmap.red, count, B_READ) ||
768 !useracc(p->cmap.green, count, B_READ) ||
769 !useracc(p->cmap.blue, count, B_READ))
770 return (EFAULT);
771 }
772 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
773 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
774 return (EINVAL);
775 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
776 if (!useracc(p->image, count, B_READ) ||
777 !useracc(p->mask, count, B_READ))
778 return (EFAULT);
779 }
780 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
781 if (v & WSDISPLAY_CURSOR_DOCUR)
782 cc->cc_hot = p->hot;
783 if (v & WSDISPLAY_CURSOR_DOPOS)
784 set_curpos(sc, &p->pos);
785 bt459_set_curpos(sc);
786 }
787
788 sc->sc_changed = 0;
789 if (v & WSDISPLAY_CURSOR_DOCUR) {
790 sc->sc_curenb = p->enable;
791 sc->sc_changed |= DATA_ENB_CHANGED;
792 }
793 if (v & WSDISPLAY_CURSOR_DOCMAP) {
794 copyin(p->cmap.red, &cc->cc_color[index], count);
795 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
796 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
797 sc->sc_changed |= DATA_CURCMAP_CHANGED;
798 }
799 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
800 cc->cc_size = p->size;
801 memset(cc->cc_image, 0, sizeof cc->cc_image);
802 copyin(p->image, cc->cc_image, icount);
803 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
804 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
805 }
806
807 return (0);
808 #undef cc
809 }
810
811 static int
812 get_cursor(sc, p)
813 struct sfb_softc *sc;
814 struct wsdisplay_cursor *p;
815 {
816 return (ENOTTY); /* XXX */
817 }
818
819 static void
820 set_curpos(sc, curpos)
821 struct sfb_softc *sc;
822 struct wsdisplay_curpos *curpos;
823 {
824 struct fb_devconfig *dc = sc->sc_dc;
825 int x = curpos->x, y = curpos->y;
826
827 if (y < 0)
828 y = 0;
829 else if (y > dc->dc_ht)
830 y = dc->dc_ht;
831 if (x < 0)
832 x = 0;
833 else if (x > dc->dc_wid)
834 x = dc->dc_wid;
835 sc->sc_cursor.cc_pos.x = x;
836 sc->sc_cursor.cc_pos.y = y;
837 }
838
839 static void
840 bt459_set_curpos(sc)
841 struct sfb_softc *sc;
842 {
843 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
844 struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
845 int x, y, s;
846
847 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
848 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
849 x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
850
851 s = spltty();
852
853 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
854 vdac->bt_reg = x; tc_wmb();
855 vdac->bt_reg = x >> 8; tc_wmb();
856 vdac->bt_reg = y; tc_wmb();
857 vdac->bt_reg = y >> 8; tc_wmb();
858
859 splx(s);
860 }
861
862 #ifdef SFB_ROPS
863
864 #define MODE_SIMPLE 0
865 #define MODE_OPAQUESTIPPLE 1
866 #define MODE_OPAQUELINE 2
867 #define MODE_TRANSPARENTSTIPPLE 5
868 #define MODE_TRANSPARENTLINE 6
869 #define MODE_COPY 7
870
871 #define SFBALIGNMASK 0x7
872 #define SFBSTIPPLEALL1 0xffffffff
873 #define SFBSTIPPLEBITS 32
874 #define SFBSTIPPLEBITMASK 0x1f
875 #define SFBSTIPPLEBYTESDONE 32
876
877 /*
878 * Paint (or unpaint) the cursor.
879 */
880 void
881 sfb_cursor(id, on, row, col)
882 void *id;
883 int on, row, col;
884 {
885 struct rcons *rc = id;
886 int x, y;
887
888 /* turn the cursor off */
889 if (!on) {
890 /* make sure it's on */
891 if ((rc->rc_bits & RC_CURSOR) == 0)
892 return;
893
894 row = *rc->rc_crowp;
895 col = *rc->rc_ccolp;
896 } else {
897 /* unpaint the old copy. */
898 *rc->rc_crowp = row;
899 *rc->rc_ccolp = col;
900 }
901
902 x = col * rc->rc_font->width + rc->rc_xorigin;
903 y = row * rc->rc_font->height + rc->rc_yorigin;
904
905 raster_op(rc->rc_sp, x, y,
906 rc->rc_font->width, rc->rc_font->height,
907 RAS_INVERT,
908 (struct raster *) 0, 0, 0);
909
910 rc->rc_bits ^= RC_CURSOR;
911 }
912
913 /*
914 * Actually write a string to the frame buffer.
915 */
916 int
917 sfb_mapchar(id, uni, index)
918 void *id;
919 int uni;
920 unsigned int *index;
921 {
922 if (uni < 128) {
923 *index = uni;
924 return (5);
925 }
926 *index = ' ';
927 return (0);
928 }
929
930 /*
931 * Actually write a string to the frame buffer.
932 */
933 void
934 sfb_putchar(id, row, col, uc, attr)
935 void *id;
936 int row, col;
937 u_int uc;
938 long attr;
939 {
940 struct rcons *rc = id;
941 int x, y, op;
942 u_char help;
943
944 x = col * rc->rc_font->width + rc->rc_xorigin;
945 y = row * rc->rc_font->height + rc->rc_font_ascent + rc->rc_yorigin;
946
947 op = RAS_SRC;
948 if ((attr != 0) ^ ((rc->rc_bits & RC_INVERT) != 0))
949 op = RAS_NOT(op);
950 help = uc & 0xff;
951 raster_textn(rc->rc_sp, x, y, op, rc->rc_font, &help, 1);
952 }
953
954 /*
955 * Copy columns (characters) in a row (line).
956 */
957 void
958 sfb_copycols(id, row, srccol, dstcol, ncols)
959 void *id;
960 int row, srccol, dstcol, ncols;
961 {
962 struct rcons *rc = id;
963 int y, srcx, dstx, nx;
964
965 y = rc->rc_yorigin + rc->rc_font->height * row;
966 srcx = rc->rc_xorigin + rc->rc_font->width * srccol;
967 dstx = rc->rc_xorigin + rc->rc_font->width * dstcol;
968 nx = rc->rc_font->width * ncols;
969
970 raster_op(rc->rc_sp, dstx, y,
971 nx, rc->rc_font->height, RAS_SRC,
972 rc->rc_sp, srcx, y);
973 }
974
975 /*
976 * Clear columns (characters) in a row (line).
977 */
978 void
979 sfb_erasecols(id, row, startcol, ncols, fillattr)
980 void *id;
981 int row, startcol, ncols;
982 long fillattr;
983 {
984 struct rcons *rc = id;
985 struct raster *rap = rc->rc_sp;
986 caddr_t sfb, p;
987 int scanspan, startx, height, width, align, w, y;
988 u_int32_t lmask, rmask;
989
990 scanspan = rap->linelongs * 4;
991 y = rc->rc_yorigin + rc->rc_font->height * row;
992 startx = rc->rc_xorigin + rc->rc_font->width * startcol;
993 height = rc->rc_font->height;
994 w = rc->rc_font->width * ncols;
995
996 p = (caddr_t)rap->pixels + y * scanspan + startx;
997 align = (long)p & SFBALIGNMASK;
998 p -= align;
999 width = w + align;
1000 lmask = SFBSTIPPLEALL1 << align;
1001 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1002 sfb = rap->data;
1003 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
1004 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1005 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
1006 if (width <= SFBSTIPPLEBITS) {
1007 while (height > 0) {
1008 *(u_int32_t *)(sfb + SFB_ASIC_ADDRESS) = (long)p;
1009 *(u_int32_t *)(sfb + SFB_ASIC_START) = lmask & rmask;
1010 p += scanspan;
1011 height--;
1012 }
1013 }
1014 else {
1015 caddr_t q = p;
1016 while (height > 0) {
1017 *(u_int32_t *)p = lmask;
1018 width -= 2 * SFBSTIPPLEBITS;
1019 while (width > 0) {
1020 p += SFBSTIPPLEBYTESDONE;
1021 *(u_int32_t *)p = SFBSTIPPLEALL1;
1022 width -= SFBSTIPPLEBITS;
1023 }
1024 p += SFBSTIPPLEBYTESDONE;
1025 *(u_int32_t *)p = rmask;
1026
1027 p = (q += scanspan);
1028 width = w + align;
1029 height--;
1030 }
1031 }
1032 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1033 }
1034
1035 /*
1036 * Copy rows (lines).
1037 */
1038 void
1039 sfb_copyrows(id, srcrow, dstrow, nrows)
1040 void *id;
1041 int srcrow, dstrow, nrows;
1042 {
1043 struct rcons *rc = id;
1044 struct raster *rap = rc->rc_sp;
1045 caddr_t sfb, p;
1046 int scanspan, offset, srcy, height, width, align, w;
1047 u_int32_t lmask, rmask;
1048
1049 scanspan = rap->linelongs * 4;
1050 height = rc->rc_font->height * nrows;
1051 offset = (dstrow - srcrow) * scanspan * rc->rc_font->height;
1052 srcy = rc->rc_yorigin + rc->rc_font->height * srcrow;
1053 if (srcrow < dstrow && srcrow + nrows > dstrow) {
1054 scanspan = -scanspan;
1055 srcy += height;
1056 }
1057
1058 p = (caddr_t)(rap->pixels + srcy * rap->linelongs) + rc->rc_xorigin;
1059 align = (long)p & SFBALIGNMASK;
1060 p -= align;
1061 w = rc->rc_font->width * rc->rc_maxcol;
1062 width = w + align;
1063 lmask = SFBSTIPPLEALL1 << align;
1064 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1065 sfb = rap->data;
1066 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_COPY;
1067 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1068 *(u_int32_t *)(sfb + SFB_ASIC_PIXELSHIFT) = 0;
1069 if (width <= SFBSTIPPLEBITS) {
1070 /* never happens */;
1071 }
1072 else {
1073 caddr_t q = p;
1074 while (height > 0) {
1075 *(u_int32_t *)p = lmask;
1076 *(u_int32_t *)(p + offset) = lmask;
1077 width -= 2 * SFBSTIPPLEBITS;
1078 while (width > 0) {
1079 p += SFBSTIPPLEBYTESDONE;
1080 *(u_int32_t *)p = SFBSTIPPLEALL1;
1081 *(u_int32_t *)(p + offset) = SFBSTIPPLEALL1;
1082 width -= SFBSTIPPLEBITS;
1083 }
1084 p += SFBSTIPPLEBYTESDONE;
1085 *(u_int32_t *)p = rmask;
1086 *(u_int32_t *)(p + offset) = rmask;
1087
1088 p = (q += scanspan);
1089 width = w + align;
1090 height--;
1091 }
1092 }
1093 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1094 }
1095
1096 /*
1097 * Erase rows (lines).
1098 */
1099 void
1100 sfb_eraserows(id, startrow, nrows, fillattr)
1101 void *id;
1102 int startrow, nrows;
1103 long fillattr;
1104 {
1105 struct rcons *rc = id;
1106 struct raster *rap = rc->rc_sp;
1107 caddr_t sfb, p;
1108 int scanspan, starty, height, width, align, w;
1109 u_int32_t lmask, rmask;
1110
1111 scanspan = rap->linelongs * 4;
1112 starty = rc->rc_yorigin + rc->rc_font->height * startrow;
1113 height = rc->rc_font->height * nrows;
1114
1115 p = (caddr_t)rap->pixels + starty * scanspan + rc->rc_xorigin;
1116 align = (long)p & SFBALIGNMASK;
1117 p -= align;
1118 w = rc->rc_font->width * rc->rc_maxcol;
1119 width = w + align;
1120 lmask = SFBSTIPPLEALL1 << align;
1121 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1122 sfb = rap->data;
1123 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
1124 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1125 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
1126 if (width <= SFBSTIPPLEBITS) {
1127 /* never happens */;
1128 }
1129 else {
1130 caddr_t q = p;
1131 while (height > 0) {
1132 *(u_int32_t *)p = lmask;
1133 width -= 2 * SFBSTIPPLEBITS;
1134 while (width > 0) {
1135 p += SFBSTIPPLEBYTESDONE;
1136 *(u_int32_t *)p = SFBSTIPPLEALL1;
1137 width -= SFBSTIPPLEBITS;
1138 }
1139 p += SFBSTIPPLEBYTESDONE;
1140 *(u_int32_t *)p = rmask;
1141
1142 p = (q += scanspan);
1143 width = w + align;
1144 height--;
1145 }
1146 }
1147 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1148 }
1149
1150 int
1151 sfb_alloc_attr(id, fg, bg, flags, attrp)
1152 void *id;
1153 int fg, bg, flags;
1154 long *attrp;
1155 {
1156 if (flags & (WSATTR_HILIT | WSATTR_BLINK |
1157 WSATTR_UNDERLINE | WSATTR_WSCOLORS))
1158 return (EINVAL);
1159 if (flags & WSATTR_REVERSE)
1160 *attrp = 1;
1161 else
1162 *attrp = 0;
1163 return (0);
1164 }
1165 #endif
1166