NetBSD/sys/arch/pmax/dev/fb_usrreq.c

356 lines
6.7 KiB
C

/* $NetBSD: fb_usrreq.c,v 1.28 2003/07/15 02:54:38 lukem Exp $ */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fb_usrreq.c,v 1.28 2003/07/15 02:54:38 lukem Exp $");
#include <sys/conf.h>
dev_type_open(fbopen);
dev_type_close(fbclose);
dev_type_ioctl(fbioctl);
dev_type_poll(fbpoll);
dev_type_mmap(fbmmap);
dev_type_kqfilter(fbkqfilter);
const struct cdevsw fb_cdevsw = {
fbopen, fbclose, noread, nowrite, fbioctl,
nostop, notty, fbpoll, fbmmap, fbkqfilter,
};
/*ARGSUSED*/
int
fbopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
struct fbinfo *fi;
if (minor(dev) >= fbndevs)
return(ENXIO);
fi = fbdevs[minor(dev)];
if (fi->fi_open)
return (EBUSY);
/* Save colormap for 8bpp devices */
if (fi->fi_type.fb_depth == 8) {
fi->fi_savedcmap = malloc(768, M_DEVBUF, M_NOWAIT);
if (fi->fi_savedcmap == NULL) {
printf("fbopen: no memory for cmap\n");
return (ENOMEM);
}
fi->fi_driver->fbd_getcmap(fi, fi->fi_savedcmap, 0, 256);
}
fi->fi_open = 1;
(*fi->fi_driver->fbd_initcmap)(fi);
/*
* Set up event queue for later
*/
pmEventQueueInit(&fi->fi_fbu->scrInfo.qe);
genConfigMouse();
return (0);
}
/*ARGSUSED*/
int
fbclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
struct fbinfo *fi;
struct pmax_fbtty *fbtty;
if (minor(dev) >= fbndevs)
return(EBADF);
fi = fbdevs[minor(dev)];
if (!fi->fi_open)
return (EBADF);
fbtty = fi->fi_glasstty;
fi->fi_open = 0;
if (fi->fi_type.fb_depth == 8) {
fi->fi_driver->fbd_putcmap(fi, fi->fi_savedcmap, 0, 256);
free(fi->fi_savedcmap, M_DEVBUF);
} else
fi->fi_driver->fbd_initcmap(fi);
genDeconfigMouse();
/*
* Reset the keyboard - we don't know what the X server (or whatever
* was using the framebuffer) did to the keyboard. The X11R6 server
* changes the keyboard state, and doesn't reset it.
*/
lk_reset(fbtty->kbddev, fbtty->KBDPutc);
memset(fi->fi_pixels, 0, fi->fi_pixelsize);
(*fi->fi_driver->fbd_poscursor)
(fi, fbtty->col * 8, fbtty->row * 15);
return (0);
}
/*ARGSUSED*/
int
fbioctl(dev, cmd, data, flag, p)
dev_t dev;
u_long cmd;
caddr_t data;
struct proc *p;
{
struct fbinfo *fi;
struct pmax_fbtty *fbtty;
char cmap_buf [3];
if (minor(dev) >= fbndevs)
return(EBADF);
fi = fbdevs[minor(dev)];
fbtty = fi->fi_glasstty;
switch (cmd) {
/*
* Ultrix-compatible, pm/qvss-style ioctls(). Mostly
* so that X consortium Xservers work.
*/
case QIOCGINFO:
return (fbmmap_fb(fi, dev, data, p));
case QIOCPMSTATE:
/*
* Set mouse state.
*/
fi->fi_fbu->scrInfo.mouse = *(pmCursor *)data;
(*fi->fi_driver->fbd_poscursor)
(fi, fi->fi_fbu->scrInfo.mouse.x,
fi->fi_fbu->scrInfo.mouse.y);
break;
case QIOCINIT:
/*
* Initialize the screen.
*/
break;
case QIOCKPCMD:
{
pmKpCmd *kpCmdPtr;
unsigned char *cp;
kpCmdPtr = (pmKpCmd *)data;
if (kpCmdPtr->nbytes == 0)
kpCmdPtr->cmd |= 0x80;
if (!fi->fi_open)
kpCmdPtr->cmd |= 1;
(*fbtty->KBDPutc)(fbtty->kbddev, (int)kpCmdPtr->cmd);
cp = &kpCmdPtr->par[0];
for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
if (kpCmdPtr->nbytes == 1)
*cp |= 0x80;
(*fbtty->KBDPutc)(fbtty->kbddev, (int)*cp);
}
break;
}
case QIOCADDR:
*(PM_Info **)data = &fi->fi_fbu->scrInfo;
break;
case QIOWCURSOR:
(*fi->fi_driver->fbd_loadcursor)
(fi, (unsigned short *)data);
break;
case QIOWCURSORCOLOR:
(*fi->fi_driver->fbd_cursorcolor)(fi, (unsigned int *)data);
break;
case QIOSETCMAP:
cmap_buf[0] = ((ColorMap *)data)->Entry.red;
cmap_buf[1] = ((ColorMap *)data)->Entry.green;
cmap_buf[2] = ((ColorMap *)data)->Entry.blue;
(*fi->fi_driver->fbd_putcmap)
(fi,
cmap_buf,
((ColorMap *)data)->index, 1);
break;
case QIOKERNLOOP:
genConfigMouse();
break;
case QIOKERNUNLOOP:
genDeconfigMouse();
break;
case QIOVIDEOON:
(*fi->fi_driver->fbd_unblank) (fi);
break;
case QIOVIDEOOFF:
(*fi->fi_driver->fbd_blank) (fi);
break;
/*
* Sun-style ioctls, mostly so that screenblank(1) and other
* ``native'' NetBSD applications work.
*/
case FBIOGTYPE:
*(struct fbtype *)data = fi->fi_type;
break;
case FBIOGETCMAP:
return ((*(fi->fi_driver -> fbd_getcmap))
(fi, data, 0, fi->fi_type.fb_cmsize));
case FBIOPUTCMAP:
return ((*(fi->fi_driver -> fbd_putcmap))
(fi, data, 0, fi->fi_type.fb_cmsize));
break;
case FBIOGVIDEO:
*(int *)data = (fi->fi_blanked) ? FBVIDEO_OFF: FBVIDEO_ON;
break;
case FBIOSVIDEO:
if (*(int *)data == FBVIDEO_OFF)
return (*(fi->fi_driver->fbd_blank)) (fi);
else
return (*(fi->fi_driver->fbd_unblank)) (fi);
default:
printf("fb%d: Unknown ioctl command %lx\n", minor(dev), cmd);
return (EINVAL);
}
return (0);
}
/*
* Poll on Digital-OS-compatible in-kernel input-event ringbuffer.
*/
int
fbpoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
struct fbinfo *fi;
int revents = 0;
if (minor(dev) >= fbndevs)
return(EBADF);
fi = fbdevs[minor(dev)];
if (events & (POLLIN | POLLRDNORM)) {
if (fi->fi_fbu->scrInfo.qe.eHead !=
fi->fi_fbu->scrInfo.qe.eTail)
revents |= (events & (POLLIN|POLLRDNORM));
else
selrecord(p, &fi->fi_selp);
}
/* XXX mice are not writable, what to do for poll on write? */
#ifdef notdef
if (events & (POLLOUT | POLLWRNORM))
revents |= events & (POLLOUT | POLLWRNORM);
#endif
return (revents);
}
static void
filt_fbrdetach(struct knote *kn)
{
struct fbinfo *fi = kn->kn_hook;
int s;
s = spltty();
SLIST_REMOVE(&fi->fi_selp.sel_klist, kn, knote, kn_selnext);
splx(s);
}
static int
filt_fbread(struct knote *kn, long hint)
{
struct fbinfo *fi = kn->kn_hook;
if (fi->fi_fbu->scrInfo.qe.eHead == fi->fi_fbu->scrInfo.qe.eTail)
return (0);
kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
return (1);
}
static const struct filterops fbread_filtops =
{ 1, NULL, filt_fbrdetach, filt_fbread };
int
fbkqfilter(dev_t dev, struct knote *kn)
{
struct fbinfo *fi = fbdevs[minor(dev)];
struct klist *klist;
int s;
switch (kn->kn_filter) {
case EVFILT_READ:
klist = &fi->fi_selp.sel_klist;
kn->kn_fop = &fbread_filtops;
break;
default:
return (1);
}
kn->kn_hook = fi;
s = spltty();
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
splx(s);
return (0);
}
/*
* Return the physical page number that corresponds to byte offset 'off'.
*/
/*ARGSUSED*/
paddr_t
fbmmap(dev, off, prot)
dev_t dev;
off_t off;
int prot;
{
struct fbinfo *fi;
int len;
if (off < 0)
return (-1);
if (minor(dev) >= fbndevs)
return(-1);
fi = fbdevs[minor(dev)];
len = mips_round_page(((vaddr_t)fi->fi_fbu & PGOFSET)
+ sizeof(*fi->fi_fbu));
if (off < len)
return mips_btop(MIPS_KSEG0_TO_PHYS(fi->fi_fbu) + off);
off -= len;
if (off >= fi->fi_type.fb_size)
return (-1);
return mips_btop(MIPS_KSEG1_TO_PHYS(fi->fi_pixels) + off);
}