127cf7d04SAleksandr Rybalko /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
427cf7d04SAleksandr Rybalko * Copyright (c) 2013 The FreeBSD Foundation
527cf7d04SAleksandr Rybalko *
627cf7d04SAleksandr Rybalko * This software was developed by Aleksandr Rybalko under sponsorship from the
727cf7d04SAleksandr Rybalko * FreeBSD Foundation.
827cf7d04SAleksandr Rybalko *
927cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without
1027cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions
1127cf7d04SAleksandr Rybalko * are met:
1227cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright
1327cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer.
1427cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright
1527cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the
1627cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution.
1727cf7d04SAleksandr Rybalko *
1827cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1927cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2027cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2127cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2227cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2327cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2427cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2527cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2627cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2727cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2827cf7d04SAleksandr Rybalko * SUCH DAMAGE.
2927cf7d04SAleksandr Rybalko */
3027cf7d04SAleksandr Rybalko
3127cf7d04SAleksandr Rybalko /* Generic framebuffer */
3227cf7d04SAleksandr Rybalko /* TODO unlink from VT(9) */
3327cf7d04SAleksandr Rybalko /* TODO done normal /dev/fb methods */
3427cf7d04SAleksandr Rybalko
3527cf7d04SAleksandr Rybalko #include <sys/param.h>
3627cf7d04SAleksandr Rybalko #include <sys/systm.h>
3727cf7d04SAleksandr Rybalko #include <sys/bus.h>
3827cf7d04SAleksandr Rybalko #include <sys/conf.h>
39e12be321SConrad Meyer #include <sys/eventhandler.h>
4027cf7d04SAleksandr Rybalko #include <sys/kernel.h>
4127cf7d04SAleksandr Rybalko #include <sys/malloc.h>
4227cf7d04SAleksandr Rybalko #include <sys/module.h>
4327cf7d04SAleksandr Rybalko #include <sys/queue.h>
4427cf7d04SAleksandr Rybalko #include <sys/fbio.h>
4527cf7d04SAleksandr Rybalko
4627cf7d04SAleksandr Rybalko #include <machine/bus.h>
4727cf7d04SAleksandr Rybalko
4827cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
4927cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h>
5027cf7d04SAleksandr Rybalko
51a985ae9bSHans Petter Selasky #include <vm/vm.h>
52a985ae9bSHans Petter Selasky #include <vm/pmap.h>
53a985ae9bSHans Petter Selasky
5427cf7d04SAleksandr Rybalko #include "fb_if.h"
5527cf7d04SAleksandr Rybalko
5627cf7d04SAleksandr Rybalko LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
5727cf7d04SAleksandr Rybalko LIST_HEAD_INITIALIZER(fb_list_head);
5827cf7d04SAleksandr Rybalko struct fb_list_entry {
5927cf7d04SAleksandr Rybalko struct fb_info *fb_info;
6027cf7d04SAleksandr Rybalko struct cdev *fb_si;
6127cf7d04SAleksandr Rybalko LIST_ENTRY(fb_list_entry) fb_list;
6227cf7d04SAleksandr Rybalko };
6327cf7d04SAleksandr Rybalko
6427cf7d04SAleksandr Rybalko struct fbd_softc {
6527cf7d04SAleksandr Rybalko device_t sc_dev;
6627cf7d04SAleksandr Rybalko struct fb_info *sc_info;
6727cf7d04SAleksandr Rybalko };
6827cf7d04SAleksandr Rybalko
6927cf7d04SAleksandr Rybalko static void fbd_evh_init(void *);
7027cf7d04SAleksandr Rybalko /* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
7127cf7d04SAleksandr Rybalko SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
7227cf7d04SAleksandr Rybalko
7327cf7d04SAleksandr Rybalko static d_open_t fb_open;
7427cf7d04SAleksandr Rybalko static d_close_t fb_close;
7527cf7d04SAleksandr Rybalko static d_read_t fb_read;
7627cf7d04SAleksandr Rybalko static d_write_t fb_write;
7727cf7d04SAleksandr Rybalko static d_ioctl_t fb_ioctl;
7827cf7d04SAleksandr Rybalko static d_mmap_t fb_mmap;
7927cf7d04SAleksandr Rybalko
8027cf7d04SAleksandr Rybalko static struct cdevsw fb_cdevsw = {
8127cf7d04SAleksandr Rybalko .d_version = D_VERSION,
8227cf7d04SAleksandr Rybalko .d_flags = D_NEEDGIANT,
8327cf7d04SAleksandr Rybalko .d_open = fb_open,
8427cf7d04SAleksandr Rybalko .d_close = fb_close,
8527cf7d04SAleksandr Rybalko .d_read = fb_read,
8627cf7d04SAleksandr Rybalko .d_write = fb_write,
8727cf7d04SAleksandr Rybalko .d_ioctl = fb_ioctl,
8827cf7d04SAleksandr Rybalko .d_mmap = fb_mmap,
8927cf7d04SAleksandr Rybalko .d_name = "fb",
9027cf7d04SAleksandr Rybalko };
9127cf7d04SAleksandr Rybalko
9227cf7d04SAleksandr Rybalko static int framebuffer_dev_unit = 0;
9327cf7d04SAleksandr Rybalko
9427cf7d04SAleksandr Rybalko static int
fb_open(struct cdev * dev,int oflags,int devtype,struct thread * td)9527cf7d04SAleksandr Rybalko fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
9627cf7d04SAleksandr Rybalko {
9727cf7d04SAleksandr Rybalko
9827cf7d04SAleksandr Rybalko return (0);
9927cf7d04SAleksandr Rybalko }
10027cf7d04SAleksandr Rybalko
10127cf7d04SAleksandr Rybalko static int
fb_close(struct cdev * dev,int fflag,int devtype,struct thread * td)10227cf7d04SAleksandr Rybalko fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
10327cf7d04SAleksandr Rybalko {
10427cf7d04SAleksandr Rybalko
10527cf7d04SAleksandr Rybalko return (0);
10627cf7d04SAleksandr Rybalko }
10727cf7d04SAleksandr Rybalko
10827cf7d04SAleksandr Rybalko static int
fb_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)10927cf7d04SAleksandr Rybalko fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
11027cf7d04SAleksandr Rybalko struct thread *td)
11127cf7d04SAleksandr Rybalko {
11227cf7d04SAleksandr Rybalko struct fb_info *info;
11327cf7d04SAleksandr Rybalko int error;
11427cf7d04SAleksandr Rybalko
11527cf7d04SAleksandr Rybalko error = 0;
11627cf7d04SAleksandr Rybalko info = dev->si_drv1;
11727cf7d04SAleksandr Rybalko
11827cf7d04SAleksandr Rybalko switch (cmd) {
11927cf7d04SAleksandr Rybalko case FBIOGTYPE:
12027cf7d04SAleksandr Rybalko bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
12127cf7d04SAleksandr Rybalko break;
12227cf7d04SAleksandr Rybalko
12327cf7d04SAleksandr Rybalko case FBIO_GETWINORG: /* get frame buffer window origin */
12427cf7d04SAleksandr Rybalko *(u_int *)data = 0;
12527cf7d04SAleksandr Rybalko break;
12627cf7d04SAleksandr Rybalko
12727cf7d04SAleksandr Rybalko case FBIO_GETDISPSTART: /* get display start address */
12827cf7d04SAleksandr Rybalko ((video_display_start_t *)data)->x = 0;
12927cf7d04SAleksandr Rybalko ((video_display_start_t *)data)->y = 0;
13027cf7d04SAleksandr Rybalko break;
13127cf7d04SAleksandr Rybalko
13227cf7d04SAleksandr Rybalko case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
13327cf7d04SAleksandr Rybalko *(u_int *)data = info->fb_stride;
13427cf7d04SAleksandr Rybalko break;
13527cf7d04SAleksandr Rybalko
13627cf7d04SAleksandr Rybalko case FBIO_BLANK: /* blank display */
137b914a529SHans Petter Selasky if (info->setblankmode != NULL)
138b914a529SHans Petter Selasky error = info->setblankmode(info->fb_priv, *(int *)data);
13927cf7d04SAleksandr Rybalko break;
14027cf7d04SAleksandr Rybalko
14127cf7d04SAleksandr Rybalko default:
14227cf7d04SAleksandr Rybalko error = ENOIOCTL;
14327cf7d04SAleksandr Rybalko break;
14427cf7d04SAleksandr Rybalko }
14527cf7d04SAleksandr Rybalko return (error);
14627cf7d04SAleksandr Rybalko }
14727cf7d04SAleksandr Rybalko
14827cf7d04SAleksandr Rybalko static int
fb_read(struct cdev * dev,struct uio * uio,int ioflag)14927cf7d04SAleksandr Rybalko fb_read(struct cdev *dev, struct uio *uio, int ioflag)
15027cf7d04SAleksandr Rybalko {
15127cf7d04SAleksandr Rybalko
15227cf7d04SAleksandr Rybalko return (0); /* XXX nothing to read, yet */
15327cf7d04SAleksandr Rybalko }
15427cf7d04SAleksandr Rybalko
15527cf7d04SAleksandr Rybalko static int
fb_write(struct cdev * dev,struct uio * uio,int ioflag)15627cf7d04SAleksandr Rybalko fb_write(struct cdev *dev, struct uio *uio, int ioflag)
15727cf7d04SAleksandr Rybalko {
15827cf7d04SAleksandr Rybalko
15927cf7d04SAleksandr Rybalko return (0); /* XXX nothing written */
16027cf7d04SAleksandr Rybalko }
16127cf7d04SAleksandr Rybalko
16227cf7d04SAleksandr Rybalko static int
fb_mmap(struct cdev * dev,vm_ooffset_t offset,vm_paddr_t * paddr,int nprot,vm_memattr_t * memattr)16327cf7d04SAleksandr Rybalko fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
16427cf7d04SAleksandr Rybalko vm_memattr_t *memattr)
16527cf7d04SAleksandr Rybalko {
16627cf7d04SAleksandr Rybalko struct fb_info *info;
16727cf7d04SAleksandr Rybalko
16827cf7d04SAleksandr Rybalko info = dev->si_drv1;
1699ed297c8SNathan Whitehorn
170a985ae9bSHans Petter Selasky if (info->fb_flags & FB_FLAG_NOMMAP)
1719ed297c8SNathan Whitehorn return (ENODEV);
1729ed297c8SNathan Whitehorn
173f9cc8410SEric van Gyzen if (offset < info->fb_size) {
174a985ae9bSHans Petter Selasky if (info->fb_pbase == 0)
175a985ae9bSHans Petter Selasky *paddr = vtophys((uint8_t *)info->fb_vbase + offset);
176a985ae9bSHans Petter Selasky else
17727cf7d04SAleksandr Rybalko *paddr = info->fb_pbase + offset;
1782685a39aSOleksandr Tymoshenko if (info->fb_flags & FB_FLAG_MEMATTR)
1792685a39aSOleksandr Tymoshenko *memattr = info->fb_memattr;
18027cf7d04SAleksandr Rybalko return (0);
18127cf7d04SAleksandr Rybalko }
18227cf7d04SAleksandr Rybalko return (EINVAL);
18327cf7d04SAleksandr Rybalko }
18427cf7d04SAleksandr Rybalko
18527cf7d04SAleksandr Rybalko static int
fb_init(struct fb_list_entry * entry,int unit)18627cf7d04SAleksandr Rybalko fb_init(struct fb_list_entry *entry, int unit)
18727cf7d04SAleksandr Rybalko {
18827cf7d04SAleksandr Rybalko struct fb_info *info;
18927cf7d04SAleksandr Rybalko
19027cf7d04SAleksandr Rybalko info = entry->fb_info;
19127cf7d04SAleksandr Rybalko entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
19227cf7d04SAleksandr Rybalko 0600, "fb%d", unit);
19327cf7d04SAleksandr Rybalko entry->fb_si->si_drv1 = info;
1947a1a32c4SAleksandr Rybalko info->fb_cdev = entry->fb_si;
19527cf7d04SAleksandr Rybalko
19627cf7d04SAleksandr Rybalko return (0);
19727cf7d04SAleksandr Rybalko }
19827cf7d04SAleksandr Rybalko
19927cf7d04SAleksandr Rybalko int
fbd_list(void)2009863e501SDimitry Andric fbd_list(void)
20127cf7d04SAleksandr Rybalko {
20227cf7d04SAleksandr Rybalko struct fb_list_entry *entry;
20327cf7d04SAleksandr Rybalko
20427cf7d04SAleksandr Rybalko if (LIST_EMPTY(&fb_list_head))
20527cf7d04SAleksandr Rybalko return (ENOENT);
20627cf7d04SAleksandr Rybalko
20727cf7d04SAleksandr Rybalko LIST_FOREACH(entry, &fb_list_head, fb_list) {
208a9fca3b9SJohn Baldwin printf("FB %s @%#jx\n", entry->fb_info->fb_name,
209a9fca3b9SJohn Baldwin (uintmax_t)entry->fb_info->fb_pbase);
21027cf7d04SAleksandr Rybalko }
21127cf7d04SAleksandr Rybalko
21227cf7d04SAleksandr Rybalko return (0);
21327cf7d04SAleksandr Rybalko }
21427cf7d04SAleksandr Rybalko
21527cf7d04SAleksandr Rybalko static struct fb_list_entry *
fbd_find(struct fb_info * info)21627cf7d04SAleksandr Rybalko fbd_find(struct fb_info* info)
21727cf7d04SAleksandr Rybalko {
21827cf7d04SAleksandr Rybalko struct fb_list_entry *entry, *tmp;
21927cf7d04SAleksandr Rybalko
22027cf7d04SAleksandr Rybalko LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
22127cf7d04SAleksandr Rybalko if (entry->fb_info == info) {
22227cf7d04SAleksandr Rybalko return (entry);
22327cf7d04SAleksandr Rybalko }
22427cf7d04SAleksandr Rybalko }
22527cf7d04SAleksandr Rybalko
22627cf7d04SAleksandr Rybalko return (NULL);
22727cf7d04SAleksandr Rybalko }
22827cf7d04SAleksandr Rybalko
22927cf7d04SAleksandr Rybalko int
fbd_register(struct fb_info * info)23027cf7d04SAleksandr Rybalko fbd_register(struct fb_info* info)
23127cf7d04SAleksandr Rybalko {
23227cf7d04SAleksandr Rybalko struct fb_list_entry *entry;
23327cf7d04SAleksandr Rybalko int err, first;
23427cf7d04SAleksandr Rybalko
23527cf7d04SAleksandr Rybalko first = 0;
23627cf7d04SAleksandr Rybalko if (LIST_EMPTY(&fb_list_head))
23727cf7d04SAleksandr Rybalko first++;
23827cf7d04SAleksandr Rybalko
23927cf7d04SAleksandr Rybalko entry = fbd_find(info);
24027cf7d04SAleksandr Rybalko if (entry != NULL) {
24127cf7d04SAleksandr Rybalko /* XXX Update framebuffer params */
24227cf7d04SAleksandr Rybalko return (0);
24327cf7d04SAleksandr Rybalko }
24427cf7d04SAleksandr Rybalko
24527cf7d04SAleksandr Rybalko entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
24627cf7d04SAleksandr Rybalko entry->fb_info = info;
24727cf7d04SAleksandr Rybalko
24827cf7d04SAleksandr Rybalko LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
24927cf7d04SAleksandr Rybalko
25027cf7d04SAleksandr Rybalko err = fb_init(entry, framebuffer_dev_unit++);
25127cf7d04SAleksandr Rybalko if (err)
25227cf7d04SAleksandr Rybalko return (err);
25327cf7d04SAleksandr Rybalko
2549ed297c8SNathan Whitehorn if (first) {
2552cf9e30bSJean-Sébastien Pédron err = vt_fb_attach(info);
2562cf9e30bSJean-Sébastien Pédron if (err)
2572cf9e30bSJean-Sébastien Pédron return (err);
2589ed297c8SNathan Whitehorn }
25927cf7d04SAleksandr Rybalko
26027cf7d04SAleksandr Rybalko return (0);
26127cf7d04SAleksandr Rybalko }
26227cf7d04SAleksandr Rybalko
26327cf7d04SAleksandr Rybalko int
fbd_unregister(struct fb_info * info)26427cf7d04SAleksandr Rybalko fbd_unregister(struct fb_info* info)
26527cf7d04SAleksandr Rybalko {
26627cf7d04SAleksandr Rybalko struct fb_list_entry *entry, *tmp;
26727cf7d04SAleksandr Rybalko
26827cf7d04SAleksandr Rybalko LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
26927cf7d04SAleksandr Rybalko if (entry->fb_info == info) {
27027cf7d04SAleksandr Rybalko LIST_REMOVE(entry, fb_list);
27176e2f976SJean-Sébastien Pédron if (LIST_EMPTY(&fb_list_head))
27276e2f976SJean-Sébastien Pédron vt_fb_detach(info);
27327cf7d04SAleksandr Rybalko free(entry, M_DEVBUF);
27427cf7d04SAleksandr Rybalko return (0);
27527cf7d04SAleksandr Rybalko }
27627cf7d04SAleksandr Rybalko }
27727cf7d04SAleksandr Rybalko
27827cf7d04SAleksandr Rybalko return (ENOENT);
27927cf7d04SAleksandr Rybalko }
28027cf7d04SAleksandr Rybalko
28127cf7d04SAleksandr Rybalko static void
register_fb_wrap(void * arg,void * ptr)28227cf7d04SAleksandr Rybalko register_fb_wrap(void *arg, void *ptr)
28327cf7d04SAleksandr Rybalko {
28427cf7d04SAleksandr Rybalko
28527cf7d04SAleksandr Rybalko fbd_register((struct fb_info *)ptr);
28627cf7d04SAleksandr Rybalko }
28727cf7d04SAleksandr Rybalko
28827cf7d04SAleksandr Rybalko static void
unregister_fb_wrap(void * arg,void * ptr)28927cf7d04SAleksandr Rybalko unregister_fb_wrap(void *arg, void *ptr)
29027cf7d04SAleksandr Rybalko {
29127cf7d04SAleksandr Rybalko
29227cf7d04SAleksandr Rybalko fbd_unregister((struct fb_info *)ptr);
29327cf7d04SAleksandr Rybalko }
29427cf7d04SAleksandr Rybalko
29527cf7d04SAleksandr Rybalko static void
fbd_evh_init(void * ctx)29627cf7d04SAleksandr Rybalko fbd_evh_init(void *ctx)
29727cf7d04SAleksandr Rybalko {
29827cf7d04SAleksandr Rybalko
29927cf7d04SAleksandr Rybalko EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
30027cf7d04SAleksandr Rybalko EVENTHANDLER_PRI_ANY);
30127cf7d04SAleksandr Rybalko EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
30227cf7d04SAleksandr Rybalko EVENTHANDLER_PRI_ANY);
30327cf7d04SAleksandr Rybalko }
30427cf7d04SAleksandr Rybalko
30527cf7d04SAleksandr Rybalko /* Newbus methods. */
30627cf7d04SAleksandr Rybalko static int
fbd_probe(device_t dev)30727cf7d04SAleksandr Rybalko fbd_probe(device_t dev)
30827cf7d04SAleksandr Rybalko {
30927cf7d04SAleksandr Rybalko
31027cf7d04SAleksandr Rybalko return (BUS_PROBE_NOWILDCARD);
31127cf7d04SAleksandr Rybalko }
31227cf7d04SAleksandr Rybalko
31327cf7d04SAleksandr Rybalko static int
fbd_attach(device_t dev)31427cf7d04SAleksandr Rybalko fbd_attach(device_t dev)
31527cf7d04SAleksandr Rybalko {
31627cf7d04SAleksandr Rybalko struct fbd_softc *sc;
31727cf7d04SAleksandr Rybalko int err;
31827cf7d04SAleksandr Rybalko
31927cf7d04SAleksandr Rybalko sc = device_get_softc(dev);
32027cf7d04SAleksandr Rybalko
32127cf7d04SAleksandr Rybalko sc->sc_dev = dev;
32227cf7d04SAleksandr Rybalko sc->sc_info = FB_GETINFO(device_get_parent(dev));
32327cf7d04SAleksandr Rybalko if (sc->sc_info == NULL)
32427cf7d04SAleksandr Rybalko return (ENXIO);
32527cf7d04SAleksandr Rybalko err = fbd_register(sc->sc_info);
32627cf7d04SAleksandr Rybalko
32727cf7d04SAleksandr Rybalko return (err);
32827cf7d04SAleksandr Rybalko }
32927cf7d04SAleksandr Rybalko
33027cf7d04SAleksandr Rybalko static int
fbd_detach(device_t dev)33127cf7d04SAleksandr Rybalko fbd_detach(device_t dev)
33227cf7d04SAleksandr Rybalko {
33327cf7d04SAleksandr Rybalko struct fbd_softc *sc;
33427cf7d04SAleksandr Rybalko int err;
33527cf7d04SAleksandr Rybalko
33627cf7d04SAleksandr Rybalko sc = device_get_softc(dev);
33727cf7d04SAleksandr Rybalko
33827cf7d04SAleksandr Rybalko err = fbd_unregister(sc->sc_info);
33927cf7d04SAleksandr Rybalko
34027cf7d04SAleksandr Rybalko return (err);
34127cf7d04SAleksandr Rybalko }
34227cf7d04SAleksandr Rybalko
34327cf7d04SAleksandr Rybalko static device_method_t fbd_methods[] = {
34427cf7d04SAleksandr Rybalko /* Device interface */
34527cf7d04SAleksandr Rybalko DEVMETHOD(device_probe, fbd_probe),
34627cf7d04SAleksandr Rybalko DEVMETHOD(device_attach, fbd_attach),
34727cf7d04SAleksandr Rybalko DEVMETHOD(device_detach, fbd_detach),
34827cf7d04SAleksandr Rybalko
34927cf7d04SAleksandr Rybalko DEVMETHOD(device_shutdown, bus_generic_shutdown),
35027cf7d04SAleksandr Rybalko
35127cf7d04SAleksandr Rybalko { 0, 0 }
35227cf7d04SAleksandr Rybalko };
35327cf7d04SAleksandr Rybalko
35427cf7d04SAleksandr Rybalko driver_t fbd_driver = {
35527cf7d04SAleksandr Rybalko "fbd",
35627cf7d04SAleksandr Rybalko fbd_methods,
35727cf7d04SAleksandr Rybalko sizeof(struct fbd_softc)
35827cf7d04SAleksandr Rybalko };
35927cf7d04SAleksandr Rybalko
3609360510bSJohn Baldwin DRIVER_MODULE(fbd, fb, fbd_driver, 0, 0);
3619360510bSJohn Baldwin DRIVER_MODULE(fbd, drmn, fbd_driver, 0, 0);
3629360510bSJohn Baldwin DRIVER_MODULE(fbd, udl, fbd_driver, 0, 0);
36327cf7d04SAleksandr Rybalko MODULE_VERSION(fbd, 1);
36427cf7d04SAleksandr Rybalko
365