]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/fb/fbd.c
Include eventhandler.h in more compilation units
[FreeBSD/FreeBSD.git] / sys / dev / fb / fbd.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Aleksandr Rybalko under sponsorship from the
8  * FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 /* Generic framebuffer */
35 /* TODO unlink from VT(9) */
36 /* TODO done normal /dev/fb methods */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/conf.h>
45 #include <sys/eventhandler.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/module.h>
49 #include <sys/queue.h>
50 #include <sys/fbio.h>
51
52 #include <machine/bus.h>
53
54 #include <dev/vt/vt.h>
55 #include <dev/vt/hw/fb/vt_fb.h>
56
57 #include <vm/vm.h>
58 #include <vm/pmap.h>
59
60 #include "fb_if.h"
61
62 LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
63     LIST_HEAD_INITIALIZER(fb_list_head);
64 struct fb_list_entry {
65         struct fb_info  *fb_info;
66         struct cdev     *fb_si;
67         LIST_ENTRY(fb_list_entry) fb_list;
68 };
69
70 struct fbd_softc {
71         device_t        sc_dev;
72         struct fb_info  *sc_info;
73 };
74
75 static void fbd_evh_init(void *);
76 /* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
77 SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
78
79 static d_open_t         fb_open;
80 static d_close_t        fb_close;
81 static d_read_t         fb_read;
82 static d_write_t        fb_write;
83 static d_ioctl_t        fb_ioctl;
84 static d_mmap_t         fb_mmap;
85
86 static struct cdevsw fb_cdevsw = {
87         .d_version =    D_VERSION,
88         .d_flags =      D_NEEDGIANT,
89         .d_open =       fb_open,
90         .d_close =      fb_close,
91         .d_read =       fb_read,
92         .d_write =      fb_write,
93         .d_ioctl =      fb_ioctl,
94         .d_mmap =       fb_mmap,
95         .d_name =       "fb",
96 };
97
98 static int framebuffer_dev_unit = 0;
99
100 static int
101 fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
102 {
103
104         return (0);
105 }
106
107 static int
108 fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
109 {
110
111         return (0);
112 }
113
114 static int
115 fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
116     struct thread *td)
117 {
118         struct fb_info *info;
119         int error;
120
121         error = 0;
122         info = dev->si_drv1;
123
124         switch (cmd) {
125         case FBIOGTYPE:
126                 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
127                 break;
128
129         case FBIO_GETWINORG:    /* get frame buffer window origin */
130                 *(u_int *)data = 0;
131                 break;
132
133         case FBIO_GETDISPSTART: /* get display start address */
134                 ((video_display_start_t *)data)->x = 0;
135                 ((video_display_start_t *)data)->y = 0;
136                 break;
137
138         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
139                 *(u_int *)data = info->fb_stride;
140                 break;
141
142         case FBIO_BLANK:        /* blank display */
143                 if (info->setblankmode != NULL)
144                         error = info->setblankmode(info->fb_priv, *(int *)data);
145                 break;
146
147         default:
148                 error = ENOIOCTL;
149                 break;
150         }
151         return (error);
152 }
153
154 static int
155 fb_read(struct cdev *dev, struct uio *uio, int ioflag)
156 {
157
158         return (0); /* XXX nothing to read, yet */
159 }
160
161 static int
162 fb_write(struct cdev *dev, struct uio *uio, int ioflag)
163 {
164
165         return (0); /* XXX nothing written */
166 }
167
168 static int
169 fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
170     vm_memattr_t *memattr)
171 {
172         struct fb_info *info;
173
174         info = dev->si_drv1;
175
176         if (info->fb_flags & FB_FLAG_NOMMAP)
177                 return (ENODEV);
178
179         if (offset >= 0 && offset < info->fb_size) {
180                 if (info->fb_pbase == 0)
181                         *paddr = vtophys((uint8_t *)info->fb_vbase + offset);
182                 else
183                         *paddr = info->fb_pbase + offset;
184                 if (info->fb_flags & FB_FLAG_MEMATTR)
185                         *memattr = info->fb_memattr;
186                 return (0);
187         }
188         return (EINVAL);
189 }
190
191 static int
192 fb_init(struct fb_list_entry *entry, int unit)
193 {
194         struct fb_info *info;
195
196         info = entry->fb_info;
197         entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
198             0600, "fb%d", unit);
199         entry->fb_si->si_drv1 = info;
200         info->fb_cdev = entry->fb_si;
201
202         return (0);
203 }
204
205 int
206 fbd_list()
207 {
208         struct fb_list_entry *entry;
209
210         if (LIST_EMPTY(&fb_list_head))
211                 return (ENOENT);
212
213         LIST_FOREACH(entry, &fb_list_head, fb_list) {
214                 printf("FB %s @%p\n", entry->fb_info->fb_name,
215                     (void *)entry->fb_info->fb_pbase);
216         }
217
218         return (0);
219 }
220
221 static struct fb_list_entry *
222 fbd_find(struct fb_info* info)
223 {
224         struct fb_list_entry *entry, *tmp;
225
226         LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
227                 if (entry->fb_info == info) {
228                         return (entry);
229                 }
230         }
231
232         return (NULL);
233 }
234
235 int
236 fbd_register(struct fb_info* info)
237 {
238         struct fb_list_entry *entry;
239         int err, first;
240
241         first = 0;
242         if (LIST_EMPTY(&fb_list_head))
243                 first++;
244
245         entry = fbd_find(info);
246         if (entry != NULL) {
247                 /* XXX Update framebuffer params */
248                 return (0);
249         }
250
251         entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
252         entry->fb_info = info;
253
254         LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
255
256         err = fb_init(entry, framebuffer_dev_unit++);
257         if (err)
258                 return (err);
259
260         if (first) {
261                 err = vt_fb_attach(info);
262                 if (err)
263                         return (err);
264         }
265
266         return (0);
267 }
268
269 int
270 fbd_unregister(struct fb_info* info)
271 {
272         struct fb_list_entry *entry, *tmp;
273
274         LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
275                 if (entry->fb_info == info) {
276                         LIST_REMOVE(entry, fb_list);
277                         if (LIST_EMPTY(&fb_list_head))
278                                 vt_fb_detach(info);
279                         free(entry, M_DEVBUF);
280                         return (0);
281                 }
282         }
283
284         return (ENOENT);
285 }
286
287 static void
288 register_fb_wrap(void *arg, void *ptr)
289 {
290
291         fbd_register((struct fb_info *)ptr);
292 }
293
294 static void
295 unregister_fb_wrap(void *arg, void *ptr)
296 {
297
298         fbd_unregister((struct fb_info *)ptr);
299 }
300
301 static void
302 fbd_evh_init(void *ctx)
303 {
304
305         EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
306             EVENTHANDLER_PRI_ANY);
307         EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
308             EVENTHANDLER_PRI_ANY);
309 }
310
311 /* Newbus methods. */
312 static int
313 fbd_probe(device_t dev)
314 {
315
316         return (BUS_PROBE_NOWILDCARD);
317 }
318
319 static int
320 fbd_attach(device_t dev)
321 {
322         struct fbd_softc *sc;
323         int err;
324
325         sc = device_get_softc(dev);
326
327         sc->sc_dev = dev;
328         sc->sc_info = FB_GETINFO(device_get_parent(dev));
329         if (sc->sc_info == NULL)
330                 return (ENXIO);
331         err = fbd_register(sc->sc_info);
332
333         return (err);
334 }
335
336 static int
337 fbd_detach(device_t dev)
338 {
339         struct fbd_softc *sc;
340         int err;
341
342         sc = device_get_softc(dev);
343
344         err = fbd_unregister(sc->sc_info);
345
346         return (err);
347 }
348
349 static device_method_t fbd_methods[] = {
350         /* Device interface */
351         DEVMETHOD(device_probe,         fbd_probe),
352         DEVMETHOD(device_attach,        fbd_attach),
353         DEVMETHOD(device_detach,        fbd_detach),
354
355         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
356
357         { 0, 0 }
358 };
359
360 driver_t fbd_driver = {
361         "fbd",
362         fbd_methods,
363         sizeof(struct fbd_softc)
364 };
365
366 devclass_t      fbd_devclass;
367
368 DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
369 DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
370 DRIVER_MODULE(fbd, udl, fbd_driver, fbd_devclass, 0, 0);
371 MODULE_VERSION(fbd, 1);
372