fbd.c revision 269779
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 269779 2014-08-10 14:55:39Z dumbbell $
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 269779 2014-08-10 14:55:39Z dumbbell $");
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 */
137258491Sray		error = 0;	/* TODO */
138258491Sray		break;
139258491Sray
140258491Sray	default:
141258491Sray		error = ENOIOCTL;
142258491Sray		break;
143258491Sray	}
144258491Sray	return (error);
145256905Sray}
146256905Sray
147256905Sraystatic int
148256905Srayfb_read(struct cdev *dev, struct uio *uio, int ioflag)
149256905Sray{
150256905Sray
151256905Sray	return (0); /* XXX nothing to read, yet */
152256905Sray}
153256905Sray
154256905Sraystatic int
155256905Srayfb_write(struct cdev *dev, struct uio *uio, int ioflag)
156256905Sray{
157256905Sray
158256905Sray	return (0); /* XXX nothing written */
159256905Sray}
160256905Sray
161256905Sraystatic int
162256905Srayfb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
163256905Sray    vm_memattr_t *memattr)
164256905Sray{
165256905Sray	struct fb_info *info;
166256905Sray
167256905Sray	info = dev->si_drv1;
168269620Snwhitehorn
169269620Snwhitehorn	if ((info->fb_flags & FB_FLAG_NOMMAP) || info->fb_pbase == 0)
170269620Snwhitehorn		return (ENODEV);
171269620Snwhitehorn
172256905Sray	if (offset < info->fb_size) {
173256905Sray		*paddr = info->fb_pbase + offset;
174256905Sray		return (0);
175256905Sray	}
176256905Sray	return (EINVAL);
177256905Sray}
178256905Sray
179256905Sraystatic int
180256905Srayfb_init(struct fb_list_entry *entry, int unit)
181256905Sray{
182256905Sray	struct fb_info *info;
183256905Sray
184256905Sray	info = entry->fb_info;
185256905Sray	entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
186256905Sray	    0600, "fb%d", unit);
187256905Sray	entry->fb_si->si_drv1 = info;
188259777Sray	info->fb_cdev = entry->fb_si;
189256905Sray
190256905Sray	return (0);
191256905Sray}
192256905Sray
193256905Srayint
194256905Srayfbd_list()
195256905Sray{
196256905Sray	struct fb_list_entry *entry;
197256905Sray
198256905Sray	if (LIST_EMPTY(&fb_list_head))
199256905Sray		return (ENOENT);
200256905Sray
201256905Sray	LIST_FOREACH(entry, &fb_list_head, fb_list) {
202256905Sray		printf("FB %s @%p\n", entry->fb_info->fb_name,
203256905Sray		    (void *)entry->fb_info->fb_pbase);
204256905Sray	}
205256905Sray
206256905Sray	return (0);
207256905Sray}
208256905Sray
209256905Sraystatic struct fb_list_entry *
210256905Srayfbd_find(struct fb_info* info)
211256905Sray{
212256905Sray	struct fb_list_entry *entry, *tmp;
213256905Sray
214256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
215256905Sray		if (entry->fb_info == info) {
216256905Sray			return (entry);
217256905Sray		}
218256905Sray	}
219256905Sray
220256905Sray	return (NULL);
221256905Sray}
222256905Sray
223256905Srayint
224256905Srayfbd_register(struct fb_info* info)
225256905Sray{
226256905Sray	struct fb_list_entry *entry;
227256905Sray	int err, first;
228256905Sray
229256905Sray	first = 0;
230256905Sray	if (LIST_EMPTY(&fb_list_head))
231256905Sray		first++;
232256905Sray
233256905Sray	entry = fbd_find(info);
234256905Sray	if (entry != NULL) {
235256905Sray		/* XXX Update framebuffer params */
236256905Sray		return (0);
237256905Sray	}
238256905Sray
239256905Sray	entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
240256905Sray	entry->fb_info = info;
241256905Sray
242256905Sray	LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
243256905Sray
244256905Sray	err = fb_init(entry, framebuffer_dev_unit++);
245256905Sray	if (err)
246256905Sray		return (err);
247256905Sray
248269620Snwhitehorn	if (first) {
249269779Sdumbbell		err = vt_fb_attach(info);
250269779Sdumbbell		if (err)
251269779Sdumbbell			return (err);
252269620Snwhitehorn	}
253256905Sray
254256905Sray	return (0);
255256905Sray}
256256905Sray
257256905Srayint
258256905Srayfbd_unregister(struct fb_info* info)
259256905Sray{
260256905Sray	struct fb_list_entry *entry, *tmp;
261256905Sray
262256905Sray	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
263256905Sray		if (entry->fb_info == info) {
264256905Sray			LIST_REMOVE(entry, fb_list);
265256905Sray			free(entry, M_DEVBUF);
266256905Sray			return (0);
267256905Sray		}
268256905Sray	}
269256905Sray
270256905Sray	return (ENOENT);
271256905Sray}
272256905Sray
273256905Sraystatic void
274256905Srayregister_fb_wrap(void *arg, void *ptr)
275256905Sray{
276256905Sray
277256905Sray	fbd_register((struct fb_info *)ptr);
278256905Sray}
279256905Sray
280256905Sraystatic void
281256905Srayunregister_fb_wrap(void *arg, void *ptr)
282256905Sray{
283256905Sray
284256905Sray	fbd_unregister((struct fb_info *)ptr);
285256905Sray}
286256905Sray
287256905Sraystatic void
288256905Srayfbd_evh_init(void *ctx)
289256905Sray{
290256905Sray
291256905Sray	EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
292256905Sray	    EVENTHANDLER_PRI_ANY);
293256905Sray	EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
294256905Sray	    EVENTHANDLER_PRI_ANY);
295256905Sray}
296257438Sray
297257438Sray/* Newbus methods. */
298257438Sraystatic int
299257438Srayfbd_probe(device_t dev)
300257438Sray{
301257438Sray
302257438Sray	return (BUS_PROBE_NOWILDCARD);
303257438Sray}
304257438Sray
305257438Sraystatic int
306257438Srayfbd_attach(device_t dev)
307257438Sray{
308257438Sray	struct fbd_softc *sc;
309257438Sray	int err;
310257438Sray
311257438Sray	sc = device_get_softc(dev);
312257438Sray
313257438Sray	sc->sc_dev = dev;
314257438Sray	sc->sc_info = FB_GETINFO(device_get_parent(dev));
315257546Sray	if (sc->sc_info == NULL)
316257546Sray		return (ENXIO);
317257438Sray	err = fbd_register(sc->sc_info);
318257438Sray
319257438Sray	return (err);
320257438Sray}
321257438Sray
322257438Sraystatic int
323257438Srayfbd_detach(device_t dev)
324257438Sray{
325257438Sray	struct fbd_softc *sc;
326257438Sray	int err;
327257438Sray
328257438Sray	sc = device_get_softc(dev);
329257438Sray
330257438Sray	err = fbd_unregister(sc->sc_info);
331257438Sray
332257438Sray	return (err);
333257438Sray}
334257438Sray
335257815Sraystatic int
336257815Srayfbd_suspend(device_t dev)
337257815Sray{
338257438Sray
339257815Sray	vt_fb_suspend();
340257815Sray	return (bus_generic_suspend(dev));
341257815Sray}
342257815Sray
343257815Sraystatic int
344257815Srayfbd_resume(device_t dev)
345257815Sray{
346257815Sray
347257815Sray	vt_fb_resume();
348257815Sray	return (bus_generic_resume(dev));
349257815Sray}
350257815Sray
351257438Sraystatic device_method_t fbd_methods[] = {
352257438Sray	/* Device interface */
353257438Sray	DEVMETHOD(device_probe,		fbd_probe),
354257438Sray	DEVMETHOD(device_attach,	fbd_attach),
355257438Sray	DEVMETHOD(device_detach,	fbd_detach),
356257438Sray
357257438Sray	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
358257815Sray	DEVMETHOD(device_suspend,	fbd_suspend),
359257815Sray	DEVMETHOD(device_resume,	fbd_resume),
360257438Sray
361257438Sray	{ 0, 0 }
362257438Sray};
363257438Sray
364257438Sraydriver_t fbd_driver = {
365257438Sray	"fbd",
366257438Sray	fbd_methods,
367257438Sray	sizeof(struct fbd_softc)
368257438Sray};
369257438Sray
370257438Sraydevclass_t	fbd_devclass;
371257438Sray
372257438SrayDRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
373257517SrayDRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
374257438SrayMODULE_VERSION(fbd, 1);
375257438Sray
376