FreeBSD/Linux Kernel Cross Reference
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: releng/12.0/sys/dev/fb/fbd.c 326255 2017-11-27 14:52:40Z pfg $
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: releng/12.0/sys/dev/fb/fbd.c 326255 2017-11-27 14:52:40Z pfg $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/conf.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/queue.h>
49 #include <sys/fbio.h>
50
51 #include <machine/bus.h>
52
53 #include <dev/vt/vt.h>
54 #include <dev/vt/hw/fb/vt_fb.h>
55
56 #include <vm/vm.h>
57 #include <vm/pmap.h>
58
59 #include "fb_if.h"
60
61 LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
62 LIST_HEAD_INITIALIZER(fb_list_head);
63 struct fb_list_entry {
64 struct fb_info *fb_info;
65 struct cdev *fb_si;
66 LIST_ENTRY(fb_list_entry) fb_list;
67 };
68
69 struct fbd_softc {
70 device_t sc_dev;
71 struct fb_info *sc_info;
72 };
73
74 static void fbd_evh_init(void *);
75 /* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
76 SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
77
78 static d_open_t fb_open;
79 static d_close_t fb_close;
80 static d_read_t fb_read;
81 static d_write_t fb_write;
82 static d_ioctl_t fb_ioctl;
83 static d_mmap_t fb_mmap;
84
85 static struct cdevsw fb_cdevsw = {
86 .d_version = D_VERSION,
87 .d_flags = D_NEEDGIANT,
88 .d_open = fb_open,
89 .d_close = fb_close,
90 .d_read = fb_read,
91 .d_write = fb_write,
92 .d_ioctl = fb_ioctl,
93 .d_mmap = fb_mmap,
94 .d_name = "fb",
95 };
96
97 static int framebuffer_dev_unit = 0;
98
99 static int
100 fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
101 {
102
103 return (0);
104 }
105
106 static int
107 fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
108 {
109
110 return (0);
111 }
112
113 static int
114 fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
115 struct thread *td)
116 {
117 struct fb_info *info;
118 int error;
119
120 error = 0;
121 info = dev->si_drv1;
122
123 switch (cmd) {
124 case FBIOGTYPE:
125 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
126 break;
127
128 case FBIO_GETWINORG: /* get frame buffer window origin */
129 *(u_int *)data = 0;
130 break;
131
132 case FBIO_GETDISPSTART: /* get display start address */
133 ((video_display_start_t *)data)->x = 0;
134 ((video_display_start_t *)data)->y = 0;
135 break;
136
137 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
138 *(u_int *)data = info->fb_stride;
139 break;
140
141 case FBIO_BLANK: /* blank display */
142 if (info->setblankmode != NULL)
143 error = info->setblankmode(info->fb_priv, *(int *)data);
144 break;
145
146 default:
147 error = ENOIOCTL;
148 break;
149 }
150 return (error);
151 }
152
153 static int
154 fb_read(struct cdev *dev, struct uio *uio, int ioflag)
155 {
156
157 return (0); /* XXX nothing to read, yet */
158 }
159
160 static int
161 fb_write(struct cdev *dev, struct uio *uio, int ioflag)
162 {
163
164 return (0); /* XXX nothing written */
165 }
166
167 static int
168 fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
169 vm_memattr_t *memattr)
170 {
171 struct fb_info *info;
172
173 info = dev->si_drv1;
174
175 if (info->fb_flags & FB_FLAG_NOMMAP)
176 return (ENODEV);
177
178 if (offset >= 0 && offset < info->fb_size) {
179 if (info->fb_pbase == 0)
180 *paddr = vtophys((uint8_t *)info->fb_vbase + offset);
181 else
182 *paddr = info->fb_pbase + offset;
183 if (info->fb_flags & FB_FLAG_MEMATTR)
184 *memattr = info->fb_memattr;
185 return (0);
186 }
187 return (EINVAL);
188 }
189
190 static int
191 fb_init(struct fb_list_entry *entry, int unit)
192 {
193 struct fb_info *info;
194
195 info = entry->fb_info;
196 entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
197 0600, "fb%d", unit);
198 entry->fb_si->si_drv1 = info;
199 info->fb_cdev = entry->fb_si;
200
201 return (0);
202 }
203
204 int
205 fbd_list()
206 {
207 struct fb_list_entry *entry;
208
209 if (LIST_EMPTY(&fb_list_head))
210 return (ENOENT);
211
212 LIST_FOREACH(entry, &fb_list_head, fb_list) {
213 printf("FB %s @%p\n", entry->fb_info->fb_name,
214 (void *)entry->fb_info->fb_pbase);
215 }
216
217 return (0);
218 }
219
220 static struct fb_list_entry *
221 fbd_find(struct fb_info* info)
222 {
223 struct fb_list_entry *entry, *tmp;
224
225 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
226 if (entry->fb_info == info) {
227 return (entry);
228 }
229 }
230
231 return (NULL);
232 }
233
234 int
235 fbd_register(struct fb_info* info)
236 {
237 struct fb_list_entry *entry;
238 int err, first;
239
240 first = 0;
241 if (LIST_EMPTY(&fb_list_head))
242 first++;
243
244 entry = fbd_find(info);
245 if (entry != NULL) {
246 /* XXX Update framebuffer params */
247 return (0);
248 }
249
250 entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
251 entry->fb_info = info;
252
253 LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
254
255 err = fb_init(entry, framebuffer_dev_unit++);
256 if (err)
257 return (err);
258
259 if (first) {
260 err = vt_fb_attach(info);
261 if (err)
262 return (err);
263 }
264
265 return (0);
266 }
267
268 int
269 fbd_unregister(struct fb_info* info)
270 {
271 struct fb_list_entry *entry, *tmp;
272
273 LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
274 if (entry->fb_info == info) {
275 LIST_REMOVE(entry, fb_list);
276 if (LIST_EMPTY(&fb_list_head))
277 vt_fb_detach(info);
278 free(entry, M_DEVBUF);
279 return (0);
280 }
281 }
282
283 return (ENOENT);
284 }
285
286 static void
287 register_fb_wrap(void *arg, void *ptr)
288 {
289
290 fbd_register((struct fb_info *)ptr);
291 }
292
293 static void
294 unregister_fb_wrap(void *arg, void *ptr)
295 {
296
297 fbd_unregister((struct fb_info *)ptr);
298 }
299
300 static void
301 fbd_evh_init(void *ctx)
302 {
303
304 EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
305 EVENTHANDLER_PRI_ANY);
306 EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
307 EVENTHANDLER_PRI_ANY);
308 }
309
310 /* Newbus methods. */
311 static int
312 fbd_probe(device_t dev)
313 {
314
315 return (BUS_PROBE_NOWILDCARD);
316 }
317
318 static int
319 fbd_attach(device_t dev)
320 {
321 struct fbd_softc *sc;
322 int err;
323
324 sc = device_get_softc(dev);
325
326 sc->sc_dev = dev;
327 sc->sc_info = FB_GETINFO(device_get_parent(dev));
328 if (sc->sc_info == NULL)
329 return (ENXIO);
330 err = fbd_register(sc->sc_info);
331
332 return (err);
333 }
334
335 static int
336 fbd_detach(device_t dev)
337 {
338 struct fbd_softc *sc;
339 int err;
340
341 sc = device_get_softc(dev);
342
343 err = fbd_unregister(sc->sc_info);
344
345 return (err);
346 }
347
348 static device_method_t fbd_methods[] = {
349 /* Device interface */
350 DEVMETHOD(device_probe, fbd_probe),
351 DEVMETHOD(device_attach, fbd_attach),
352 DEVMETHOD(device_detach, fbd_detach),
353
354 DEVMETHOD(device_shutdown, bus_generic_shutdown),
355
356 { 0, 0 }
357 };
358
359 driver_t fbd_driver = {
360 "fbd",
361 fbd_methods,
362 sizeof(struct fbd_softc)
363 };
364
365 devclass_t fbd_devclass;
366
367 DRIVER_MODULE(fbd, fb, fbd_driver, fbd_devclass, 0, 0);
368 DRIVER_MODULE(fbd, drmn, fbd_driver, fbd_devclass, 0, 0);
369 DRIVER_MODULE(fbd, udl, fbd_driver, fbd_devclass, 0, 0);
370 MODULE_VERSION(fbd, 1);
371
Cache object: da69155ff7acad469dfbd981ce06c82c
|