fbd.c revision 278846
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: head/sys/dev/fb/fbd.c 278846 2015-02-16 11:49:48Z hselasky $
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: head/sys/dev/fb/fbd.c 278846 2015-02-16 11:49:48Z hselasky $");
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
54257438Sray#include "fb_if.h"
55257438Sray
56256905SrayLIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
57256905Sray    LIST_HEAD_INITIALIZER(fb_list_head);
58256905Sraystruct fb_list_entry {
59256905Sray	struct fb_info	*fb_info;
60256905Sray	struct cdev	*fb_si;
61256905Sray	LIST_ENTRY(fb_list_entry) fb_list;
62256905Sray};
63256905Sray
64257438Sraystruct fbd_softc {
65257438Sray	device_t	sc_dev;
66257438Sray	struct fb_info	*sc_info;
67257438Sray};
68257438Sray
69256905Sraystatic void fbd_evh_init(void *);
70256905Sray/* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
71256905SraySYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
72256905Sray
73256905Sraystatic d_open_t		fb_open;
74256905Sraystatic d_close_t	fb_close;
75256905Sraystatic d_read_t		fb_read;
76256905Sraystatic d_write_t	fb_write;
77256905Sraystatic d_ioctl_t	fb_ioctl;
78256905Sraystatic d_mmap_t		fb_mmap;
79256905Sray
80256905Sraystatic struct cdevsw fb_cdevsw = {
81256905Sray	.d_version =	D_VERSION,
82256905Sray	.d_flags =	D_NEEDGIANT,
83256905Sray	.d_open =	fb_open,
84256905Sray	.d_close =	fb_close,
85256905Sray	.d_read =	fb_read,
86256905Sray	.d_write =	fb_write,
87256905Sray	.d_ioctl =	fb_ioctl,
88256905Sray	.d_mmap =	fb_mmap,
89256905Sray	.d_name =	"fb",
90256905Sray};
91256905Sray
92256905Sraystatic int framebuffer_dev_unit = 0;
93256905Sray
94256905Sraystatic int
95256905Srayfb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
96256905Sray{
97256905Sray
98256905Sray	return (0);
99256905Sray}
100256905Sray
101256905Sraystatic int
102256905Srayfb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
103256905Sray{
104256905Sray
105256905Sray	return (0);
106256905Sray}
107256905Sray
108256905Sraystatic int
109256905Srayfb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
110256905Sray    struct thread *td)
111256905Sray{
112258491Sray	struct fb_info *info;
113258491Sray	int error;
114256905Sray
115258491Sray	error = 0;
116258491Sray	info = dev->si_drv1;
117258491Sray
118258491Sray	switch (cmd) {
119258491Sray	case FBIOGTYPE:
120258491Sray		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
121258491Sray		break;
122258491Sray
123258491Sray	case FBIO_GETWINORG:	/* get frame buffer window origin */
124258491Sray		*(u_int *)data = 0;
125258491Sray		break;
126258491Sray
127258491Sray	case FBIO_GETDISPSTART:	/* get display start address */
128258491Sray		((video_display_start_t *)data)->x = 0;
129258491Sray		((video_display_start_t *)data)->y = 0;
130258491Sray		break;
131258491Sray
132258491Sray	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
133258491Sray		*(u_int *)data = info->fb_stride;
134258491Sray		break;
135258491Sray
136258491Sray	case FBIO_BLANK:	/* blank display */
137278846Shselasky		if (info->setblankmode != NULL)
138278846Shselasky			error = info->setblankmode(info->fb_priv, *(int *)data);
139258491Sray		break;
140258491Sray
141258491Sray	default:
142258491Sray		error = ENOIOCTL;
143258491Sray		break;
144258491Sray	}
145258491Sray	return (error);
146256905Sray}
147256905Sray
148256905Sraystatic int
149256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag)
150256905Sray{
151256905Sray
152256905Sray	return (0); /* XXX nothing to read, yet */
153256905Sray}
154256905Sray
155256905Sraystatic int
156256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag)
157256905Sray{
158256905Sray
159256905Sray	return (0); /* XXX nothing written */
160256905Sray}
161256905Sray
162256905Sraystatic int
163256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
164256905Sray    vm_memattr_t *memattr)
165256905Sray{
166256905Sray	struct fb_info *info;
167256905Sray
168256905Sray	info = dev->si_drv1;
169269620Snwhitehorn
170269620Snwhitehorn	if ((info->fb_flags & FB_FLAG_NOMMAP) || info->fb_pbase == 0)
171269620Snwhitehorn		return (ENODEV);
172269620Snwhitehorn
173256905Sray	if (offset < info->fb_size) {
174256905Sray		*paddr = info->fb_pbase + offset;
175256905Sray		return (0);
176256905Sray	}
177256905Sray	return (EINVAL);
178256905Sray}
179256905Sray
180256905Sraystatic int
181256905Srayfb_init(struct fb_list_entry *entry, int unit)
182256905Sray{
183256905Sray	struct fb_info *info;
184256905Sray
185256905Sray	info = entry->fb_info;
186256905Sray	entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
187256905Sray	    0600, "fb%d", unit);
188256905Sray	entry->fb_si->si_drv1 = info;
189259777Sray	info->fb_cdev = entry->fb_si;
190256905Sray
191256905Sray	return (0);
192256905Sray}
193256905Sray
194256905Srayint
195256905Srayfbd_list()
196256905Sray{
197256905Sray	struct fb_list_entry *entry;
198256905Sray
199256905Sray	if (LIST_EMPTY(&fb_list_head))
200256905Sray		return (ENOENT);
201256905Sray
202256905Sray	LIST_FOREACH(entry, &fb_list_head, fb_list) {
203256905Sray		printf("FB %s @%p\n", entry->fb_info->fb_name,
204256905Sray		    (void *)entry->fb_info->fb_pbase);
205256905Sray	}
206256905Sray
207256905Sray	return (0);
208256905Sray}
209256905Sray
210256905Sraystatic struct fb_list_entry *
211256905Srayfbd_find(struct fb_info* info)
212256905Sray{
213256905Sray	struct fb_list_entry *entry, *tmp;
214256905Sray
215256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
216256905Sray		if (entry->fb_info == info) {
217256905Sray			return (entry);
218256905Sray		}
219256905Sray	}
220256905Sray
221256905Sray	return (NULL);
222256905Sray}
223256905Sray
224256905Srayint
225256905Srayfbd_register(struct fb_info* info)
226256905Sray{
227256905Sray	struct fb_list_entry *entry;
228256905Sray	int err, first;
229256905Sray
230256905Sray	first = 0;
231256905Sray	if (LIST_EMPTY(&fb_list_head))
232256905Sray		first++;
233256905Sray
234256905Sray	entry = fbd_find(info);
235256905Sray	if (entry != NULL) {
236256905Sray		/* XXX Update framebuffer params */
237256905Sray		return (0);
238256905Sray	}
239256905Sray
240256905Sray	entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
241256905Sray	entry->fb_info = info;
242256905Sray
243256905Sray	LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
244256905Sray
245256905Sray	err = fb_init(entry, framebuffer_dev_unit++);
246256905Sray	if (err)
247256905Sray		return (err);
248256905Sray
249269620Snwhitehorn	if (first) {
250269779Sdumbbell		err = vt_fb_attach(info);
251269779Sdumbbell		if (err)
252269779Sdumbbell			return (err);
253269620Snwhitehorn	}
254256905Sray
255256905Sray	return (0);
256256905Sray}
257256905Sray
258256905Srayint
259256905Srayfbd_unregister(struct fb_info* info)
260256905Sray{
261256905Sray	struct fb_list_entry *entry, *tmp;
262256905Sray
263256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
264256905Sray		if (entry->fb_info == info) {
265256905Sray			LIST_REMOVE(entry, fb_list);
266256905Sray			free(entry, M_DEVBUF);
267256905Sray			return (0);
268256905Sray		}
269256905Sray	}
270256905Sray
271256905Sray	return (ENOENT);
272256905Sray}
273256905Sray
274256905Sraystatic void
275256905Srayregister_fb_wrap(void *arg, void *ptr)
276256905Sray{
277256905Sray
278256905Sray	fbd_register((struct fb_info *)ptr);
279256905Sray}
280256905Sray
281256905Sraystatic void
282256905Srayunregister_fb_wrap(void *arg, void *ptr)
283256905Sray{
284256905Sray
285256905Sray	fbd_unregister((struct fb_info *)ptr);
286256905Sray}
287256905Sray
288256905Sraystatic void
289256905Srayfbd_evh_init(void *ctx)
290256905Sray{
291256905Sray
292256905Sray	EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
293256905Sray	    EVENTHANDLER_PRI_ANY);
294256905Sray	EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
295256905Sray	    EVENTHANDLER_PRI_ANY);
296256905Sray}
297257438Sray
298257438Sray/* Newbus methods. */
299257438Sraystatic int
300257438Srayfbd_probe(device_t dev)
301257438Sray{
302257438Sray
303257438Sray	return (BUS_PROBE_NOWILDCARD);
304257438Sray}
305257438Sray
306257438Sraystatic int
307257438Srayfbd_attach(device_t dev)
308257438Sray{
309257438Sray	struct fbd_softc *sc;
310257438Sray	int err;
311257438Sray
312257438Sray	sc = device_get_softc(dev);
313257438Sray
314257438Sray	sc->sc_dev = dev;
315257438Sray	sc->sc_info = FB_GETINFO(device_get_parent(dev));
316257546Sray	if (sc->sc_info == NULL)
317257546Sray		return (ENXIO);
318257438Sray	err = fbd_register(sc->sc_info);
319257438Sray
320257438Sray	return (err);
321257438Sray}
322257438Sray
323257438Sraystatic int
324257438Srayfbd_detach(device_t dev)
325257438Sray{
326257438Sray	struct fbd_softc *sc;
327257438Sray	int err;
328257438Sray
329257438Sray	sc = device_get_softc(dev);
330257438Sray
331257438Sray	err = fbd_unregister(sc->sc_info);
332257438Sray
333257438Sray	return (err);
334257438Sray}
335257438Sray
336257438Sraystatic device_method_t fbd_methods[] = {
337257438Sray	/* Device interface */
338257438Sray	DEVMETHOD(device_probe,		fbd_probe),
339257438Sray	DEVMETHOD(device_attach,	fbd_attach),
340257438Sray	DEVMETHOD(device_detach,	fbd_detach),
341257438Sray
342257438Sray	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
343257438Sray
344257438Sray	{ 0, 0 }
345257438Sray};
346257438Sray
347257438Sraydriver_t fbd_driver = {
348257438Sray	"fbd",
349257438Sray	fbd_methods,
350257438Sray	sizeof(struct fbd_softc)
351257438Sray};
352257438Sray
353257438Sraydevclass_t	fbd_devclass;
354257438Sray
355257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
356257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
357257438SrayMODULE_VERSION(fbd, 1);
358257438Sray
359