1256905Sray/*-
2256905Sray * Copyright (c) 2013 The FreeBSD Foundation
3256905Sray * All rights reserved.
4256905Sray *
5256905Sray * This software was developed by Aleksandr Rybalko under sponsorship from the
6256905Sray * FreeBSD Foundation.
7256905Sray *
8256905Sray * Redistribution and use in source and binary forms, with or without
9256905Sray * modification, are permitted provided that the following conditions
10256905Sray * are met:
11256905Sray * 1. Redistributions of source code must retain the above copyright
12256905Sray *    notice, this list of conditions and the following disclaimer.
13256905Sray * 2. Redistributions in binary form must reproduce the above copyright
14256905Sray *    notice, this list of conditions and the following disclaimer in the
15256905Sray *    documentation and/or other materials provided with the distribution.
16256905Sray *
17256905Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18256905Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19256905Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20256905Sray * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21256905Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22256905Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23256905Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24256905Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25256905Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26256905Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27256905Sray * SUCH DAMAGE.
28256905Sray *
29256905Sray * $FreeBSD: stable/11/sys/dev/fb/fbd.c 307589 2016-10-19 01:35:21Z gonzo $
30256905Sray */
31256905Sray
32256905Sray/* Generic framebuffer */
33256905Sray/* TODO unlink from VT(9) */
34256905Sray/* TODO done normal /dev/fb methods */
35256905Sray
36256905Sray#include <sys/cdefs.h>
37256905Sray__FBSDID("$FreeBSD: stable/11/sys/dev/fb/fbd.c 307589 2016-10-19 01:35:21Z gonzo $");
38256905Sray
39256905Sray#include <sys/param.h>
40256905Sray#include <sys/systm.h>
41257438Sray#include <sys/bus.h>
42256905Sray#include <sys/conf.h>
43256905Sray#include <sys/kernel.h>
44256905Sray#include <sys/malloc.h>
45257438Sray#include <sys/module.h>
46256905Sray#include <sys/queue.h>
47256905Sray#include <sys/fbio.h>
48257438Sray
49257438Sray#include <machine/bus.h>
50257438Sray
51257727Sray#include <dev/vt/vt.h>
52256905Sray#include <dev/vt/hw/fb/vt_fb.h>
53256905Sray
54279752Shselasky#include <vm/vm.h>
55279752Shselasky#include <vm/pmap.h>
56279752Shselasky
57257438Sray#include "fb_if.h"
58257438Sray
59256905SrayLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
60256905Sray    LIST_HEAD_INITIALIZER(fb_list_head);
61256905Sraystruct fb_list_entry {
62256905Sray	struct fb_info	*fb_info;
63256905Sray	struct cdev	*fb_si;
64256905Sray	LIST_ENTRY(fb_list_entry) fb_list;
65256905Sray};
66256905Sray
67257438Sraystruct fbd_softc {
68257438Sray	device_t	sc_dev;
69257438Sray	struct fb_info	*sc_info;
70257438Sray};
71257438Sray
72256905Sraystatic void fbd_evh_init(void *);
73256905Sray/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
74256905SraySYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
75256905Sray
76256905Sraystatic d_open_t		fb_open;
77256905Sraystatic d_close_t	fb_close;
78256905Sraystatic d_read_t		fb_read;
79256905Sraystatic d_write_t	fb_write;
80256905Sraystatic d_ioctl_t	fb_ioctl;
81256905Sraystatic d_mmap_t		fb_mmap;
82256905Sray
83256905Sraystatic struct cdevsw fb_cdevsw = {
84256905Sray	.d_version =	D_VERSION,
85256905Sray	.d_flags =	D_NEEDGIANT,
86256905Sray	.d_open =	fb_open,
87256905Sray	.d_close =	fb_close,
88256905Sray	.d_read =	fb_read,
89256905Sray	.d_write =	fb_write,
90256905Sray	.d_ioctl =	fb_ioctl,
91256905Sray	.d_mmap =	fb_mmap,
92256905Sray	.d_name =	"fb",
93256905Sray};
94256905Sray
95256905Sraystatic int framebuffer_dev_unit = 0;
96256905Sray
97256905Sraystatic int
98256905Srayfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
99256905Sray{
100256905Sray
101256905Sray	return (0);
102256905Sray}
103256905Sray
104256905Sraystatic int
105256905Srayfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
106256905Sray{
107256905Sray
108256905Sray	return (0);
109256905Sray}
110256905Sray
111256905Sraystatic int
112256905Srayfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
113256905Sray    struct thread *td)
114256905Sray{
115258491Sray	struct fb_info *info;
116258491Sray	int error;
117256905Sray
118258491Sray	error = 0;
119258491Sray	info = dev->si_drv1;
120258491Sray
121258491Sray	switch (cmd) {
122258491Sray	case FBIOGTYPE:
123258491Sray		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
124258491Sray		break;
125258491Sray
126258491Sray	case FBIO_GETWINORG:	/* get frame buffer window origin */
127258491Sray		*(u_int *)data = 0;
128258491Sray		break;
129258491Sray
130258491Sray	case FBIO_GETDISPSTART:	/* get display start address */
131258491Sray		((video_display_start_t *)data)->x = 0;
132258491Sray		((video_display_start_t *)data)->y = 0;
133258491Sray		break;
134258491Sray
135258491Sray	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
136258491Sray		*(u_int *)data = info->fb_stride;
137258491Sray		break;
138258491Sray
139258491Sray	case FBIO_BLANK:	/* blank display */
140278846Shselasky		if (info->setblankmode != NULL)
141278846Shselasky			error = info->setblankmode(info->fb_priv, *(int *)data);
142258491Sray		break;
143258491Sray
144258491Sray	default:
145258491Sray		error = ENOIOCTL;
146258491Sray		break;
147258491Sray	}
148258491Sray	return (error);
149256905Sray}
150256905Sray
151256905Sraystatic int
152256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag)
153256905Sray{
154256905Sray
155256905Sray	return (0); /* XXX nothing to read, yet */
156256905Sray}
157256905Sray
158256905Sraystatic int
159256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag)
160256905Sray{
161256905Sray
162256905Sray	return (0); /* XXX nothing written */
163256905Sray}
164256905Sray
165256905Sraystatic int
166256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
167256905Sray    vm_memattr_t *memattr)
168256905Sray{
169256905Sray	struct fb_info *info;
170256905Sray
171256905Sray	info = dev->si_drv1;
172269620Snwhitehorn
173279752Shselasky	if (info->fb_flags & FB_FLAG_NOMMAP)
174269620Snwhitehorn		return (ENODEV);
175269620Snwhitehorn
176279752Shselasky	if (offset >= 0 && offset < info->fb_size) {
177279752Shselasky		if (info->fb_pbase == 0)
178279752Shselasky			*paddr = vtophys((uint8_t *)info->fb_vbase + offset);
179279752Shselasky		else
180279752Shselasky			*paddr = info->fb_pbase + offset;
181307589Sgonzo		if (info->fb_flags & FB_FLAG_MEMATTR)
182307589Sgonzo			*memattr = info->fb_memattr;
183256905Sray		return (0);
184256905Sray	}
185256905Sray	return (EINVAL);
186256905Sray}
187256905Sray
188256905Sraystatic int
189256905Srayfb_init(struct fb_list_entry *entry, int unit)
190256905Sray{
191256905Sray	struct fb_info *info;
192256905Sray
193256905Sray	info = entry->fb_info;
194256905Sray	entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
195256905Sray	    0600, "fb%d", unit);
196256905Sray	entry->fb_si->si_drv1 = info;
197259777Sray	info->fb_cdev = entry->fb_si;
198256905Sray
199256905Sray	return (0);
200256905Sray}
201256905Sray
202256905Srayint
203256905Srayfbd_list()
204256905Sray{
205256905Sray	struct fb_list_entry *entry;
206256905Sray
207256905Sray	if (LIST_EMPTY(&fb_list_head))
208256905Sray		return (ENOENT);
209256905Sray
210256905Sray	LIST_FOREACH(entry, &fb_list_head, fb_list) {
211256905Sray		printf("FB %s @%p\n", entry->fb_info->fb_name,
212256905Sray		    (void *)entry->fb_info->fb_pbase);
213256905Sray	}
214256905Sray
215256905Sray	return (0);
216256905Sray}
217256905Sray
218256905Sraystatic struct fb_list_entry *
219256905Srayfbd_find(struct fb_info* info)
220256905Sray{
221256905Sray	struct fb_list_entry *entry, *tmp;
222256905Sray
223256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
224256905Sray		if (entry->fb_info == info) {
225256905Sray			return (entry);
226256905Sray		}
227256905Sray	}
228256905Sray
229256905Sray	return (NULL);
230256905Sray}
231256905Sray
232256905Srayint
233256905Srayfbd_register(struct fb_info* info)
234256905Sray{
235256905Sray	struct fb_list_entry *entry;
236256905Sray	int err, first;
237256905Sray
238256905Sray	first = 0;
239256905Sray	if (LIST_EMPTY(&fb_list_head))
240256905Sray		first++;
241256905Sray
242256905Sray	entry = fbd_find(info);
243256905Sray	if (entry != NULL) {
244256905Sray		/* XXX Update framebuffer params */
245256905Sray		return (0);
246256905Sray	}
247256905Sray
248256905Sray	entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
249256905Sray	entry->fb_info = info;
250256905Sray
251256905Sray	LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
252256905Sray
253256905Sray	err = fb_init(entry, framebuffer_dev_unit++);
254256905Sray	if (err)
255256905Sray		return (err);
256256905Sray
257269620Snwhitehorn	if (first) {
258269779Sdumbbell		err = vt_fb_attach(info);
259269779Sdumbbell		if (err)
260269779Sdumbbell			return (err);
261269620Snwhitehorn	}
262256905Sray
263256905Sray	return (0);
264256905Sray}
265256905Sray
266256905Srayint
267256905Srayfbd_unregister(struct fb_info* info)
268256905Sray{
269256905Sray	struct fb_list_entry *entry, *tmp;
270256905Sray
271256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
272256905Sray		if (entry->fb_info == info) {
273256905Sray			LIST_REMOVE(entry, fb_list);
274279488Sdumbbell			if (LIST_EMPTY(&fb_list_head))
275279488Sdumbbell				vt_fb_detach(info);
276256905Sray			free(entry, M_DEVBUF);
277256905Sray			return (0);
278256905Sray		}
279256905Sray	}
280256905Sray
281256905Sray	return (ENOENT);
282256905Sray}
283256905Sray
284256905Sraystatic void
285256905Srayregister_fb_wrap(void *arg, void *ptr)
286256905Sray{
287256905Sray
288256905Sray	fbd_register((struct fb_info *)ptr);
289256905Sray}
290256905Sray
291256905Sraystatic void
292256905Srayunregister_fb_wrap(void *arg, void *ptr)
293256905Sray{
294256905Sray
295256905Sray	fbd_unregister((struct fb_info *)ptr);
296256905Sray}
297256905Sray
298256905Sraystatic void
299256905Srayfbd_evh_init(void *ctx)
300256905Sray{
301256905Sray
302256905Sray	EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
303256905Sray	    EVENTHANDLER_PRI_ANY);
304256905Sray	EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
305256905Sray	    EVENTHANDLER_PRI_ANY);
306256905Sray}
307257438Sray
308257438Sray/* Newbus methods. */
309257438Sraystatic int
310257438Srayfbd_probe(device_t dev)
311257438Sray{
312257438Sray
313257438Sray	return (BUS_PROBE_NOWILDCARD);
314257438Sray}
315257438Sray
316257438Sraystatic int
317257438Srayfbd_attach(device_t dev)
318257438Sray{
319257438Sray	struct fbd_softc *sc;
320257438Sray	int err;
321257438Sray
322257438Sray	sc = device_get_softc(dev);
323257438Sray
324257438Sray	sc->sc_dev = dev;
325257438Sray	sc->sc_info = FB_GETINFO(device_get_parent(dev));
326257546Sray	if (sc->sc_info == NULL)
327257546Sray		return (ENXIO);
328257438Sray	err = fbd_register(sc->sc_info);
329257438Sray
330257438Sray	return (err);
331257438Sray}
332257438Sray
333257438Sraystatic int
334257438Srayfbd_detach(device_t dev)
335257438Sray{
336257438Sray	struct fbd_softc *sc;
337257438Sray	int err;
338257438Sray
339257438Sray	sc = device_get_softc(dev);
340257438Sray
341257438Sray	err = fbd_unregister(sc->sc_info);
342257438Sray
343257438Sray	return (err);
344257438Sray}
345257438Sray
346257438Sraystatic device_method_t fbd_methods[] = {
347257438Sray	/* Device interface */
348257438Sray	DEVMETHOD(device_probe,		fbd_probe),
349257438Sray	DEVMETHOD(device_attach,	fbd_attach),
350257438Sray	DEVMETHOD(device_detach,	fbd_detach),
351257438Sray
352257438Sray	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
353257438Sray
354257438Sray	{ 0, 0 }
355257438Sray};
356257438Sray
357257438Sraydriver_t fbd_driver = {
358257438Sray	"fbd",
359257438Sray	fbd_methods,
360257438Sray	sizeof(struct fbd_softc)
361257438Sray};
362257438Sray
363257438Sraydevclass_t	fbd_devclass;
364257438Sray
365257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
366257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
367279752ShselaskyDRIVER_MODULE(fbd, udl, fbd_driver, fbd_devclass, 0, 0);
368257438SrayMODULE_VERSION(fbd, 1);
369257438Sray
370